
При ответе на другой комментарий, блок смещается вправо относительно родительского комментария.
Внешний вид можно настроить под дизайн своего сайта корректируя стили CSS.
Структура БД.

При этом создается связь между таблицей comments и posts по полю post_id.
В прикрепленном файле находятся миграции для создания таблицы комментариев, а так же дамп для импорта данной таблицы с уже созданной связью и тестовыми данными. Для импорта сначала создайте таблицу "comments".
Контроллер.
В примере блок комментариев будет выводиться на странице отдельного поста. То есть комментарии привязаны к определенному посту.public function show($alias){ $post = Post::where('alias', $alias)->first(); if($post){ $comments = $post->comments; /* * Группируем комментарии по полю parent_id. При этом данное поле становится ключами массива * коллекций содержащих модели комментариев */ $com = $comments->groupBy('parent_id'); } else $com = false; return view('post',[ 'post' => $post, 'com' => $com ]); }
Тут для получения определенного поста используется алиас (а не id), по которому приложение находит строку в БД.
Для получение комментариев связанных с данным постом используется метод
public function comments() { return $this->hasMany(Comment::class ); }из модели Post.
В переменную $com попадает такой объект (согласно тестовых данных указанных выше):

где 1,3 - это значения поля 'parent_id'. У первой коллекции значение отсутствует т.к. это родительские комментарии. То есть получаем общую коллекцию содержащую другие коллекции моделей Comment. При этом эти коллекции отсортированы по полю 'parent_id'.
Напомню, что вывести на экран значение переменной $com в таком виде можно с помощью:
dd($com);разместив эту строку после объявления данной переменной.
Шаблон post.blade.php
@extends('layouts.posts') … @section('comments') @include('comments_block') @endsectionподключаем в нужном месте вывод блока комментариев.
Приведу еще минимальный код макета - файл resources\views\layouts\posts.blade.php, который тут наследуется:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <link type="text/css" media="all" href="{{asset('css')}}/comments.css" /> </head> <body> @yield('menu') @yield('content') @yield('comments') </body> </html>тут подключаем стили, а так же выводим на экран секцию с комментариями.
Файл comments.css прилагается в архиве.
Шаблон comments_block.blade.php
<div id="comments"> <ol class="commentlist group"> @foreach($com as $k => $comments) <!--Выводим только родительские комментарии parent_id = 0--> @if($k) @break @endif @include('comment', ['items' => $comments]) @endforeach </ol> </div>
Шаблон comment.blade.php
@foreach($items as $item) <li id="li-comment-{{$item->id}}" class="comment"> <div id="comment-{{$item->id}}" class="comment-container"> <div class="comment-author vcard"> <img alt="" src="https:⁄⁄www.gravatar.com/avatar/{{md5($item->email)}}?d=mm&s=75" class="avatar" height="75" width="75"> <cite class="fn">{{$item->name}}</cite> </div> <!-- .comment-author .vcard --> <div class="comment-meta commentmetadata"> <div class="intro"> <div class="commentDate"> {{ is_object($item->created_at) ? $item->created_at->format('d.m.Y в H:i') : ''}} </div> </div> <div class="comment-body"> <p>{{ $item->text }}</p> </div> <div class="reply group"> <a class="comment-reply-link" href="#respond">Ответить</a> </div> </div> </div> @if(isset($com[$item->id])) <ul class="children"> @include(env('THEME').'.comment', ['items' => $com[$item->id]]) </ul> @endif </li> @endforeach
Некоторым элементам назначен атрибут id и др., который можно использовать для скриптов js.
Функционал данного примера не использует поле для сохранения фотографии автора комментария. Предполагается, что оставить комментарий можно вообще без регистрации. При этом обязательно указание e-mail адреса. Сервис http://ru.gravatar.com позволяет получить фото по указанному e-mail в случае, если e-mail зарегистрирован на данном сервисе. Если нет, то используется изображение по-умолчанию (заглушка).
Тут, в конце, расположен блок
@if(isset($com[$item->id])) <ul class="children"> @include(env('THEME').'.comment', ['items' => $com[$item->id]]) </ul> @endifв котором проверяется имеются ли в общей коллекции подколлекции моделей с ключами равными id текущего комментария. Если есть (поле parent_id равно id текущего комментария), то рекурсионно вызывается этот же шаблон, которому передается коллекция моделей в переменной 'items'.
Все, можно тестировать вывод комментариев на экран. Не забудьте скачать файл стилей из архива и поместить в папку public\css.
Если вас интересует готовое решение с формой добавления новых комментариев - используйте мой пакет "laravel-widgets", его страница на GitHub тут.
ответ на комментарий Сергей от 20.09.2017
ответ на комментарий Сергей от 21.09.2017
ответ на комментарий Сергей от 21.09.2017
Можете передать их так же как вы передаете переменную $post:
В статье рассматривается построение "дерева" комментариев, если интересует готовое решение, то стоит установить пакет, ссылка на который дана в конце статьи.
ответ на комментарий Сергей от 22.09.2017
связь настроена, но получить name вот так не получается -> $item->user->name, есть решение?
ответ на комментарий andrey от 10.10.2017
Подробнее http://klisl.com/laravel_relationships.html
ответ на комментарий Сергей от 10.10.2017
третья связь не получается. коллекции как я понял нельзя связаывать
ответ на комментарий Андрей от 10.10.2017
Что касается коллекций, то в переменную $item попадает не коллекция, а объект модели Comment, из которой вы вполне можете получить, используя связь то, что хотели - $item->user->name вместо того, что в примере ($item->name).
ответ на комментарий Василий от 19.11.2017
получаем сразу все комментарии привязанные к посту.
ответ на комментарий Игорь от 17.02.2018
https://laravel.ru/docs/v5/collections#доступные
ответ на комментарий Сергей от 17.02.2018
А если так - $comments = $post->comments->sortBy('created_at'); ты выводит сначала комментарий с датой 17 Feb 2018 03:34 а потом 17 Feb 2018 03:50 , это тоже не верно.
ответ на комментарий Игорь от 17.02.2018
и увидите, что там нет элементов массива с ключем 'created_at'. Чтобы добраться до 'created_at' нужно перебирать коллекцию например методом map и в функции обратного вызова формировать новый нужный массив.
ответ на комментарий Иван от 16.05.2018