2014-09-30 2 views
0

так что я использую php framework, это Laravel. У меня есть таблица комментариев, и комментарии могут иметь дочерние комментарии. Я заказал комментарии по обновленным времени:Laravel глубина первого обхода дерева

$post->comments()->orderBy('updated_at')->paginate(10); 

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

  • comment1
  • subcommentA из comment1
  • subcommentB из comment1
  • comment2
  • subcommentC из comment2
  • subcommentD из comment2
  • subcommentE из subcommentD
  • ...

Теперь этот порядок не может быть сделано путем простого 'OrderBy', мой вопрос: может Я выполняю это с помощью Laravel query builder/eloquent, или мне нужно заказывать вручную? Кстати, я создал модель комментарий так, что его родитель/дети могут быть выбраны с помощью:

$comment->parentComment; 
$comment->childComments; 
+0

Поскольку это древовидная структура, это немного сложно, потому что вы можете получить несколько (в теории бесконечных) запросов, но самым простым способом будет просто рекурсивно загружать комментарии с детьми. –

ответ

0

Я понял, что если мне придется заказывать все комментарии к сообщению каждый раз, когда я беру данные из базы данных, это может в конечном итоге привести к большой проблеме с производительностью. Так что мой обходной путь заключается в следующем: Во-первых, это мой комментарий таблица:

+-------------------+------------------+------+-----+---------------------+----------------+ 
| Field    | Type    | Null | Key | Default    | Extra   | 
+-------------------+------------------+------+-----+---------------------+----------------+ 
| id    | int(10) unsigned | NO | PRI | NULL    | auto_increment | 
| content   | varchar(2000) | NO |  | NULL    |    | 
| author_id   | int(10) unsigned | NO | MUL | NULL    |    | 
| post_id   | int(10) unsigned | NO | MUL | NULL    |    | 
| parent_comment_id | int(10) unsigned | YES | MUL | NULL    |    | 
| level    | tinyint(4)  | NO |  | 1     |    | 
| sort_order  | int(10) unsigned | NO |  | NULL    |    | 
| created_at  | timestamp  | NO |  | 0000-00-00 00:00:00 |    | 
| updated_at  | timestamp  | NO |  | 0000-00-00 00:00:00 |    | 
+-------------------+------------------+------+-----+---------------------+----------------+ 

Обратите внимание, что есть поле, называемое sort_order, каждый раз, когда есть новый комментарий, добавленный к сообщению, один из следующих двух вещей случаться решить значение sort_order в Новый_комментарий в:

  1. Если комментарий не имеет родителя, то

    $ newComment-> sort_order = комментарий :: макс ('sORT_ORDER') + 1;

  2. Если комментарий имеет родителя, то

    $parent = $newComment->parentComment; 
    $newComment->sort_order = $parent->sort_order + 1; 
    // for all the comments that have sort_order larger than the parent of the newly added comment, add their sort_order by 1 
    $comments_to_be_updated = Comment::where('sort_order', '>', $parent->sort_order)->get(); 
    foreach ($comments_to_be_updated as $comment_to_be_updated) { 
        $comment_to_be_updated->sort_order += 1; 
        $comment_to_be_updated->save(); 
    } 
    

    Таким образом, каждый раз, когда новый комментарий добавлен, его позиция/заказ будет завершен и записан sort_order, когда я хочу получать комментарии к записи с требуемым порядком, все, что мне нужно:

    $ post-> comments-> orderBy ('sort_order') -> paginate (10);

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

0

Вы можете достичь этого, используя модель отношений (само), к примеру, предположим, что это ваш comments таблица:

id (PK) | content | post_id | user_id | comment_parent 
------------------------------------------------------ 
1  | Hello | 1  | 1  | 0 <-- This is a parent because of 0 
2  | Hi  | 1  | 2  | 1 <-- child of 1 
3  | Howdy | 1  | 3  | 1 <-- child of 1 

Читайте эту таблицу: есть всего три комментария, первый комментарий производится User с user_id-1 и у него есть два ребенок замечания, сделанные два других пользователей, чьи id «s являются user_id-2 и user_id-3.

Здесь колонка comment_parent поддерживает отношения между parent и child комментариями. comment_parent со значением 0 является родительским комментарием и кроме 0, например, здесь два комментария имеют comment_parent из 1, что означает, что эти два комментария являются дочерними элементами комментария, id/PK - 1.

Итак, теперь, в вашей Comment модели объявить эти методы:

// Get only children of a comment 
public function children() 
{ 
    return $this->hasMany('Comment', 'comment_parent'); 
} 

// Get the user of comment 
public function user() 
{ 
    return $this->belongsTo('User', 'user_id'); 
} 

// Get the post of comment 
public function post() 
{ 
    return $this->belongsTo('Post', 'post_id'); 
} 

Затем в Post модели объявить этот метод:

// Only parent comments 
public function comments() 
{ 
    return $this->hasMany('Comment', 'post_id')->where('comment_parent', 0); 
} 

// All Comments 
public function allComments() 
{ 
    return $this->hasMany('Comment', 'post_id'); 
} 

Теперь, если вы делаете что-то вроде этого:

$post = Post::with('comments.children')->find(1); 

Тогда вы можете попробовать что-то подобное на ваш взгляд (возможно в вашем post.single.blade.php):

{{ $post->title }} 
{{ $post->body }} 

<!-- Comment Template For Posting New Comments--> 

@if($post->comments->count()) 

    @foreach($post->comments as $comment) 

     {{ $comment->user->username }} 
     {{ $comment->body }} 

     @if($comment->children->count()) 

      @foreach($comment->children as $childComment) 

       {{ $childComment->user->username }} 
       {{ $childComment->body }} 

      @endforeach 

     @endif 

    @endforeach 

@endif 

Это идея, и в этом случае ваши комментарии будут иметь 0 как comment_parent по умолчанию, и если комментарий является ответом на другой комментарий, то установить его comment_parent на это родитель id. Кроме того, вы можете проверить this article на другой подход.

+0

Спасибо за подробный ответ. Я думаю, что это работает, хотя я думаю, что здесь есть большая предпосылка: дерево комментариев имеет максимальную глубину 2. В моей первой мысли я думаю, что система комментариев допускает бесконечную глубину, что означает, что независимо от того, насколько далеко далек комментарий A от своего первого предка (скажем, комментарий А является внуком внука внука ... комментария Б), комментарий А по-прежнему открыт для другого детского комментария ... так что в моем случае я считаю, что рекурсия - это , – dulan

+0

Тогда вы можете перейти по ссылке, которую я вам дал :-) –

Смежные вопросы