Система управления иерархическими древовидными комментариями для Laravel.
Древовидная иерархия хранится в реляционной базе данных. Для получения узлов (элементов) дерева не используются SQL-запросы с рекурсией.
Для организации структуры комментариев применяется метод «Closure Table» совмещённым с «Adjacency List».
Метод хранения «Closure Table» обладает большим количеством преимуществ, не позволяет извлечь из базы данных узлы ветви иерархии и эффективно построить корректно отсортированное дерево. Для преодоления этого ограничения, метод «Closure Table» совмещён с «Adjacency List».
«Adjacency List» или список смежности — один из способов представления графа в виде коллекции списков вершин. Каждой вершине графа соответствует список, состоящий из «соседей» этой вершины.
composer require drandin/closure-table-comments
Добавить в файл конфигурации приложения config/app.php сервис-провайдер. Строку указанную ниже следует внести в массив 'providers'.
\Drandin\ClosureTableComments\ClosureTableServiceProvider::class,
Выполнить в консоли команду, которая скопирует файл конфигурации closure-table-comments.php в каталог config вашего приложения:
php artisan vendor:publish --tag=config
(!) После выполнения данной команды, в файле config/closure-table-comments.php вы можете изменить название базы данных и таблиц. Если это необходимо, то скорректируйте параметры конфигурации, прежде чем двигаться дальше.
Выполнить в консоли команду:
php artisan config:cache
Выполнить в консоли команду, которая запустит выполнение миграций:
php artisan migrate
В результате будут созданы 2 таблицы в базе данных.
Каждый комментарий может относиться к определённому предмету и иметь ссылку на автора, который его написал. Например, если требуется организовать обсуждение статьи на новостном сайте, то уникальный целочисленный идентификатор сущности «Статья» следует использовать в качестве указания на принадлежность комментариев к обсуждаемому предмету, а целочисленный идентификатор пользователя — будет указывать на автора комментария.
subject_id — целочисленный идентификатор сущности «Статья». Может иметь значение NULL. Если subject_id равняется NULL, то комментарий не будет относиться к какому-либо предмету.
user_id — целочисленный идентификатор сущности «Автор статьи». Может иметь значение NULL. Если user_id равняется NULL, то комментарий не будет принадлежать какому-либо автору. Такие комментарии можно считать анонимными.
Предположим, у нас есть сущность «Статья» с уникальным номером 5636 и пользователь с уникальным идентификатором 7 решил оставить комментарий к статье.
use Drandin\ClosureTableComments\ClosureTableService;
use Drandin\ClosureTableComments\Commentator;
$commentator = new Commentator(new ClosureTableService());
$comment = "Отличная статья. Спасибо за полезный материал.";
$id = $commentator
->setSubjectId(5636)
->addCommentToRoot($comment, 7);
В базе данных будет создан комментарий с уникальным идентификатором $id, он будет принадлежать статье с кодом 5636. Автором комментария будет пользователь с идентификатором 7.
Предположим, у нас есть сущность «Статья» с уникальным номером 5636 и пользователь с уникальным идентификатором 43 решил ответить на ранее написанный другим пользователем комментарий к статье.
Для этого нам нужно знать идентификатор комментария (или уникальный номер узла в древовидной иерархии комментариев Node), на который пользователь хочет написать ответ. Предположим, что уникальный идентификатор комментария равен 1.
use Drandin\ClosureTableComments\ClosureTableService;
use Drandin\ClosureTableComments\Commentator;
$commentator = new Commentator(new ClosureTableService());
$comment = "А вот и нет, в статье есть ошибки.";
$id = $commentator
->setSubjectId(2332)
->replyToComment(1, $comment, 43);
В базе данных будет создан новый комментарий с уникальным идентификатором $id, он будет принадлежать статье с идентификатором 5636. Автором комментария будет пользователь с идентификатором 43.
Здесь важно то, что новый добавленный комментарий будет связан с родительским комментарием (с идентификатором равным 1). Кроме связи, уровень (level) нового комментария будет на единицу больше, чем уровень родительского комментария.
Для внесения изменения в текст комментарий нужно знать его уникальный идентификатор.
use Drandin\ClosureTableComments\ClosureTableService;
use Drandin\ClosureTableComments\Commentator;
$commentator = new Commentator(new ClosureTableService());
$comment = "Отличная статья. Благодарю автора.";
$res = $commentator->editComment(1, $comment);
Если изменить комментарий удалось, то $res будет иметь значение true.
Вы можете узнать существует ли комментарий (узел в иерархии) по его уникальному идентификатору.
use Drandin\ClosureTableComments\ClosureTableService;
use Drandin\ClosureTableComments\Commentator;
$commentator = new Commentator(new ClosureTableService());
$res = $commentator->has(2);
Если комментарий с уникальным идентификатором в древовидной структуре есть, то переменная $res будет равняться true.
Предположим, что мы хотим получить объект Node по уникальному идентификатору, который равен 2.
use Drandin\ClosureTableComments\ClosureTableService;
use Drandin\ClosureTableComments\Commentator;
$commentator = new Commentator(new ClosureTableService());
$node = $commentator->getNode(2);
В случае, если комментарий с уникальным идентификатором 2 существует, метод getNode вернёт объект Node. Объект Node будет содержать информацию об узле иерархии комментариев.
Предположим у нас есть статья с уникальным идентификатором 5636, к этой статье разные пользователи написали комментарии. Некоторые комментаторы начали дискуссию между собой. То есть, у нас образовалась древовидная структура комментариев.
Но дискуссия возможна только если мы сможем корректно визуализировать структуру комментариев. Иначе пользователи просто не смогут общаться между собой. Для этого необходимо сформировать список отсортированных комментариев (узлов древовидной структуры). При этом в данном отсортированном списке узлов должен быть указан уровнь каждого узла, а так же идентификатор узла родителя.
Для решения этой задачи следует использовать метод getTreeBranch
use Drandin\ClosureTableComments\ClosureTableService;
use Drandin\ClosureTableComments\Commentator;
$commentator = new Commentator(new ClosureTableService());
$nodes = $commentator
->setSubjectId(5636)
->getTreeBranch();
В результате мы получим коллекцию объектов Node.
Если нужно получить узлы иерархии комментариев, начиная с узла с определённым идентификатором, то в метод getTreeBranch следует передать значение этого идентификатора.
use Drandin\ClosureTableComments\ClosureTableService;
use Drandin\ClosureTableComments\Commentator;
$commentator = new Commentator(new ClosureTableService());
$nodes = $commentator
->setSubjectId(5636)
->getTreeBranch(2);
Мы получим коллекцию объектов всех узлов иерархии начиная с узла 2.
Получить массив дерева комментариев можно при помощи метода getTreeBranchArray.
use Drandin\ClosureTableComments\ClosureTableService;
use Drandin\ClosureTableComments\Commentator;
$commentator = new Commentator(new ClosureTableService());
$tree = $commentator
->setSubjectId(5636)
->getTreeBranchArray();
Если необходимо получить ветку комментариев, которая должна начинаться с определённого узла, то в метод getTreeBranchArray следует передать идентификатор этого узла иерархии.
Предположим, мы хотим получить массив уникальных идентификаторов всех узлов ветки комментариев начиная с узла с идентификатором 23.
use Drandin\ClosureTableComments\ClosureTableService;
use Drandin\ClosureTableComments\Commentator;
$commentator = new Commentator(new ClosureTableService());
$ids = $commentator->getBranchIds(23);
Предположим, нам нужно узнать уровень узла 23 в иерархии, но извлекать объект Node методом getNode мы хотим, так как нам нужна лишь информация об уровне. Чтобы это сделать следует воспользоваться методом getLevel.
use Drandin\ClosureTableComments\ClosureTableService;
use Drandin\ClosureTableComments\Commentator;
$commentator = new Commentator(new ClosureTableService());
$level = $commentator->getLevel(23);
Если нам нужно удалить ветку комментариев или только один последний комментарий в иерархии (лист в дереве комментариев), то это можно сделать при помощи метода delete.
Метод delete получает уникальный идентификатор узла и удаляет все комментарии, начиная с узла, идентификатор которого был передан этому методу.
В примере ниже мы удаляем узел 64 и всех его потомков, если они есть.
use Drandin\ClosureTableComments\ClosureTableService;
use Drandin\ClosureTableComments\Commentator;
$commentator = new Commentator(new ClosureTableService());
$res = $commentator->delete(64);
Будьте осторожны, удалённые комментарии восстановить невозможно.