PHPackages                             drandin/closure-table-comments - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. drandin/closure-table-comments

ActiveLibrary[Database &amp; ORM](/categories/database)

drandin/closure-table-comments
==============================

A system for managing hierarchical tree comments. Storing hierarchical tree structures in a database using the "Closure Table" method combined with "Adjacency List"

0.1(5y ago)24455[1 issues](https://github.com/drandin/closure-table-comments/issues)MITPHPPHP ^7.3

Since Aug 20Pushed 5y ago4 watchersCompare

[ Source](https://github.com/drandin/closure-table-comments)[ Packagist](https://packagist.org/packages/drandin/closure-table-comments)[ RSS](/packages/drandin-closure-table-comments/feed)WikiDiscussions master Synced 5d ago

READMEChangelogDependenciesVersions (2)Used By (0)

Commentator
-----------

[](#commentator)

Система управления иерархическими древовидными комментариями для **Laravel**.

Древовидная иерархия хранится в реляционной базе данных. Для получения узлов (элементов) дерева не используются SQL-запросы с рекурсией.

Для организации структуры комментариев применяется метод «Closure Table» совмещённым с «Adjacency List».

##### Схема связей элементов дерева «Closure Table»

[](#схема-связей-элементов-дерева-closure-table)

[![Схема связей элементов дерева «Closure Table»](https://camo.githubusercontent.com/84e718040ea62c7f27ee1bc9d6f748b6d9a2fa006649bb0527e1c618684ca2f0/68747470733a2f2f6873746f2e6f72672f66696c65732f3036612f6636302f6663302f30366166363066633065303634336238623135363133666137623365633432322e676966)](https://camo.githubusercontent.com/84e718040ea62c7f27ee1bc9d6f748b6d9a2fa006649bb0527e1c618684ca2f0/68747470733a2f2f6873746f2e6f72672f66696c65732f3036612f6636302f6663302f30366166363066633065303634336238623135363133666137623365633432322e676966)

Метод хранения «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**, то комментарий не будет принадлежать какому-либо автору. Такие комментарии можно считать анонимными.

#### 1. Создание корневого нового комментария.

[](#1-создание-корневого-нового-комментария)

Предположим, у нас есть сущность «Статья» с уникальным номером **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**.

#### 2. Ответ на комментарий, который был написан ранее.

[](#2-ответ-на-комментарий-который-был-написан-ранее)

Предположим, у нас есть сущность «Статья» с уникальным номером **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**) нового комментария будет на единицу больше, чем уровень родительского комментария.

#### 3. Редактирование текста комментария.

[](#3-редактирование-текста-комментария)

Для внесения изменения в текст комментарий нужно знать его уникальный идентификатор.

```
  use Drandin\ClosureTableComments\ClosureTableService;
  use Drandin\ClosureTableComments\Commentator;

  $commentator = new Commentator(new ClosureTableService());

  $comment = "Отличная статья. Благодарю автора.";

  $res = $commentator->editComment(1, $comment);
```

Если изменить комментарий удалось, то **$res** будет иметь значение **true**.

#### 4. Проверка существования комментария

[](#4-проверка-существования-комментария)

Вы можете узнать существует ли комментарий (узел в иерархии) по его уникальному идентификатору.

```
  use Drandin\ClosureTableComments\ClosureTableService;
  use Drandin\ClosureTableComments\Commentator;

  $commentator = new Commentator(new ClosureTableService());

  $res = $commentator->has(2);
```

Если комментарий с уникальным идентификатором в древовидной структуре есть, то переменная **$res** будет равняться **true**.

#### 5. Получение комментария (узла в иерархии) по уникальному идентификатору

[](#5-получение-комментария-узла-в-иерархии-по-уникальному-идентификатору)

Предположим, что мы хотим получить объект **Node** по уникальному идентификатору, который равен **2**.

```
  use Drandin\ClosureTableComments\ClosureTableService;
  use Drandin\ClosureTableComments\Commentator;

  $commentator = new Commentator(new ClosureTableService());

  $node = $commentator->getNode(2);
```

В случае, если комментарий с уникальным идентификатором **2** существует, метод **getNode** вернёт объект **Node**. Объект **Node** будет содержать информацию об узле иерархии комментариев.

#### 6. Получение отсортированной ветки комментариев

[](#6-получение-отсортированной-ветки-комментариев)

Предположим у нас есть статья с уникальным идентификатором **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**.

#### 7. Получение массива древовидной иерархии

[](#7-получение-массива-древовидной-иерархии)

Получить массив дерева комментариев можно при помощи метода **getTreeBranchArray**.

```
  use Drandin\ClosureTableComments\ClosureTableService;
  use Drandin\ClosureTableComments\Commentator;

  $commentator = new Commentator(new ClosureTableService());

  $tree = $commentator
               ->setSubjectId(5636)
               ->getTreeBranchArray();
```

Если необходимо получить ветку комментариев, которая должна начинаться с определённого узла, то в метод **getTreeBranchArray** следует передать идентификатор этого узла иерархии.

#### 8. Получение идентификаторов ветки комментариев

[](#8-получение-идентификаторов-ветки-комментариев)

Предположим, мы хотим получить массив уникальных идентификаторов всех узлов ветки комментариев начиная с узла с идентификатором **23**.

```
  use Drandin\ClosureTableComments\ClosureTableService;
  use Drandin\ClosureTableComments\Commentator;

  $commentator = new Commentator(new ClosureTableService());

  $ids = $commentator->getBranchIds(23);
```

#### 9. Получение уровня узла по уникальному идентификатору

[](#9-получение-уровня-узла-по-уникальному-идентификатору)

Предположим, нам нужно узнать уровень узла **23** в иерархии, но извлекать объект Node методом ***getNode*** мы хотим, так как нам нужна лишь информация об уровне. Чтобы это сделать следует воспользоваться методом ***getLevel***.

```
  use Drandin\ClosureTableComments\ClosureTableService;
  use Drandin\ClosureTableComments\Commentator;

  $commentator = new Commentator(new ClosureTableService());

  $level = $commentator->getLevel(23);
```

#### 10. Удаление узла иерархии (листа) или ветки древовидной иерархии комментариев

[](#10-удаление-узла-иерархии-листа-или-ветки-древовидной-иерархии-комментариев)

Если нам нужно удалить ветку комментариев или только один последний комментарий в иерархии (лист в дереве комментариев), то это можно сделать при помощи метода **delete**.

Метод **delete** получает уникальный идентификатор узла и удаляет все комментарии, начиная с узла, идентификатор которого был передан этому методу.

В примере ниже мы удаляем узел **64** и всех его потомков, если они есть.

```
  use Drandin\ClosureTableComments\ClosureTableService;
  use Drandin\ClosureTableComments\Commentator;

  $commentator = new Commentator(new ClosureTableService());

  $res = $commentator->delete(64);
```

Будьте осторожны, удалённые комментарии восстановить невозможно.

Лицензия (License)
------------------

[](#лицензия-license)

[MIT license](LICENSE)

###  Health Score

24

—

LowBetter than 32% of packages

Maintenance19

Infrequent updates — may be unmaintained

Popularity19

Limited adoption so far

Community11

Small or concentrated contributor base

Maturity39

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

2095d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/8179885?v=4)[Igor Drandin](/maintainers/drandin)[@drandin](https://github.com/drandin)

---

Top Contributors

[![drandin](https://avatars.githubusercontent.com/u/8179885?v=4)](https://github.com/drandin "drandin (15 commits)")

---

Tags

laraveltreeclosure tableadjacency listhierarchical

### Embed Badge

![Health badge](/badges/drandin-closure-table-comments/health.svg)

```
[![Health](https://phpackages.com/badges/drandin-closure-table-comments/health.svg)](https://phpackages.com/packages/drandin-closure-table-comments)
```

###  Alternatives

[franzose/closure-table

Adjacency List’ed Closure Table database design pattern implementation for Laravel

4641.1M3](/packages/franzose-closure-table)[typicms/nestablecollection

A Laravel Package that extends Collection to handle unlimited nested items following adjacency list model.

88327.2k20](/packages/typicms-nestablecollection)[baril/bonsai

An implementation of the Closure Tables pattern for Eloquent.

3593.5k](/packages/baril-bonsai)[jiaxincui/closure-table

A closure table tree package for laravel eloquent

1138.4k](/packages/jiaxincui-closure-table)[nevadskiy/laravel-tree

Tree-like structure for Eloquent models.

6693.9k4](/packages/nevadskiy-laravel-tree)[umbrellio/laravel-ltree

Extension LTree (Postgres) for Laravel

34111.6k](/packages/umbrellio-laravel-ltree)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
