За последние 24 часа нас посетили 17535 программистов и 1719 роботов. Сейчас ищут 1652 программиста ...

Вывод категорий и подкатегорий

Тема в разделе "PHP для новичков", создана пользователем Dimon2x, 19 дек 2017.

  1. Dimon2x

    Dimon2x Старожил

    С нами с:
    26 фев 2012
    Сообщения:
    2.210
    Симпатии:
    185
    Сделал новым способом, какие есть убожества?

    PHP:
    1. $ret = [
    2.     1=>["id"=>1, "parent_id"=>0, 'title' => 'Фильмы'],
    3.     2=>["id"=>2, "parent_id"=>1, 'title' => 'Джеки Чан'],
    4.     3=>["id"=>3, "parent_id"=>1, 'title' => 'Форсаж'],
    5.     4=>["id"=>4, "parent_id"=>0, 'title' => 'Антивирусы'],
    6.     5=>["id"=>5, "parent_id"=>4, 'title' => 'Касперский'],
    7.     6=>["id"=>6, "parent_id"=>1, 'title' => 'Шурик'],
    8.     7=>["id"=>7, "parent_id"=>5, 'title' => 'Версия 2020'],
    9. ];
    PHP:
    1. foreach ($ret as $id => $node) {
    2.     if (isset($ret[$node['parent_id']])) {
    3.         $ret[$node['parent_id']]['sub'][$id] =& $ret[$id];
    4.  
    5.     }
    6. }
    7.  
    8. $return = [];
    9.  
    10. foreach ($ret as $k=>$v){
    11.     if($v["parent_id"] == 0){
    12.         $return[$k]= $v;
    13.     }
    14. }
    Получается вот такое

    Код (Text):
    1. Array
    2. (
    3.     [1] => Array
    4.         (
    5.             [id] => 1
    6.             [parent_id] => 0
    7.             [title] => Фильмы
    8.             [sub] => Array
    9.                 (
    10.                     [2] => Array
    11.                         (
    12.                             [id] => 2
    13.                             [parent_id] => 1
    14.                             [title] => Джеки Чан
    15.                         )
    16.  
    17.                     [3] => Array
    18.                         (
    19.                             [id] => 3
    20.                             [parent_id] => 1
    21.                             [title] => Форсаж
    22.                         )
    23.  
    24.                     [6] => Array
    25.                         (
    26.                             [id] => 6
    27.                             [parent_id] => 1
    28.                             [title] => Шурик
    29.                         )
    30.  
    31.                 )
    32.  
    33.         )
    34.  
    35.     [4] => Array
    36.         (
    37.             [id] => 4
    38.             [parent_id] => 0
    39.             [title] => Антивирусы
    40.             [sub] => Array
    41.                 (
    42.                     [5] => Array
    43.                         (
    44.                             [id] => 5
    45.                             [parent_id] => 4
    46.                             [title] => Касперский
    47.                             [sub] => Array
    48.                                 (
    49.                                     [7] => Array
    50.                                         (
    51.                                             [id] => 7
    52.                                             [parent_id] => 5
    53.                                             [title] => Версия 2020
    54.                                         )
    55.  
    56.                                 )
    57.  
    58.                         )
    59.  
    60.                 )
    61.  
    62.         )
    63.  
    64. )
    И потом формирую разметку

    PHP:
    1. function derevo($el) {
    2.     foreach($el as $k => $v) {
    3.    
    4.     $markup .= '<li>';
    5.    
    6.         if(is_array($v)) {
    7.             $markup .= '<a href="'.$v['parent_id'].'">' . $v['title'] . '</a>';
    8.             if(isset($v['sub']) && !empty($v['sub'])) {
    9.                 $markup .= derevo($v['sub']);
    10.                 continue;
    11.             }
    12.             else {
    13.                 continue;
    14.             }
    15.         }
    16.        
    17.     $markup .= '<li>';
    18. }
    19.  
    20. return '<ul>' . $markup . '</ul>';
    21. }
    22.  
    23. echo derevo($return);
     
  2. TeslaFeo

    TeslaFeo Старожил

    С нами с:
    9 мар 2016
    Сообщения:
    2.984
    Симпатии:
    759
    вот тебе маленький кусок кода, который трахнет твой компутер в ЦП и в ОЗУ :)
    PHP:
    1. for ($x = 1; $x < 256; $x++){
    2.   for ($y = 1; $y < 256; $y++){
    3.     for ($z = 1; $z < 256; $z++){
    4.       $array[$x][$y][$z] = $x * $y * $z;
    5.     }
    6.   }
    7. }
    циферки безобидные на первый взгляд, но это обманчивое впечатление.
     
    Dimon2x нравится это.
  3. TeslaFeo

    TeslaFeo Старожил

    С нами с:
    9 мар 2016
    Сообщения:
    2.984
    Симпатии:
    759
    первым способом можно делать и не париться
    пусть себе перебирается. категорий не бывает по 2к обычно

    если прям так перфекционизм кушает, то можно удалять "использованную" часть

    если так заморачиваться, то ни один проект никогда не закончишь.
     
  4. Dimon2x

    Dimon2x Старожил

    С нами с:
    26 фев 2012
    Сообщения:
    2.210
    Симпатии:
    185
  5. Dimon2x

    Dimon2x Старожил

    С нами с:
    26 фев 2012
    Сообщения:
    2.210
    Симпатии:
    185
    @mkramer я думаю рекурсия для небольшого дерева, ничего не на вредит?
     
  6. TeslaFeo

    TeslaFeo Старожил

    С нами с:
    9 мар 2016
    Сообщения:
    2.984
    Симпатии:
    759
    Который Миша забраковал)
     
  7. johovich

    johovich Активный пользователь

    С нами с:
    24 авг 2016
    Сообщения:
    146
    Симпатии:
    17
    PHP:
    1.     // Инициализация категорий, после которой категории будем выбирать из локальной переменной
    2.     public function init_categories($reinit = false): void
    3.     {
    4.         dtimer::log(__METHOD__ . " start reinit flag: " . var_export($reinit, true));
    5.         if ($reinit === false ) {
    6.             //если категории уже инициализированы
    7.             if($this->all_categories !== null){
    8.                 return;
    9.             }
    10.             if (function_exists('apcu_fetch')) {
    11.                 dtimer::log(__METHOD__ . " ACPU CACHE CATEGORIES READ ");
    12.                 $this->all_categories = apcu_exists($this->config->host . 'all_categories') ? apcu_fetch($this->config->host . 'all_categories') : null;
    13.                 $this->categories_tree = &$this->all_categories[0]['subcategories'];
    14.                 $this->categories_uri = &$this->all_categories[0]['uri'];
    15.                 unset($this->all_categories[0]); //remove root element
    16.                 if ($this->all_categories) {
    17.                     return;
    18.                 }
    19.             }
    20.         }
    21.  
    22.  
    23.         // Выбираем все категории
    24.         $cats = $this->db3->getInd("id", "SELECT * FROM s_categories ORDER BY parent_id, pos ASC");
    25.         $ids = array_keys($cats);
    26.         // Дерево категорий
    27.         $tree = [];
    28.         $tree['subcategories'] = [];
    29.         $tree['level'] = 0;
    30.         $tree['children'] = [0];
    31.         $tree['path'] = [];
    32.         $tree['uri'] = [];
    33.         $tree['total'] = 0;
    34.  
    35.         //указатели на узлы дерева
    36.         $ptr[0] = &$tree; //корневой элемент
    37.  
    38.         // Не кончаем, пока не кончатся категории, или пока ни одну из оставшихся некуда приткнуть
    39.         $finish = false;
    40.         while(!empty($ids) && !$finish) {
    41.             $flag = false;
    42.             foreach ($ids as $i=>$cid) {
    43.                 if(!isset($ptr[$cats[$cid]['parent_id']])){
    44.                     continue;
    45.                 }
    46.                 $cat = &$cats[$cid];
    47.                 $cat['id'] = (int)$cid;
    48.                 $cat['parent_id'] = (int)$cat['parent_id'];
    49.                 $cat['vparent_id'] = (int)$cat['vparent_id'];
    50.                 $cat['vcat1'] = explode(',', $cat['vcat1']);
    51.                 $cat['vcat2'] = explode(',', $cat['vcat2']);
    52.                 $cat['enabled'] = (bool)$cat['enabled'];
    53.                 $cat['visible'] = (bool)$cat['visible'];
    54.                 $cat['path'] = [];
    55.                 $cat['vchildren'] = [];
    56.                 $cat['children'] = [];
    57.                 $cat['subcategories'] = [];
    58.                 $cat['total'] = 0;
    59.                 //сначала часть родительского пути
    60.                 $cat['path'] = $ptr[$cat['parent_id']]['path'];
    61.                 //саму себя в конце
    62.                 $cat['path'][] = &$cat;
    63.  
    64.                 //запишемся в массив указателей
    65.                 $ptr[$cid] = &$cat;
    66.                 //добавимся в дочерние к родительской категории
    67.                 $ptr[$cat['parent_id']]['subcategories'][] = &$ptr[$cid];
    68.                 if($cat['visible']) $ptr[$cat['parent_id']]['total'] += 1;
    69.  
    70.                 // Уровень вложенности категории
    71.                 $cat['level'] = 1 + $ptr[$cat['parent_id']]['level'];
    72.  
    73.                 //добавим виртуальные разделы к его родителю
    74.                 $cats[$cat['vparent_id']]['vchildren'][] = $cid;
    75.  
    76.                 unset($ids[$i]);
    77.                 $flag = true;
    78.             }
    79.             if(!$flag){
    80.                 $finish = true;
    81.             }
    82.         }
    83.  
    84.         $ids = array_keys($ptr);
    85.         unset($ids[0]); //уберем корневой раздел
    86.         $ids = array_reverse($ids); //обратный порядок важен чтобы матрешка собралась правильно
    87.         foreach ($ids as $cid) {
    88.             $cat = &$ptr[$cid];
    89.  
    90.             //отмечаем первый и последний элемент (используется в меню)
    91.             $i = 0;
    92.             while(!empty($cat['subcategories'][$i])){
    93.                 if($cat['subcategories'][$i]['visible']){
    94.                     $cat['subcategories'][$i]['first'] = true;
    95.                     break(1);
    96.                 }
    97.                 ++$i;
    98.             }
    99.             $j = count($cat['subcategories']) - 1;
    100.             while(!empty($cat['subcategories'][$i])){
    101.                 if($cat['subcategories'][$j]['visible']){
    102.                     $cat['subcategories'][$j]['last'] = true;
    103.                     break(1);
    104.                 }
    105.                 --$j;
    106.             }
    107.  
    108.             //сначала добавим саму себя
    109.             $cat['children'][] = $cid;
    110.             //теперь прибавим к родительскому разделу свои
    111.             $ptr[$cat['parent_id']]['children'] = array_merge($ptr[$cat['parent_id']]['children'], $cat['children']);
    112.  
    113.             //транслит имена добавим в корневой массив
    114.             $tree['uri'][$cat['trans']] = $cid;
    115.             if($cat['trans2'] !== '') {
    116.                 $tree['uri'][$cat['trans2']] = $cid;
    117.             }
    118.         }
    119.  
    120.  
    121.         if (function_exists('apcu_store')) {
    122.             dtimer::log(__METHOD__ . " update categories APCU");
    123.             apcu_store($this->config->host . 'all_categories', $ptr, 14400);
    124.         }
    125.  
    126.         unset($ptr[0]); //unset root element
    127.         $this->all_categories = &$ptr;
    128.         $this->categories_uri = &$tree['uri'];
    129.         $this->categories_tree = &$tree['subcategories'];
    130.  
    131.     }
    Вывод категорий 1 запросом с последующим сохранением в apcu кеш.
    Преимущества:
    1. Есть мало памяти
    2. Относительно быстро инициализируется (1 запрос в БД, перечисление чуть больше, чем кол-во категорий).

    Недостатки:
    1. Невозможно компактно сериализовать по причине использования указателей.
     
  8. Dimon2x

    Dimon2x Старожил

    С нами с:
    26 фев 2012
    Сообщения:
    2.210
    Симпатии:
    185
  9. johovich

    johovich Активный пользователь

    С нами с:
    24 авг 2016
    Сообщения:
    146
    Симпатии:
    17
    Чего тебе не хватает?
     
  10. Fell-x27

    Fell-x27 Суперстар
    Команда форума Модератор

    С нами с:
    25 июл 2013
    Сообщения:
    12.156
    Симпатии:
    1.770
    Адрес:
    :сердА
    Карочи. Вот тебе без рекурсий, за один проход по массиву, без лишнего расхода памяти, без лишнего расхода процессура.
    Функция берет на вход твой массив, на выходе отдает древовидную структуру. По ней уже строй HTML хоть застройся.

    Можно сразу HTML строить и в функции, но я не люблю мух с котлетами смешивать, сорян. Дальше сам.

    PHP:
    1. <?php
    2.  
    3. $tree = [
    4.     ['name' => 'Уровень 1',     'id' => 1,  'pid' => 0],
    5.     ['name' => 'Уровень 1.1',   'id' => 2,  'pid' => 1],
    6.     ['name' => 'Уровень 1.2',   'id' => 3,  'pid' => 1],
    7.     ['name' => 'Уровень 1.3',   'id' => 4,  'pid' => 1],
    8.     ['name' => 'Уровень 2',     'id' => 5,  'pid' => 0],
    9.     ['name' => 'Уровень 2.1',   'id' => 6,  'pid' => 5],
    10.     ['name' => 'Уровень 2.2',   'id' => 7,  'pid' => 5],
    11.     ['name' => 'Уровень 3',     'id' => 8,  'pid' => 0],
    12.     ['name' => 'Уровень 3.1',   'id' => 9,  'pid' => 8],
    13.     ['name' => 'Уровень 3.1.1', 'id' => 10, 'pid' => 9],
    14.     ['name' => 'Уровень 3.1.2', 'id' => 11, 'pid' => 9]
    15. ];
    16.  
    17. function rebuildTree($tree){
    18.     $branches = [];
    19.     $resut = [];
    20.     foreach ($tree as $key=>$node){
    21.         $ref = &$tree[$key];
    22.         $branches[$node['id']] = &$ref;    
    23.         $branches[$node['pid']]['chld'][] = &$ref;    
    24.  
    25.         if ($node['pid'] === 0){
    26.             $result[] = &$ref;
    27.         }
    28.     }
    29.     return $result;
    30. }
    31.  
    32. print_r(rebuildTree($tree));
    Выхлоп:
    PHP:
    1. (
    2.     [0] => Array
    3.         (
    4.             [name] => Уровень 1
    5.             [id] => 1
    6.             [pid] => 0
    7.             [chld] => Array
    8.                 (
    9.                     [0] => Array
    10.                         (
    11.                             [name] => Уровень 1.1
    12.                             [id] => 2
    13.                             [pid] => 1
    14.                         )
    15.  
    16.                     [1] => Array
    17.                         (
    18.                             [name] => Уровень 1.2
    19.                             [id] => 3
    20.                             [pid] => 1
    21.                         )
    22.  
    23.                     [2] => Array
    24.                         (
    25.                             [name] => Уровень 1.3
    26.                             [id] => 4
    27.                             [pid] => 1
    28.                         )
    29.  
    30.                 )
    31.  
    32.         )
    33.  
    34.     [1] => Array
    35.         (
    36.             [name] => Уровень 2
    37.             [id] => 5
    38.             [pid] => 0
    39.             [chld] => Array
    40.                 (
    41.                     [0] => Array
    42.                         (
    43.                             [name] => Уровень 2.1
    44.                             [id] => 6
    45.                             [pid] => 5
    46.                         )
    47.  
    48.                     [1] => Array
    49.                         (
    50.                             [name] => Уровень 2.2
    51.                             [id] => 7
    52.                             [pid] => 5
    53.                         )
    54.  
    55.                 )
    56.  
    57.         )
    58.  
    59.     [2] => Array
    60.         (
    61.             [name] => Уровень 3
    62.             [id] => 8
    63.             [pid] => 0
    64.             [chld] => Array
    65.                 (
    66.                     [0] => Array
    67.                         (
    68.                             [name] => Уровень 3.1
    69.                             [id] => 9
    70.                             [pid] => 8
    71.                             [chld] => Array
    72.                                 (
    73.                                     [0] => Array
    74.                                         (
    75.                                             [name] => Уровень 3.1.1
    76.                                             [id] => 10
    77.                                             [pid] => 9
    78.                                         )
    79.  
    80.                                     [1] => Array
    81.                                         (
    82.                                             [name] => Уровень 3.1.2
    83.                                             [id] => 11
    84.                                             [pid] => 9
    85.                                         )
    86.  
    87.                                 )
    88.  
    89.                         )
    90.  
    91.                 )
    92.  
    93.         )
    94.  
    95. )
     
    Dimon2x и johovich нравится это.
  11. Dimon2x

    Dimon2x Старожил

    С нами с:
    26 фев 2012
    Сообщения:
    2.210
    Симпатии:
    185
    При объединении таблиц, айдишники бьются

    Код (Text):
    1. SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
    2. SET AUTOCOMMIT = 0;
    3. START TRANSACTION;
    4. SET time_zone = "+00:00";
    5.  
    6.  
    7. /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
    8. /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
    9. /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
    10. /*!40101 SET NAMES utf8mb4 */;
    11.  
    12. --
    13. -- База данных: `derevo`
    14. --
    15.  
    16. -- --------------------------------------------------------
    17.  
    18. --
    19. -- Структура таблицы `category`
    20. --
    21.  
    22. CREATE TABLE `category` (
    23.   `id` int(11) NOT NULL,
    24.   `name` varchar(256) NOT NULL,
    25.   `pid` int(11) NOT NULL
    26. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    27.  
    28. --
    29. -- Дамп данных таблицы `category`
    30. --
    31.  
    32. INSERT INTO `category` (`id`, `name`, `pid`) VALUES
    33. (1, 'Фильмы', 0),
    34. (2, 'Антивирусы', 0);
    35.  
    36. -- --------------------------------------------------------
    37.  
    38. --
    39. -- Структура таблицы `subcategory`
    40. --
    41.  
    42. CREATE TABLE `subcategory` (
    43.   `id` int(11) NOT NULL,
    44.   `name` varchar(256) NOT NULL,
    45.   `pid` int(11) NOT NULL
    46. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    47.  
    48. --
    49. -- Дамп данных таблицы `subcategory`
    50. --
    51.  
    52. INSERT INTO `subcategory` (`id`, `name`, `pid`) VALUES
    53. (1, 'Джеки Чан', 1),
    54. (2, 'Форсаж', 1),
    55. (3, 'Касперский', 2),
    56. (4, 'Шурик', 1);
    57.  
    58. --
    59. -- Индексы сохранённых таблиц
    60. --
    61.  
    62. --
    63. -- Индексы таблицы `category`
    64. --
    65. ALTER TABLE `category`
    66.   ADD PRIMARY KEY (`id`);
    67.  
    68. --
    69. -- Индексы таблицы `subcategory`
    70. --
    71. ALTER TABLE `subcategory`
    72.   ADD PRIMARY KEY (`id`);
    73.  
    74. --
    75. -- AUTO_INCREMENT для сохранённых таблиц
    76. --
    77.  
    78. --
    79. -- AUTO_INCREMENT для таблицы `category`
    80. --
    81. ALTER TABLE `category`
    82.   MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3;
    83.  
    84. --
    85. -- AUTO_INCREMENT для таблицы `subcategory`
    86. --
    87. ALTER TABLE `subcategory`
    88.   MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=5;
    89. COMMIT;
    90.  
    91. /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
    92. /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
    93. /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
    Код (Text):
    1. SELECT * FROM category
    2. UNION SELECT * FROM subcategory
    3. ORDER BY pid DESC;
    Получается такое

    PHP:
    1. (
    2.     [0] => Array
    3.         (
    4.             [id] => 3
    5.             [name] => Касперский
    6.             [pid] => 2
    7.         )
    8.  
    9.     [1] => Array
    10.         (
    11.             [id] => 1
    12.             [name] => Джеки Чан
    13.             [pid] => 1
    14.         )
    15.  
    16.     [2] => Array
    17.         (
    18.             [id] => 2
    19.             [name] => Форсаж
    20.             [pid] => 1
    21.         )
    22.  
    23.     [3] => Array
    24.         (
    25.             [id] => 4
    26.             [name] => Шурик
    27.             [pid] => 1
    28.         )
    29.  
    30.     [4] => Array
    31.         (
    32.             [id] => 1
    33.             [name] => Фильмы
    34.             [pid] => 0
    35.         )
    36.  
    37.     [5] => Array
    38.         (
    39.             [id] => 2
    40.             [name] => Антивирусы
    41.             [pid] => 0
    42.         )
    43.  
    44. )
     
  12. Fell-x27

    Fell-x27 Суперстар
    Команда форума Модератор

    С нами с:
    25 июл 2013
    Сообщения:
    12.156
    Симпатии:
    1.770
    Адрес:
    :сердА
    А я тут причем? У тебя есть плоское представление дерева? Есть.

    Вот оно:

    PHP:
    1. $tree = [
    2.     ['name' => 'Уровень 1',     'id' => 1,  'pid' => 0],
    3.     ['name' => 'Уровень 1.1',   'id' => 2,  'pid' => 1],
    4.     ['name' => 'Уровень 1.2',   'id' => 3,  'pid' => 1],
    5.     ['name' => 'Уровень 1.3',   'id' => 4,  'pid' => 1],
    6.     ['name' => 'Уровень 2',     'id' => 5,  'pid' => 0],
    7.     ['name' => 'Уровень 2.1',   'id' => 6,  'pid' => 5],
    8.     ['name' => 'Уровень 2.2',   'id' => 7,  'pid' => 5],
    9.     ['name' => 'Уровень 3',     'id' => 8,  'pid' => 0],
    10.     ['name' => 'Уровень 3.1',   'id' => 9,  'pid' => 8],
    11.     ['name' => 'Уровень 3.1.1', 'id' => 10, 'pid' => 9],
    12.     ['name' => 'Уровень 3.1.2', 'id' => 11, 'pid' => 9]
    13. ];
    У всех элементов одинаковая структура? Одинаковая. Смысл у элементов одинаковый? Одинаковый.
    Ну так если у них одинаковая структура и смысл, то и храни их в одной таблице. Нахрена городить города?

    id - уникальный индекс
    pid - кольцевая ссылка на эту же таблицу на столбец id

    И понеслась.
     
    #37 Fell-x27, 3 дек 2018
    Последнее редактирование: 3 дек 2018
  13. johovich

    johovich Активный пользователь

    С нами с:
    24 авг 2016
    Сообщения:
    146
    Симпатии:
    17
    Возьми этот код и запусти с пошаговым выполнением через phpStorm. Сможешь понять в деталях как это происходит.

    PHP:
    1. <?php
    2. function rebuildTree($tree){
    3.     $branches = [];
    4.     $result = [];
    5.     foreach ($tree as $key=>$node){
    6.         $ref = &$tree[$key];
    7.         $branches[$node['id']] = &$ref;
    8.         $branches[$node['pid']]['child'][] = &$ref;
    9.  
    10.         if ($node['pid'] === 0){
    11.             $result[] = &$ref;
    12.         }
    13.     }
    14.     return $result;
    15. }
    16.  
    17. $tree = [
    18.     ["id" => 1, "name" => "cat 1", "pid" => 0],
    19.     ["id" => 2, "name" => "cat 2", "pid" => 1],
    20.     ["id" => 3, "name" => "cat 3", "pid" => 2],
    21.     ["id" => 4, "name" => "cat 4", "pid" => 1],
    22. ];
    23.  
    24. print_r(rebuildTree($tree));
     

    Вложения:

  14. Fell-x27

    Fell-x27 Суперстар
    Команда форума Модератор

    С нами с:
    25 июл 2013
    Сообщения:
    12.156
    Симпатии:
    1.770
    Адрес:
    :сердА
    Ды не, у него категории и подкатегории - это две разные таблицы. А подподкатегории, видимо, третья таблица. Стало быть, айдишники в них пересекаются и, при вытаскивании финальной сборки, все ломается к чертям. Еще на стадии подготовки данных.

    Такое бывает, когда данные, которые должны лежать в одной таблице, лежат в разных, а потом сваливаются в одну кучу.
     
  15. johovich

    johovich Активный пользователь

    С нами с:
    24 авг 2016
    Сообщения:
    146
    Симпатии:
    17
    Еще 1 недостаток нашел в твоей функции. Если в исходном массиве $tree сначала попадется элемент с родителем, который еще не добавлен в $branches, то дальше, когда цикл дойдет до этого родителя - child потрет.

    Вот пример дерева, которое вызовет проблемы.
    PHP:
    1. $tree = [
    2.   ["id" => 1, "name" => "cat 1", "pid" => 2],
    3.   ["id" => 2, "name" => "cat 2", "pid" => 0],
    4.   ["id" => 3, "name" => "cat 3", "pid" => 2],
    5.   ["id" => 4, "name" => "cat 4", "pid" => 1],
    6. ];
    Доработка:
    PHP:
    1. <?php
    2. function rebuildTree($tree){
    3.     $branches = [];
    4.     $result = [];
    5.     foreach ($tree as $key=>$node){
    6.         $ref = &$tree[$key];
    7.         if(isset($branches[$node['id']])){
    8.             $ref["child"] = $branches[$node['id']]["child"];
    9.         }
    10.         $branches[$node['id']] = &$ref;
    11.      
    12.         $branches[$node['pid']]['child'][] = &$ref;
    13.  
    14.         if ($node['pid'] === 0){
    15.             $result[] = &$ref;
    16.         }
    17.     }
    18.     return $result;
    19. }
    20.  
    21. $tree = [
    22.   ["id" => 1, "name" => "cat 1", "pid" => 2],
    23.   ["id" => 2, "name" => "cat 2", "pid" => 0],
    24.   ["id" => 3, "name" => "cat 3", "pid" => 2],
    25.   ["id" => 4, "name" => "cat 4", "pid" => 1],
    26. ];
    27.  
    28. print_r(rebuildTree($tree));
     
    Dimon2x нравится это.
  16. Dimon2x

    Dimon2x Старожил

    С нами с:
    26 фев 2012
    Сообщения:
    2.210
    Симпатии:
    185
    да
     
  17. Fell-x27

    Fell-x27 Суперстар
    Команда форума Модератор

    С нами с:
    25 июл 2013
    Сообщения:
    12.156
    Симпатии:
    1.770
    Адрес:
    :сердА
    Выбираешь из бд с сортировкой pid по возрастанию и ок, в общем-то.
     
  18. Dimon2x

    Dimon2x Старожил

    С нами с:
    26 фев 2012
    Сообщения:
    2.210
    Симпатии:
    185
  19. Fell-x27

    Fell-x27 Суперстар
    Команда форума Модератор

    С нами с:
    25 июл 2013
    Сообщения:
    12.156
    Симпатии:
    1.770
    Адрес:
    :сердА
    А я не тебе ответил в предыдущем сообщении, Дим. Там все в тему сказано.

    Что там бьется - это уже проблема твоей архитектуры бд. Ты выложил код, сказал, что он норм и тебе нравится, я использовал тестовые данные из твоего поста, написал свой код. А ты ко мне с бьющимися айдишниками. Это не моя проблема, решение описано было и выше на форуме и в тележке, причем не раз.
     
  20. johovich

    johovich Активный пользователь

    С нами с:
    24 авг 2016
    Сообщения:
    146
    Симпатии:
    17
    Одной сортировки недостаточно.
    Пруф.
    PHP:
    1. $tree = [
    2.  ["id" => 3, "name" => "cat 3", "pid" => 0],
    3.  ["id" => 1, "name" => "cat 1", "pid" => 2],
    4.  ["id" => 4, "name" => "cat 4", "pid" => 3],
    5.  ["id" => 2, "name" => "cat 2", "pid" => 4],
    6. ];
     
  21. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.583
    Симпатии:
    1.761
    @Dimon2x, да можно и рекурсией, только зачем? Я просто тебя не понимаю. Я тебе ещё в начале темы где-то назвал Nested Sets и Materialized Path, умные люди придумали, двести пятьдесят раз код написан. Под Ларку прекрасные библиотеки. Без ларки тоже есть библиотеки. В виде готовых SQL-запросов, если хочется самому - тоже есть. А ты всё хочешь рекурсивно, или в разных таблицах хранить категории и подкатегории. Ну может я такой глупый и не вижу в этом смысла, не знаю. У меня, если вложенные категории в проекте, я сразу пишу nested sets, если древовидные комменты - nested sets, если что угодно древовидное - nested sets.
     
  22. johovich

    johovich Активный пользователь

    С нами с:
    24 авг 2016
    Сообщения:
    146
    Симпатии:
    17
    Что значит не бьется? В последний раз слышал это слово от теток из планово-экономического отдела. У них обычно что-то не бьется. Означать может все что угодно.
    Сделай для себя полезную вещь - посмотри как работает функция пошагово через дебагер.
     
  23. Fell-x27

    Fell-x27 Суперстар
    Команда форума Модератор

    С нами с:
    25 июл 2013
    Сообщения:
    12.156
    Симпатии:
    1.770
    Адрес:
    :сердА
    а если по Id? Я реально щас проверить не могу. Но в голове вроде норм работает.
     
  24. johovich

    johovich Активный пользователь

    С нами с:
    24 авг 2016
    Сообщения:
    146
    Симпатии:
    17
    Тоже не выйдет. У тебя же на каждой итерации добавляется 2 элемента в $branches: первый - сама категория, второй - элемент от родительской категории. Тут без условия можно с двойным перебором, когда на первом цикле у тебя все категории встанут в branches, а на втором цикле разложить деток.
     
  25. Dimon2x

    Dimon2x Старожил

    С нами с:
    26 фев 2012
    Сообщения:
    2.210
    Симпатии:
    185