Задать вопрос

Древовидные комментарии

По какому алгоритму лучше организовать древовидные комментарии с уровнем вложенности 2?
Целесообразно ли здесь использовать алгоритмы построения дерева?

  • Вопрос задан
  • 13771 просмотр
Подписаться 23 Оценить Комментировать
Решения вопроса 1
GearHead
@GearHead
Fullstack разработчик и предприниматель
не надо никаких деревьев и parentID. из-за них вы можете столкнуться с JOIN'ами или проблемой (n+1) запросов. всё проще:
1) выберите признак, по которому сортируете комменты в топике. к примеру это created_at.
2) для всех комментов храните created_at и parent_created_at. для корневых кладите в parent_created_at значение created_at.
3) Выборка ORDER parent_created_at DESC, created_at DESC получает комменты в нужном порядке
4) при рендеринге проверкой parent_created_at равно created_at — без отступа, не равно — с отступом
5) ?????
6) PROFIT дерево комментов с макс. уровнем вложенности равным двум
Ответ написан
Пригласить эксперта
Ответы на вопрос 6
nixmale
@nixmale
Если речи идет о SQL, то есть одно очень хорошее решение для сортировки древовидных комментариев в один SQL запрос без LEFT JOIN, кстати которое с применением AJAX позволяет перезагружать отдельные ветки, начинающиеся с любого комментария в цепочки.

Предположим добавление комментариев к теме выглядит следующим образом:
$arr = array(
     array('id'=>1, 'pid'=>0, 'name'=>'Comment 1'),
      array('id'=>2, 'pid'=>1, 'name'=>'Comment 1.1'),
      array('id'=>3, 'pid'=>1, 'name'=>'Comment 1.2'),
      array('id'=>6, 'pid'=>1, 'name'=>'Comment 1.3'),
       array('id'=>4, 'pid'=>2, 'name'=>'Comment 1.1.1'),
       array('id'=>5, 'pid'=>2, 'name'=>'Comment 1.1.2'),
       array('id'=>7, 'pid'=>2, 'name'=>'Comment 1.1.3'),
     array('id'=>8, 'pid'=>0, 'name'=>'Comment 2'),
      array('id'=>12, 'pid'=>8, 'name'=>'Comment 2.1'),
      array('id'=>17, 'pid'=>8, 'name'=>'Comment 2.2'),
       array('id'=>13, 'pid'=>12, 'name'=>'Comment 2.1.1'),
        array('id'=>16, 'pid'=>13, 'name'=>'Comment 2.1.1.1'),
     array('id'=>9, 'pid'=>0, 'name'=>'Comment 3'),
      array('id'=>14, 'pid'=>9, 'name'=>'Comment 3.1'),
       array('id'=>15, 'pid'=>14, 'name'=>'Comment 3.1.1'),
     array('id'=>10, 'pid'=>0, 'name'=>'Comment 4'),
     array('id'=>11, 'pid'=>0, 'name'=>'Comment 5'),
     );


Каждый комментарий имеет id и id родителя (pid). Ответ на тему должен принимать pid = 0, а ответ на комментарий — id комментария на который отвечаете соответственно. В конечном итоге дерево должно выглядеть так, как показано в массиве образце.

Чтобы раскрыть дерево за 1 SQL, достаточно достать из базы все комментарии имеющие идентификатор темы, отсортировав их так: ORDER BY pid ASC, id ASC. В результате получим следующий массив.

$arr = array(
     array('id'=>1, 'pid'=>0, 'name'=>'Comment 1'),
     array('id'=>8, 'pid'=>0, 'name'=>'Comment 2'),
     array('id'=>9, 'pid'=>0, 'name'=>'Comment 3'),
     array('id'=>10, 'pid'=>0, 'name'=>'Comment 4'),
     array('id'=>11, 'pid'=>0, 'name'=>'Comment 5'),
      array('id'=>2, 'pid'=>1, 'name'=>'Comment 1.1'),
      array('id'=>3, 'pid'=>1, 'name'=>'Comment 1.2'),
      array('id'=>6, 'pid'=>1, 'name'=>'Comment 1.3'),
       array('id'=>4, 'pid'=>2, 'name'=>'Comment 1.1.1'),
       array('id'=>5, 'pid'=>2, 'name'=>'Comment 1.1.2'),
       array('id'=>7, 'pid'=>2, 'name'=>'Comment 1.1.3'),
     array('id'=>12, 'pid'=>8, 'name'=>'Comment 2.1'),
      array('id'=>17, 'pid'=>8, 'name'=>'Comment 2.2'),
      array('id'=>14, 'pid'=>9, 'name'=>'Comment 3.1'),
      array('id'=>13, 'pid'=>12, 'name'=>'Comment 2.1.1'),
       array('id'=>16, 'pid'=>13, 'name'=>'Comment 2.1.1.1'),
       array('id'=>15, 'pid'=>14, 'name'=>'Comment 3.1.1'),
     );


Теперь требуется изменить структуру массива.

     for ($i = 0, $c = count($arr); $i < $c; $i++)
     {
       $new_arr[$arr[$i]['pid']][] = $arr[$i];
     }


И завершающая рекурсионная функция.

     function my_sort($data, $parent = 0, $level = 0)
     {
       $arr = $data[$parent];

       for($i = 0; $i < count($arr); $i++)
       {
         echo '<div style="padding-left:' . $level . 'px;">';
         echo $arr[$i]['name'];
           if(isset($data[$arr[$i]['id']])) my_sort($data, $arr[$i]['id'], 20);
         echo '</div>';
       }
     }


Теперь чтобы показать все дерево одним разом, достаточно вызвать

my_sort($new_arr, 0);
Ответ написан
@shsmad
Ну если вложенность будет 2 и не будет увеличиваться и будет использоваться sql-база, то можно использовать связку id/parent_id, алгоритмы пути и nested set можно не использовать :) А если не sql, а скажем nosql (например, mongodb), то там еще проще.
Ответ написан
Комментировать
В данном случае достаочно держать только парента у коментария, а потом спрашивать есть-ли коментарии с таким парентом

или

Сделать примерно вот так:
автонкремент на ид = 100, тй. 100, 200, 300, итд…
таблица:
ид, левел, коментарий
100, 1, «коментарий 1»
ответы на коментарий вставлять в таблицу с +1 на ид.
101, 2, «коментарий на коментарий 1»
Ответ написан
ertaquo
@ertaquo
Почему бы не сделать неограниченную вложенность, но отображать одинаково все уровни выше первого?
Ответ написан
Комментировать
Самое главное, когда будете делать дерево, сделайте дискретный градиент перед комментарием, чтобы было без проблем видно, какого уровня комментарий.
Потому что на хабре, например, когда ветка комментов разрастается, то иной раз и не поймёшь кто кому отвечает.
Ответ написан
Комментировать
phpclub.ru/detail/article/db_tree
еще стоит проштудировать nestedtree
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы