PHPackages                             codrasil/closurable - 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. codrasil/closurable

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

codrasil/closurable
===================

Closure Table relational database implementation in PHP Laravel for any hierarchic data

v1.1.1(6y ago)2591[1 issues](https://github.com/codrasil/closurable/issues)MITPHPCI failing

Since Jul 25Pushed 6y ago2 watchersCompare

[ Source](https://github.com/codrasil/closurable)[ Packagist](https://packagist.org/packages/codrasil/closurable)[ RSS](/packages/codrasil-closurable/feed)WikiDiscussions master Synced today

READMEChangelogDependencies (2)Versions (4)Used By (0)

Closurable
==========

[](#closurable)

[![Latest Stable Version](https://camo.githubusercontent.com/01ccb895a83711873e396613f4e3920e9e41a80b645e71010f49129e914cb0a5/68747470733a2f2f706f7365722e707567782e6f72672f636f64726173696c2f636c6f73757261626c652f762f737461626c65)](https://packagist.org/packages/codrasil/closurable)[![Total Downloads](https://camo.githubusercontent.com/bbd8c4c6b44d3aac9f7eacf9ef2d0e9b26c3dff827d44af6ea137714da474fee/68747470733a2f2f706f7365722e707567782e6f72672f636f64726173696c2f636c6f73757261626c652f646f776e6c6f616473)](https://packagist.org/packages/codrasil/closurable)[![Latest Unstable Version](https://camo.githubusercontent.com/22f4a9cb39b1db9fcc962821da47c55b357762537c0ced4ba7bfd2e264f5f00e/68747470733a2f2f706f7365722e707567782e6f72672f636f64726173696c2f636c6f73757261626c652f762f756e737461626c65)](https://packagist.org/packages/codrasil/closurable)[![License](https://camo.githubusercontent.com/52cf8b92aa27ce22af18e2fea80e0bcc8bb9671aadea9ef57c7d6fb6c6790525/68747470733a2f2f706f7365722e707567782e6f72672f636f64726173696c2f636c6f73757261626c652f6c6963656e7365)](https://packagist.org/packages/codrasil/closurable)

---

[![](./docs/closurables.tree.svg)](./docs/closurables.tree.svg)

Closure Table relational database implementation in PHP for any hierarchical data. ### Requirements

[](#requirements)

- `PHP`: `^7.x`
- `MySQL`: any version should be fine.

---

### Installation

[](#installation)

This package is originally built for [Laravel](https://github.com/laravel/laravel), but can also be used in any PHP project.

[Read more about integration in the docs.](docs/integration.md)

**via composer:**

```
composer require codrasil/closurable
```

### Publishing Configuration

[](#publishing-configuration)

Pass in the artisan command the package's service provider:

```
php artisan vendor:publish --provider="Codrasil\Closurable\NestableServiceProvider"
```

---

### Setup

[](#setup)

#### Generating Migration File

[](#generating-migration-file)

First, run the console command to generate a nested migration table.

Format:

```
make:closurable [options] [--]
```

Example:

*We will be using the `users` model to generate a nested relationship of users.*

```
php artisan make:closurable users
```

The command accepts an argument of `referenced table`. This will be the table to be "closured".

It will generate a table named `userstree` that comes pre-populated with the necessary columns.

The generated file should look something like below:

```
Schema::create('userstree', function (Blueprint $table) {
    $table->unsignedBigInteger('ancestor_id')->index();
    $table->unsignedBigInteger('descendant_id')->index();
    $table->unsignedBigInteger('depth')->index()->default(0);
    $table->unsignedBigInteger('root')->index()->default(0);
    $table->unique(['ancestor_id', 'descendant_id']);
    $table->index(['ancestor_id', 'descendant_id', 'depth']);
    $table->index(['descendant_id', 'depth']);
    $table->index(['depth', 'root']);
    $table->foreign('ancestor_id')
          ->references('id')
          ->on('users')
          ->onDelete('cascade')
          ->onUpdate('cascade');
    $table->foreign('descendant_id')
          ->references('id')
          ->on('users')
          ->onDelete('cascade')
          ->onUpdate('cascade');
});
```

**Note** that you should generate the migration file of the **referenced table** yourself before running the command (in the above example, you should generate the migration for the `users` table yourself).

**Note** to change the table name of the closure table, pass in an option `--table` or `--create`:

```
php artisan make:closurable users --table=familytree
```

Run `php artisan make:closurable --help` for more information on configuring the command.

#### Model usage

[](#model-usage)

Next, use either of the two options on the model to be closure nested.

*Following our example above, the `User` model should either implement:*

- the trait, `Closurable`:

    ```
    use Codrasil\Closurable\Closurable;

    class User extends Authenticatable
    {
        use Closurable;
    }

    ```

    or
- via extending the abstract class, `Codrasil\Closurable\Model`, instead of the default Illuminate Model class:

    ```
    use Codrasil\Closurable\Model;

    class User extends Model
    {
       // Of course, you will need to reimplement the Authenticatable traits
       // to the User model if you ARE going to nest the User model.
    }

    ```

---

### Usage

[](#usage)

#### Saving a Branch Node

[](#saving-a-branch-node)

Let's say we have the following data on our `users` table:

IDName1Henry Walton Jones, Sr.2Indiana Jones3Susie Jones4Henry Walton Jones IIIAnd we need the following relationship:

[![](./docs/closurables.sample2.svg)](./docs/closurables.sample2.svg)

To save the relationships described above, we need to use the `closurables()` from the User model to access the `attach(Model $model)` method.

```
$parent = User::find(1); // Jones, Sr.
$junior = User::find(2); // Indy
$parent->closurables()->attach($junior);

...

$child = User::find(3); // Susie
$parent->closurables()->attach($child);

...
$child = User::find(4); // Jones III
$junior->closurables()->attach($child);
```

The relationship will be saved in the `familytree` table as:

ancestor\_iddescendant\_iddepthroot11011210131014202200241033004400Visual representation:

[![](./docs/closurables.sample1.svg)](./docs/closurables.sample1.svg)

---

##### Displaying Root Nodes

[](#displaying-root-nodes)

- **Root**

    To display resources without parents, use the `roots` scope:

    ```
    $roots = MyModel::roots()->get();
    ```

---

#### Querying for Adjacent Relations

[](#querying-for-adjacent-relations)

By default, sorting is handled via the `sort` column found in the **reference table**. If the `sort` column is unavailable, it will default to `id` or whatever `$this->getKeyName()` will return.

- **Siblings**

    To retrieve all siblings of a child, use `siblings()` method:

    ```
    $child = MyModel::find(2);
    $siblings = $child->siblings(); // or $child->siblings
    ```

    - A helper method `->hasSiblings()` for checking emptiness is available.
    - An accessor method `getSiblingsAttribute` is available.

    ---
- **Next Sibling**

    To display the next sibling in the `$user->children`, use `next()` method:

    ```
    $firstChild = MyModel::find(2);
    $secondChild = $firstChild->next(); // or $firstChild->next
    ```

    - A helper method `->hasNext()` for checking nullness is available.
    - An accessor method `getNextAttribute` is available.

    ---
- **Previous Sibling**

    To display the previous sibling, use `previous()` method:

    ```
    $secondChild = MyModel::find(3);
    $firstChild = $secondChild->previous(); // or $secondChild->previous
    ```

    - A helper method `->hasPrevious()` for checking nullness is available.
    - An accessor method `getPreviousAttribute` is available.

---

#### Querying for Lineal Relations

[](#querying-for-lineal-relations)

- **Parent**

    To retrieve the immediate parent of the child, use `parent()` method:

    ```
    $child = MyModel::find(2);
    $parent = $child->parent(); // or $child->parent
    ```

    - A helper method `->hasParent()` for checking nullness is available.
    - An accessor method `getParentAttribute` is available.
- **Children**

    To display the children nodes of a specific resource, use the `children()` method:

    ```
    $user = User::find(1);
    ```

    ```
    {{-- in a blade file --}}

    @foreach ($user->children() as $child)
      {{ $child->name }}
    @endforeach

    {{-- use @dd($user->children) to see entire collection --}}
    ```

    - A helper method `->hasChildren()` for checking emptiness is available.
    - An accessor method `getChildrenAttribute` is available.

    ---
- **Ancestors**

    To retrieve all parents of the child (and the parent of the child's parent, and so on), use `ancestors()` method:

    ```
    $child = MyModel::find(4);
    $ancestors = $child->ancestors();
    // will output the parent([of the parent]*n) + the child.
    // dd($ancestors) to inspect actual data.
    ```

    - A helper method `->hasAncestors()` for checking emptiness is available.
    - An accessor method `getAncestorsAttribute` is available.

    ---
- **Descendants**

    To retrieve all children of the parent (and the children of the parent's children, and so on), use `descendants()` method:

    ```
    $parent = MyModel::find(2);
    $descendants = $parent->descendants();
    // will output the children([of the children]*n) + the parent.
    // dd($descendants) to inspect actual data.
    ```

    - A helper method `->hasDescendants()` for checking emptiness is available.
    - An accessor method `getDescendantsAttribute` is available.

For more use cases of `adjacent` and `lineal` relations, checkout [Relations](./docs/relations.md) section in the docs.

---

### Documentation &amp; Examples

[](#documentation--examples)

To learn more about the API, visit the [docs](./docs) folder.

For more example implementation, checkout [docs/examples](./docs/examples) folder. The examples page has a variety of use cases like [Commenting System](), [Taxonomic Ranking of the Animal Kingdom](), [Family Trees](), and more.

### License

[](#license)

The library is open-source software licensed under the [MIT license](https://opensource.org/licenses/MIT).

###  Health Score

27

—

LowBetter than 49% of packages

Maintenance10

Infrequent updates — may be unmaintained

Popularity16

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity61

Established project with proven stability

 Bus Factor1

Top contributor holds 66.7% 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

Every ~144 days

Total

3

Last Release

2193d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/15792724?v=4)[John Lioneil Dionisio](/maintainers/lioneil)[@lioneil](https://github.com/lioneil)

---

Top Contributors

[![johnlioneil](https://avatars.githubusercontent.com/u/52232085?v=4)](https://github.com/johnlioneil "johnlioneil (10 commits)")[![lioneil](https://avatars.githubusercontent.com/u/15792724?v=4)](https://github.com/lioneil "lioneil (5 commits)")

---

Tags

closure-tablehierarchymenustree

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/codrasil-closurable/health.svg)

```
[![Health](https://phpackages.com/badges/codrasil-closurable/health.svg)](https://phpackages.com/packages/codrasil-closurable)
```

###  Alternatives

[doctrine/orm

Object-Relational-Mapper for PHP

10.2k285.3M6.2k](/packages/doctrine-orm)[jdorn/sql-formatter

a PHP SQL highlighting library

3.9k115.1M102](/packages/jdorn-sql-formatter)[illuminate/database

The Illuminate Database package.

2.8k52.4M9.3k](/packages/illuminate-database)[mongodb/mongodb

MongoDB driver library

1.6k64.0M543](/packages/mongodb-mongodb)[ramsey/uuid-doctrine

Use ramsey/uuid as a Doctrine field type.

90340.3M209](/packages/ramsey-uuid-doctrine)[reliese/laravel

Reliese Components for Laravel Framework code generation.

1.7k3.4M16](/packages/reliese-laravel)

PHPackages © 2026

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