Eloquent Sync () принадлежит ToMany с сводными и вложенными детьми - PullRequest
0 голосов
/ 06 октября 2019

Я бы хотел решить эту проблему. У меня есть такой json:

[
  {
    "id": 2,
    "title": "One",
    "parent": {},
    "children": [
      {
        "id": 3,
        "title": "One One",
        "parent": {
          "id": 2,
          "title": "One"
        },
        "children": [],
        "value": 1
      },
      {
        "id": 4,
        "title": "One Two",
        "parent": {
          "id": 2,
          "title": "One"
        },
        "children": [],
        "value": 2
      }
    ],
    "value": 3
  },
  {
    "id": 5,
    "title": "Three",
    "value": 3
  }
]

Как видите, у каждого элемента может быть ребенок, у которого также может быть ребенок, у которого также может быть ребенок и так далее. Он вложен.

Теперь я хотел бы сохранить эти items и каждого ребенка в belongsToMany отношении с pivot (в данном случае: value). Если я хочу использовать sync(), мне нужно будет подготовить все свои элементы в контроллере:

 <?php

/*Save $items*/
$items
    = collect($request->input('data.items'))->mapWithKeys(function (
    $item
) {

    if (array_key_exists('value', $item)) {
        $value = $item['value'];
    } else {
        $value = null;
    }

    return [
        $item['id'] => compact('value'),
    ];
});

$user->items()->sync($items);

Но это не проходит рекурсивно для всех детей. Я думал о чем-то вроде этого:

/*Save items*/
$items
    = collect($request->input('data.items'))->mapWithKeys(function (
    $item
) {
    $traverse = function ($item) use (&$traverse) {
        if (array_key_exists('value', $item)) {
            $value = $item['value'];
        } else {
            $value = null;
        }

        foreach ($item['children'] as $child) {
            $child = $traverse($child);
        }

        $children = ($item['children']);

        return [
            $item['id'] => compact('value', 'children'),
        ];
    };

    $item = $traverse($item);

Но это не сработает.

Что я хочу получить в результате:

  • Сохранение каждого itemкак отношение belongsToMany для user с опорой value
  • Сохранить все children рекурсивно с опорой value

1 Ответ

1 голос
/ 06 октября 2019

Сначала я хочу упомянуть, что ваши данные на самом деле являются JSON, а не массивом. Итак, здесь я пишу некоторый код, где вы можете видеть, что я декодировал и получил массив из этого (функция start from loop ()).

Как я понимаю, вы хотите собрать все значения элементов в 1 массив,который будет использоваться для сохранения всех отношений для 1 пользователя. Таким образом, вы можете получить этот выходной массив (см. Нижнюю часть функции loop ()).

protected $result = [];

protected function deepDiveIntoNextLevel(array $array) {
    foreach ($array as $item) {
        $this->result[] = $item['value'];
        if(!empty($item['children'])) {
            $this->deepDiveIntoNextLevel($item['children']);
        }
    }
}

public function loop()
{
    $json_array = '[
      {
        "id": 2,
        "title": "One",
        "parent": {},
        "children": [
          {
            "id": 3,
            "title": "One One",
            "parent": {
              "id": 2,
              "title": "One"
            },
            "children": [],
            "value": 1
          },
          {
            "id": 4,
            "title": "One Two",
            "parent": {
              "id": 2,
              "title": "One"
            },
            "children": [],
            "value": 2
          }
        ],
        "value": 3
      },
      {
        "id": 5,
        "title": "Three",
        "value": 3
      }
    ]';
    $initial_array = json_decode($json_array, true);

    $this->deepDiveIntoNextLevel($initial_array);
    $result = $this->result;
    // As output you may get an array, where you can have duplicates
    sort($result);
    // Or it can be not ordered
    $relations_ids_odered = array_unique($result);
}
...