It will seem to someone that the task is sucked, but I didn’t find a sane solution, so please help me what you can :-)

So, there is a standard table category (id, title, parent_id). Parent_id is a foreign key that refers to the id of the parent of the same table.

I pull out all categories from the base with one query:

$categories = Category::find()->asArray()->all(); 

The $ categories array is of the form:

 [ ['id'=>0, 'title'=>'Электроника', 'parent_id' => null], ['id'=>1, 'title'=>'Компьютеры', 'parent_id' => 0], ['id'=>2, 'title'=>'ПК', 'parent_id' => 1], ['id'=>3, 'title'=>'Ноутбуки', 'parent_id' => 1], ['id'=>4, 'title'=>'Мобильные телефоны', 'parent_id' => 0], ['id'=>5, 'title'=>'Бытовая химия', 'parent_id' => null], ['id'=>6, 'title'=>'Порошок', 'parent_id' => 5], ['id'=>7, 'title'=>'Мыло', 'parent_id' => 5], ] 

etc., categories of infinite (unknown) nesting.

It is necessary to make another multidimensional array-tree from this array, in which the child categories are nested in the parent ones (for the subsequent tree-like output in the views). How to do it? What are the options? Thank.

3 answers 3

 <?php /**восстанавливает дерево по таблице связей * @param $data array * @return array */ function restore_tree($data) { $lst = prepare_parents($data); foreach ($lst as &$parent) { restore_tree_impl($parent, $lst); } return $lst[null]; } /** восстановление связей родитель->дети * @param $parent array * @param $data array * @return void */ function restore_tree_impl(&$parent, &$data) { foreach ($parent['child'] as &$child) { // Если текущий ребенок сам является родителем if (array_key_exists($child['id'], $data)) { // восстановить связь $child['child'] = $data[$child['id']]['child']; // проверить детей restore_tree_impl($child, $data); } else { $child['child'] = []; } } } function make($id) { return ['id' => $id, 'title' => '[root]', 'child' => []]; } /**Создает список узлов, имеющих датей * @param $data $data * @return array */ function prepare_parents($data) { $res = []; foreach ($data as $item) { $parent = $item['parent_id']; if (!array_key_exists($parent, $res)) { $res[$parent] = make($parent); if (array_key_exists($parent, $data)) { $res[$parent]['title'] = $data[$parent]['title']; } } unset($item['parent_id']); array_push($res[$parent]['child'], $item); } $data = $res; return $data; } function show($item, $level) { if ($item['id'] === null) return; while ($level --> 0) { echo '..'; } echo $item['title'].PHP_EOL; } function print_tree($data, $level = -1) { show($data, $level); foreach ($data['child'] as $item) { print_tree($item, $level + 1); } } $data = [ ['id'=>0, 'title'=>'Электроника', 'parent_id' => null], ['id'=>1, 'title'=>'Компьютеры', 'parent_id' => 0], ['id'=>2, 'title'=>'ПК', 'parent_id' => 1], ['id'=>3, 'title'=>'Ноутбуки', 'parent_id' => 1], ['id'=>4, 'title'=>'Мобильные телефоны', 'parent_id' => 0], ['id'=>5, 'title'=>'Бытовая химия', 'parent_id' => null], ['id'=>6, 'title'=>'Порошок', 'parent_id' => 5], ['id'=>7, 'title'=>'Мыло', 'parent_id' => 5], ['id'=>8, 'title'=>'Трансформеры', 'parent_id' => 3], ]; $root = restore_tree($data); print_tree($root); 

Work result

  • Fatty it turned out - DivMan

Look towards NestedSetsBehavior ( https://github.com/creocoder/yii2-nested-sets ), since you are using Yii2.

  • Yes, I'm aware of the nested-sets account, I just needed to work with this table. I will now make the menu with nested-sets) - Samat Zhanbekov

See here. Sub Sub Categories (Sub-Sub Categories) WordPress

Function get_categories schematic

 function get_categories(parent) { if (parent == null) { return SELECT * FROM categories WHERE parent IS NULL } else { return SELECT * FROM categories WHERE parent = :parent } } 

As through Category::find() I have no idea, so I’m just select sql
maxdeep remove if not needed.

You can simplify the node structure by incorporating in them not references to category, but the fields of these category. Or in category to introduce a link to parent and use instead of node.