{"id":19139700,"url":"https://github.com/franzose/closuretable","last_synced_at":"2026-01-29T06:27:48.271Z","repository":{"id":7243358,"uuid":"8553481","full_name":"franzose/ClosureTable","owner":"franzose","description":"Adjacency List’ed Closure Table database design pattern implementation for the Laravel framework.","archived":false,"fork":false,"pushed_at":"2023-08-19T17:13:45.000Z","size":553,"stargazers_count":462,"open_issues_count":20,"forks_count":107,"subscribers_count":29,"default_branch":"master","last_synced_at":"2025-05-14T19:46:46.514Z","etag":null,"topics":["closure-table","database","hierarchical-data","laravel","php","tree"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/franzose.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2013-03-04T10:39:39.000Z","updated_at":"2025-04-10T08:00:19.000Z","dependencies_parsed_at":"2024-03-30T10:15:06.469Z","dependency_job_id":null,"html_url":"https://github.com/franzose/ClosureTable","commit_stats":{"total_commits":413,"total_committers":23,"mean_commits":"17.956521739130434","dds":"0.18886198547215494","last_synced_commit":"35356b462ee4d31dcce557c839ee4daeaeb84d2a"},"previous_names":[],"tags_count":28,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/franzose%2FClosureTable","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/franzose%2FClosureTable/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/franzose%2FClosureTable/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/franzose%2FClosureTable/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/franzose","download_url":"https://codeload.github.com/franzose/ClosureTable/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254328385,"owners_count":22052632,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["closure-table","database","hierarchical-data","laravel","php","tree"],"created_at":"2024-11-09T07:14:46.527Z","updated_at":"2026-01-29T06:27:48.265Z","avatar_url":"https://github.com/franzose.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ClosureTable\n[![Build Status](https://travis-ci.org/franzose/ClosureTable.png)](https://travis-ci.org/franzose/ClosureTable)\n[![Latest Release](https://img.shields.io/github/v/release/franzose/ClosureTable)](https://packagist.org/packages/franzose/closure-table)\n[![Total Downloads](https://poser.pugx.org/franzose/closure-table/downloads.png)](https://packagist.org/packages/franzose/closure-table)\n\nThis is a database manipulation package for the Laravel 5.4+ framework. You may want to use it when you need to store and operate hierarchical data in your database. The package is an implementation of a well-known design pattern called [closure table](https://www.slideshare.net/billkarwin/models-for-hierarchical-data). However, in order to simplify and optimize SQL `SELECT` queries, it uses adjacency lists to query direct parent/child relationships.\n\nContents:\n- [Installation](#installation)\n- [Setup](#setup)\n- [Requirements](#requirements)\n- Examples → [List of Scopes](#scopes)\n- Examples → [Parent/Root](#parentroot)\n- Examples → [Ancestors](#ancestors)\n- Examples → [Descendants](#descendants)\n- Examples → [Children](#children)\n- Examples → [Siblings](#siblings)\n- Examples → [Tree](#tree)\n- Examples → [Collection Methods](#collection-methods)\n\n\n## Installation\nIt's strongly recommended to use [Composer](https://getcomposer.org) to install the package:\n```bash\n$ composer require franzose/closure-table\n```\n\nIf you use Laravel 5.5+, the package's service provider is automatically registered for you thanks to the [package auto-discovery](https://laravel.com/docs/7.x/packages#package-discovery) feature. Otherwise, you have to manually add it to your `config/app.php`:\n```php\n\u003c?php\n\nreturn [\n    'providers' =\u003e [\n        Franzose\\ClosureTable\\ClosureTableServiceProvider::class\n    ]\n];\n```\n\n## Setup\nIn a basic scenario, you can simply run the following command:\n```bash\n$ php artisan closuretable:make Node\n```\nWhere `Node` is the name of the entity model. This is what you get from running the above:\u003cbr\u003e\n1. Two models in the `app` directory: `App\\Node` and `App\\NodeClosure`\u003cbr\u003e\n2. A new migration in the `database/migrations` directory\n\nAs you can see, the command requires a single argument, name of the entity model. However, it accepts several options in order to provide some sort of customization:\n Option          | Alias | Meaning \n ----------------| ------| -------\n namespace       | ns    | Custom namespace for generated models. Keep in mind that the given namespace will override  model namespaces: `php artisan closuretable:make Foo\\\\Node --namespace=Qux --closure=Bar\\\\NodeTree` will generate `Qux\\Node` and `Qux\\NodeTree` models.\n entity-table    | et    | Database table name for the entity model       \n closure         | c     | Class name for the closure model\n closure-table   | ct    | Database table name for the closure model\n models-path     | mdl   | Directory in which to put generated models\n migrations-path | mgr   | Directory in which to put generated migrations\n use-innodb      | i     | This flag will tell the generator to set database engine to InnoDB. Useful only if you use MySQL\n\n## Requirements\nYou have to keep in mind that, by design of this package, the models/tables have a required minimum of attributes/columns:\n\u003ctable\u003e\n\u003ctr\u003e\n\u003cth colspan=\"3\"\u003eEntity\u003c/th\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003cth\u003eAttribute/Column\u003c/th\u003e\n\u003cth\u003eCustomized by\u003c/th\u003e\n\u003cth\u003eMeaning\u003c/th\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eparent_id\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003eEntity::getParentIdColumn()\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eID of the node's immediate parent, simplifies queries for immediate parent/child nodes.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eposition\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003eEntity::getPositionColumn()\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eNode position, allows to order nodes of the same depth level\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003cth colspan=\"3\"\u003eClosureTable\u003c/th\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003cth\u003eAttribute/Column\u003c/th\u003e\n\u003cth\u003eCustomized by\u003c/th\u003e\n\u003cth\u003eMeaning\u003c/th\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eid\u003c/td\u003e\n\u003ctd\u003e\u003c/td\u003e\n\u003ctd\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eancestor\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003eClosureTable::getAncestorColumn()\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eParent (self, immediate, distant) node ID\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003edescendant\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003eClosureTable::getDescendantColumn()\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eChild (self, immediate, distant) node ID\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003edepth\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003eClosureTable::getDepthColumn()\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eCurrent nesting level, 0+\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\n## Examples\nIn the examples, let's assume that we've set up a `Node` model which extends the `Franzose\\ClosureTable\\Models\\Entity` model.\n\n### Scopes\nSince ClosureTable 6, a lot of query scopes have become available in the Entity model:\n\n```php\nancestors()\nancestorsOf($id)\nancestorsWithSelf()\nancestorsWithSelfOf($id)\ndescendants()\ndescendantsOf($id)\ndescendantsWithSelf()\ndescendantsWithSelfOf($id)\nchildNode()\nchildNodeOf($id)\nchildAt(int $position)\nchildOf($id, int $position)\nfirstChild()\nfirstChildOf($id)\nlastChild()\nlastChildOf($id)\nchildrenRange(int $from, int $to = null)\nchildrenRangeOf($id, int $from, int $to = null)\nsibling()\nsiblingOf($id)\nsiblings()\nsiblingsOf($id)\nneighbors()\nneighborsOf($id)\nsiblingAt(int $position)\nsiblingOfAt($id, int $position)\nfirstSibling()\nfirstSiblingOf($id)\nlastSibling()\nlastSiblingOf($id)\nprevSibling()\nprevSiblingOf($id)\nprevSiblings()\nprevSiblingsOf($id)\nnextSibling()\nnextSiblingOf($id)\nnextSiblings()\nnextSiblingsOf($id)\nsiblingsRange(int $from, int $to = null)\nsiblingsRangeOf($id, int $from, int $to = null)\n```\n\nYou can learn how to use query scopes from the [Laravel documentation](https://laravel.com/docs/7.x/eloquent#query-scopes).\n\n### Parent/Root\n```php\n\u003c?php\n$nodes = [\n    new Node(['id' =\u003e 1]),\n    new Node(['id' =\u003e 2]),\n    new Node(['id' =\u003e 3]),\n    new Node(['id' =\u003e 4, 'parent_id' =\u003e 1])\n];\n\nforeach ($nodes as $node) {\n    $node-\u003esave();\n}\n\nNode::getRoots()-\u003epluck('id')-\u003etoArray(); // [1, 2, 3]\nNode::find(1)-\u003eisRoot(); // true\nNode::find(1)-\u003eisParent(); // true\nNode::find(4)-\u003eisRoot(); // false\nNode::find(4)-\u003eisParent(); // false\n\n// make node 4 a root at the fourth position (1 =\u003e 0, 2 =\u003e 1, 3 =\u003e 2, 4 =\u003e 3)\n$node = Node::find(4)-\u003emakeRoot(3);\n$node-\u003eisRoot(); // true\n$node-\u003eposition; // 3\n\nNode::find(4)-\u003emoveTo(0, Node::find(2)); // same as Node::find(4)-\u003emoveTo(0, 2);\nNode::find(2)-\u003egetChildren()-\u003epluck('id')-\u003etoArray(); // [4]\n\n// move a node within the same parent to reorder siblings\nNode::find(15)-\u003emoveTo(1, 9);\n```\n\n### Ancestors\n```php\n\u003c?php\n$nodes = [\n    new Node(['id' =\u003e 1]),\n    new Node(['id' =\u003e 2, 'parent_id' =\u003e 1]),\n    new Node(['id' =\u003e 3, 'parent_id' =\u003e 2]),\n    new Node(['id' =\u003e 4, 'parent_id' =\u003e 3])\n];\n\nforeach ($nodes as $node) {\n    $node-\u003esave();\n}\n\nNode::find(4)-\u003egetAncestors()-\u003epluck('id')-\u003etoArray(); // [1, 2, 3]\nNode::find(4)-\u003ecountAncestors(); // 3\nNode::find(4)-\u003ehasAncestors(); // true\nNode::find(4)-\u003eancestors()-\u003ewhere('id', '\u003e', 1)-\u003eget()-\u003epluck('id')-\u003etoArray(); // [2, 3];\nNode::find(4)-\u003eancestorsWithSelf()-\u003ewhere('id', '\u003e', 1)-\u003eget()-\u003epluck('id')-\u003etoArray(); // [2, 3, 4];\nNode::ancestorsOf(4)-\u003ewhere('id', '\u003e', 1)-\u003eget()-\u003epluck('id')-\u003etoArray(); // [2, 3];\nNode::ancestorsWithSelfOf(4)-\u003ewhere('id', '\u003e', 1)-\u003eget()-\u003epluck('id')-\u003etoArray(); // [2, 3, 4];\n```\n\nThere are several methods that have been deprecated since ClosureTable 6:\n\n```diff\n-Node::find(4)-\u003egetAncestorsTree();\n+Node::find(4)-\u003egetAncestors()-\u003etoTree();\n\n-Node::find(4)-\u003egetAncestorsWhere('id', '\u003e', 1);\n+Node::find(4)-\u003eancestors()-\u003ewhere('id', '\u003e', 1)-\u003eget();\n```\n\n### Descendants\n```php\n\u003c?php\n$nodes = [\n    new Node(['id' =\u003e 1]),\n    new Node(['id' =\u003e 2, 'parent_id' =\u003e 1]),\n    new Node(['id' =\u003e 3, 'parent_id' =\u003e 2]),\n    new Node(['id' =\u003e 4, 'parent_id' =\u003e 3])\n];\n\nforeach ($nodes as $node) {\n    $node-\u003esave();\n}\n\nNode::find(1)-\u003egetDescendants()-\u003epluck('id')-\u003etoArray(); // [2, 3, 4]\nNode::find(1)-\u003ecountDescendants(); // 3\nNode::find(1)-\u003ehasDescendants(); // true\nNode::find(1)-\u003edescendants()-\u003ewhere('id', '\u003c', 4)-\u003eget()-\u003epluck('id')-\u003etoArray(); // [2, 3];\nNode::find(1)-\u003edescendantsWithSelf()-\u003ewhere('id', '\u003c', 4)-\u003eget()-\u003epluck('id')-\u003etoArray(); // [1, 2, 3];\nNode::descendantsOf(1)-\u003ewhere('id', '\u003c', 4)-\u003eget()-\u003epluck('id')-\u003etoArray(); // [2, 3];\nNode::descendantsWithSelfOf(1)-\u003ewhere('id', '\u003c', 4)-\u003eget()-\u003epluck('id')-\u003etoArray(); // [1, 2, 3];\n```\n\nThere are several methods that have been deprecated since ClosureTable 6:\n\n```diff\n-Node::find(4)-\u003egetDescendantsTree();\n+Node::find(4)-\u003egetDescendants()-\u003etoTree();\n\n-Node::find(4)-\u003egetDescendantsWhere('foo', '=', 'bar');\n+Node::find(4)-\u003edescendants()-\u003ewhere('foo', '=', 'bar')-\u003eget();\n```\n\n### Children\n```php\n\u003c?php\n$nodes = [\n    new Node(['id' =\u003e 1]),\n    new Node(['id' =\u003e 2, 'parent_id' =\u003e 1]),\n    new Node(['id' =\u003e 3, 'parent_id' =\u003e 1]),\n    new Node(['id' =\u003e 4, 'parent_id' =\u003e 1]),\n    new Node(['id' =\u003e 5, 'parent_id' =\u003e 1]),\n    new Node(['id' =\u003e 6, 'parent_id' =\u003e 2]),\n    new Node(['id' =\u003e 7, 'parent_id' =\u003e 3])\n];\n\nforeach ($nodes as $node) {\n    $node-\u003esave();\n}\n\nNode::find(1)-\u003egetChildren()-\u003epluck('id')-\u003etoArray(); // [2, 3, 4, 5]\nNode::find(1)-\u003ecountChildren(); // 3\nNode::find(1)-\u003ehasChildren(); // true\n\n// get child at the second position (positions start from zero)\nNode::find(1)-\u003egetChildAt(1)-\u003eid; // 3\n\nNode::find(1)-\u003egetChildrenRange(1)-\u003epluck('id')-\u003etoArray(); // [3, 4, 5]\nNode::find(1)-\u003egetChildrenRange(0, 2)-\u003epluck('id')-\u003etoArray(); // [2, 3, 4]\n\nNode::find(1)-\u003egetFirstChild()-\u003eid; // 2\nNode::find(1)-\u003egetLastChild()-\u003eid; // 5\n\nNode::find(6)-\u003ecountChildren(); // 0\nNode::find(6)-\u003ehasChildren(); // false\n\nNode::find(6)-\u003eaddChild(new Node(['id' =\u003e 7]));\n\nNode::find(1)-\u003eaddChildren([new Node(['id' =\u003e 8]), new Node(['id' =\u003e 9])], 2);\nNode::find(1)-\u003egetChildren()-\u003epluck('position', 'id')-\u003etoArray(); // [2 =\u003e 0, 3 =\u003e 1, 8 =\u003e 2, 9 =\u003e 3, 4 =\u003e 4, 5 =\u003e 5]\n\n// remove child by its position\nNode::find(1)-\u003eremoveChild(2);\nNode::find(1)-\u003egetChildren()-\u003epluck('position', 'id')-\u003etoArray(); // [2 =\u003e 0, 3 =\u003e 1, 9 =\u003e 2, 4 =\u003e 3, 5 =\u003e 4]\n\nNode::find(1)-\u003eremoveChildren(2, 4);\nNode::find(1)-\u003egetChildren()-\u003epluck('position', 'id')-\u003etoArray(); // [2 =\u003e 0, 3 =\u003e 1]\n```\n\n### Siblings\n```php\n\u003c?php\n$nodes = [\n    new Node(['id' =\u003e 1]),\n    new Node(['id' =\u003e 2, 'parent_id' =\u003e 1]),\n    new Node(['id' =\u003e 3, 'parent_id' =\u003e 1]),\n    new Node(['id' =\u003e 4, 'parent_id' =\u003e 1]),\n    new Node(['id' =\u003e 5, 'parent_id' =\u003e 1]),\n    new Node(['id' =\u003e 6, 'parent_id' =\u003e 1]),\n    new Node(['id' =\u003e 7, 'parent_id' =\u003e 1])\n];\n\nforeach ($nodes as $node) {\n    $node-\u003esave();\n}\n\nNode::find(7)-\u003egetFirstSibling()-\u003eid; // 2\nNode::find(7)-\u003egetSiblingAt(0); // 2\nNode::find(2)-\u003egetLastSibling(); // 7\nNode::find(7)-\u003egetPrevSibling()-\u003eid; // 6\nNode::find(7)-\u003egetPrevSiblings()-\u003epluck('id')-\u003etoArray(); // [2, 3, 4, 5, 6]\nNode::find(7)-\u003ecountPrevSiblings(); // 5\nNode::find(7)-\u003ehasPrevSiblings(); // true\n\nNode::find(2)-\u003egetNextSibling()-\u003eid; // 3\nNode::find(2)-\u003egetNextSiblings()-\u003epluck('id')-\u003etoArray(); // [3, 4, 5, 6, 7]\nNode::find(2)-\u003ecountNextSiblings(); // 5\nNode::find(2)-\u003ehasNextSiblings(); // true\n\nNode::find(3)-\u003egetSiblings()-\u003epluck('id')-\u003etoArray(); // [2, 4, 5, 6, 7]\nNode::find(3)-\u003egetNeighbors()-\u003epluck('id')-\u003etoArray(); // [2, 4]\nNode::find(3)-\u003ecountSiblings(); // 5\nNode::find(3)-\u003ehasSiblings(); // true\n\nNode::find(2)-\u003egetSiblingsRange(2)-\u003epluck('id')-\u003etoArray(); // [4, 5, 6, 7]\nNode::find(2)-\u003egetSiblingsRange(2, 4)-\u003epluck('id')-\u003etoArray(); // [4, 5, 6]\n\nNode::find(4)-\u003eaddSibling(new Node(['id' =\u003e 8]));\nNode::find(4)-\u003egetNextSiblings()-\u003epluck('id')-\u003etoArray(); // [5, 6, 7, 8]\n\nNode::find(4)-\u003eaddSibling(new Node(['id' =\u003e 9]), 1);\nNode::find(1)-\u003egetChildren()-\u003epluck('position', 'id')-\u003etoArray();\n// [2 =\u003e 0, 9 =\u003e 1, 3 =\u003e 2, 4 =\u003e 3, 5 =\u003e 4, 6 =\u003e 5, 7 =\u003e 6, 8 =\u003e 7]\n\nNode::find(8)-\u003eaddSiblings([new Node(['id' =\u003e 10]), new Node(['id' =\u003e 11])]);\nNode::find(1)-\u003egetChildren()-\u003epluck('position', 'id')-\u003etoArray();\n// [2 =\u003e 0, 9 =\u003e 1, 3 =\u003e 2, 4 =\u003e 3, 5 =\u003e 4, 6 =\u003e 5, 7 =\u003e 6, 8 =\u003e 7, 10 =\u003e 8, 11 =\u003e 9]\n\nNode::find(2)-\u003eaddSiblings([new Node(['id' =\u003e 12]), new Node(['id' =\u003e 13])], 3);\nNode::find(1)-\u003egetChildren()-\u003epluck('position', 'id')-\u003etoArray();\n// [2 =\u003e 0, 9 =\u003e 1, 3 =\u003e 2, 12 =\u003e 3, 13 =\u003e 4, 4 =\u003e 5, 5 =\u003e 6, 6 =\u003e 7, 7 =\u003e 8, 8 =\u003e 9, 10 =\u003e 10, 11 =\u003e 11]\n```\n\n### Tree\n```php\n\u003c?php\nNode::createFromArray([\n    'id' =\u003e 1,\n    'children' =\u003e [\n        [\n            'id' =\u003e 2,\n            'children' =\u003e [\n                [\n                    'id' =\u003e 3,\n                    'children' =\u003e [\n                        [\n                            'id' =\u003e 4,\n                            'children' =\u003e [\n                                [\n                                    'id' =\u003e 5,\n                                    'children' =\u003e [\n                                        [\n                                            'id' =\u003e 6,\n                                        ]\n                                    ]\n                                ]\n                            ]\n                        ]\n                    ]\n                ]\n            ]\n        ]\n    ]\n]);\n\nNode::find(4)-\u003edeleteSubtree();\nNode::find(1)-\u003egetDescendants()-\u003epluck('id')-\u003etoArray(); // [2, 3, 4]\n\nNode::find(4)-\u003edeleteSubtree(true);\nNode::find(1)-\u003egetDescendants()-\u003epluck('id')-\u003etoArray(); // [2, 3]\n```\n\nThere are several methods that have been deprecated since ClosureTable 6:\n\n```diff\n-Node::getTree();\n-Node::getTreeByQuery(...);\n-Node::getTreeWhere('foo', '=', 'bar');\n+Node::where('foo', '=', 'bar')-\u003eget()-\u003etoTree();\n```\n\n### Collection methods\nThis library uses an extended collection class which offers some convenient methods:\n\n```php\n\u003c?php\nNode::createFromArray([\n    'id' =\u003e 1,\n    'children' =\u003e [\n        ['id' =\u003e 2],\n        ['id' =\u003e 3],\n        ['id' =\u003e 4],\n        ['id' =\u003e 5],\n        [\n            'id' =\u003e 6,\n            'children' =\u003e [\n                ['id' =\u003e 7],\n                ['id' =\u003e 8],\n            ]\n        ],\n    ]\n]);\n\n/** @var Franzose\\ClosureTable\\Extensions\\Collection $children */\n$children = Node::find(1)-\u003egetChildren();\n$children-\u003egetChildAt(1)-\u003eid; // 3\n$children-\u003egetFirstChild()-\u003eid; // 2\n$children-\u003egetLastChild()-\u003eid; // 6\n$children-\u003egetRange(1)-\u003epluck('id')-\u003etoArray(); // [3, 4, 5, 6]\n$children-\u003egetRange(1, 3)-\u003epluck('id')-\u003etoArray(); // [3, 4, 5]\n$children-\u003egetNeighbors(2)-\u003epluck('id')-\u003etoArray(); // [3, 5]\n$children-\u003egetPrevSiblings(2)-\u003epluck('id')-\u003etoArray(); // [2, 3]\n$children-\u003egetNextSiblings(2)-\u003epluck('id')-\u003etoArray(); // [5, 6]\n$children-\u003egetChildrenOf(4)-\u003epluck('id')-\u003etoArray(); // [7, 8]\n$children-\u003ehasChildren(4); // true\n$tree = $children-\u003etoTree();\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffranzose%2Fclosuretable","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffranzose%2Fclosuretable","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffranzose%2Fclosuretable/lists"}