{"id":19326127,"url":"https://github.com/bartko-s/stefano-tree","last_synced_at":"2025-04-22T20:32:28.574Z","repository":{"id":45307884,"uuid":"10440193","full_name":"bartko-s/stefano-tree","owner":"bartko-s","description":"Framework agnostic Nested Set (MPTT) implementation for PHP","archived":false,"fork":false,"pushed_at":"2023-11-27T20:31:31.000Z","size":563,"stargazers_count":28,"open_issues_count":5,"forks_count":8,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-09-21T13:36:14.351Z","etag":null,"topics":["doctrine-dbal","doctrine2","hierarchical-data","laminas","laminas-db","mptt","nested-set","pdo","tree","tree-structure","zend-framework"],"latest_commit_sha":null,"homepage":"https://bartko-s.github.io/stefano-tree","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bartko-s.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2013-06-02T18:19:45.000Z","updated_at":"2023-12-11T06:56:03.000Z","dependencies_parsed_at":"2023-11-27T21:43:01.026Z","dependency_job_id":null,"html_url":"https://github.com/bartko-s/stefano-tree","commit_stats":{"total_commits":305,"total_committers":6,"mean_commits":"50.833333333333336","dds":0.03934426229508192,"last_synced_commit":"8208ae65f59784065d852618e7a419d3faf23ac2"},"previous_names":[],"tags_count":42,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bartko-s%2Fstefano-tree","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bartko-s%2Fstefano-tree/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bartko-s%2Fstefano-tree/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bartko-s%2Fstefano-tree/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bartko-s","download_url":"https://codeload.github.com/bartko-s/stefano-tree/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250318922,"owners_count":21411011,"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":["doctrine-dbal","doctrine2","hierarchical-data","laminas","laminas-db","mptt","nested-set","pdo","tree","tree-structure","zend-framework"],"created_at":"2024-11-10T02:12:32.547Z","updated_at":"2025-04-22T20:32:28.266Z","avatar_url":"https://github.com/bartko-s.png","language":"PHP","funding_links":["https://www.buymeacoffee.com/bartko","https://paypal.me/stevo4"],"categories":[],"sub_categories":[],"readme":"# Tree\n\n\n[![Latest Stable Version](https://poser.pugx.org/stefano/stefano-tree/version)](https://packagist.org/packages/stefano/stefano-tree)\n[![Build Status](https://app.travis-ci.com/bartko-s/stefano-tree.svg?branch=master)](https://app.travis-ci.com/bartko-s/stefano-tree) \n[![Coverage Status](https://coveralls.io/repos/github/bartko-s/stefano-tree/badge.svg?branch=master)](https://coveralls.io/github/bartko-s/stefano-tree?branch=master)\n[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/bartko-s/stefano-tree/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/bartko-s/stefano-tree/?branch=master) \n[![License](https://poser.pugx.org/stefano/stefano-tree/license)](https://packagist.org/packages/stefano/stefano-tree)\n[![Total Downloads](https://poser.pugx.org/stefano/stefano-tree/downloads)](https://packagist.org/packages/stefano/stefano-tree)\n[![Monthly Downloads](https://poser.pugx.org/stefano/stefano-tree/d/monthly)](https://packagist.org/packages/stefano/stefano-tree)\n\n[![Buy me a coffee](./doc/buy-me-a-coffe.png)](https://www.buymeacoffee.com/bartko)\n\n[![Donate on PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://paypal.me/stevo4)\n\n[Nested Set](https://en.wikipedia.org/wiki/Nested_set_model) implementation for PHP.\n\n[![Live demo](./doc/live-demo.jpg)](https://www.tree.stefanbartko.sk)\n\n## Features\n\n - NestedSet(MPTT - Modified Pre-order Tree Traversal)\n - Support scopes (multiple independent tree in one db table)\n - Rebuild broken tree\n - Tested with MySQL/MariaDB and PostgreSQL but should work with any database vendor which support transaction\n - Supported [PDO](http://php.net/manual/en/intro.pdo.php), [Zend Framework 1](https://framework.zend.com/manual/1.12/en/zend.db.html), [Laminas Db](https://github.com/laminas/laminas-db), [Doctrine 2 DBAL and Doctrine 3 DBAL](http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/). It is easy to implement support for any framework\n - Support nested transaction\n - PHP 7 and PHP 8 support\n\n## Dependencies\n- This library has no external dependencies. Can work with pure PHP.\n\n## Installation\n\nRun following command in terminal\n```\ncomposer require stefano/stefano-tree\n```\n\n## Create Tree Adapter\n\n|        key         |  type  | required | default value | note                                                  |\n| :----------------- | :----: | :------: | :------------ | :---------------------------------------------------- |\n| tableName          | string | yes      |               |                                                       |\n| idColumnName       | string | yes      |               |                                                       |\n| leftColumnName     | string | no       | lft           |                                                       |\n| rightColumnName    | string | no       | rgt           |                                                       |\n| levelColumnName    | string | no       | level         |                                                       |\n| parentIdColumnName | string | no       | parent_id     |                                                       |\n| sequenceName       | string | see note |               | Required for PostgreSQL                               |\n| scopeColumnName    | string | see note |               | If empty scope support is disabled                    |\n| dbSelectBuilder    | callable | no     |               | see Join table example below                          |\n\n\n```\nuse \\StefanoTree\\NestedSet;\n\n$options = array(\n    'tableName'    =\u003e 'tree_traversal',\n    'idColumnName' =\u003e 'tree_traversal_id',\n    // other options\n);\n\n$dbAdapter = pure \\PDO, Zend1 Db Adapter, Laminas Db Adapter, Doctrine DBAL Connection or any class which implements StefanoTree\\NestedSet\\Adapter\\AdapterInterface interface \n\n$tree = new NestedSet($options, $dbAdapter);\n```\n\n- You can join table.\n\n```\n$options = array(\n    'tableName'       =\u003e 'tree_traversal',\n    'idColumnName'    =\u003e 'tree_traversal_id',\n    'dbSelectBuilder' =\u003e function() {\n         // You can use any \"callable\" like function or object\n         // Select must be without where or order part\n         return 'SELECT tree_traversal.*, m.something, ...'\n           .' FROM tree_traversal'\n           .' LEFT JOIN metadata AS m ON tree_traversal.id=m.tree_id';\n     }, \n    // other options\n);\n\n$tree = new NestedSet($options, $dbAdapter);\n```\n\n## API\n\n### Creating nodes\n\n- Create root node\n\n```\nuse StefanoTree\\Exception\\ValidationException;\n\ntry {\n    $data = array(\n        // values\n        // id_column_name =\u003e uuid \n    );\n    \n    // create root node.\n    $rootNodeId = $tree-\u003ecreateRootNode($data);\n    \n    // create root node. Second param \"$scope\" is required only if scope support is enabled.\n    $rootNodeId = $tree-\u003ecreateRootNode($data, $scope);    \n} catch (ValidationException $e) {\n    $errorMessage = $e-\u003egetMessage();\n}    \n```\n\n- Create new node. You can create new node at 4 different locations.\n\n![placements](./doc/placements.png)\n\n```\nuse StefanoTree\\Exception\\ValidationException;\n\ntry {\n    $targetNodeId = 10;\n    \n    $data = array(\n        // values\n        // id_column_name =\u003e uuid \n    );\n\n    $nodeId = $tree-\u003eaddNode($targetNodeId, $data, $tree::PLACEMENT_CHILD_TOP);\n    $nodeId = $tree-\u003eaddNode($targetNodeId, $data, $tree::PLACEMENT_CHILD_BOTTOM);\n    $nodeId = $tree-\u003eaddNode($targetNodeId, $data, $tree::PLACEMENT_TOP);\n    $nodeId = $tree-\u003eaddNode($targetNodeId, $data, $tree::PLACEMENT_BOTTOM);\n} catch (ValidationException $e) {\n    $errorMessage = $e-\u003egetMessage();\n}    \n```\n\n### Update Node\n\n```\nuse StefanoTree\\Exception\\ValidationException;\n\ntry {\n    $targetNodeId = 10;\n    \n    $data = array(\n        // values\n    );\n    \n    $tree-\u003eupdateNode($targetNodeId, $data);\n} catch (ValidationException $e) {\n    $errorMessage = $e-\u003egetMessage();\n}    \n```\n\n### Move node\n\n- You can move node at 4 different locations.\n\n![placements](./doc/placements.png)\n\n```\nuse StefanoTree\\Exception\\ValidationException;\n\ntry {\n    $sourceNodeId = 15;\n    $targetNodeId = 10;\n    \n    $tree-\u003emoveNode($sourceNodeId, $targetNodeId, $tree::PLACEMENT_CHILD_TOP);\n    $tree-\u003emoveNode($sourceNodeId, $targetNodeId, $tree::PLACEMENT_CHILD_BOTTOM);\n    $tree-\u003emoveNode($sourceNodeId, $targetNodeId, $tree::PLACEMENT_TOP);\n    $tree-\u003emoveNode($sourceNodeId, $targetNodeId, $tree::PLACEMENT_BOTTOM);\n} catch (ValidationException $e) {\n    $errorMessage = $e-\u003egetMessage();\n}        \n```\n\n### Delete node or branch\n\n```\nuse StefanoTree\\Exception\\ValidationException;\n\ntry {\n    $nodeId = 15;\n    \n    $tree-\u003edeleteBranch($nodeId);\n} catch (ValidationException $e) {\n    $errorMessage = $e-\u003egetMessage();\n}    \n```\n\n### Getting nodes\n\n- Get descendants\n\n```\n$nodeId = 15;\n\n// all descendants\n$tree-\u003egetDescendantsQueryBuilder()\n     -\u003eget($nodeId);\n     \n// all descendants result as nested array\n$tree-\u003egetDescendantsQueryBuilder()\n     -\u003eget($nodeId, true);\n     \n// only children     \n$tree-\u003egetDescendantsQueryBuilder()\n     -\u003eexcludeFirstNLevel(1)\n     -\u003elevelLimit(1)\n     -\u003eget($nodeId);\n\n// exclude first level($nodeId) from result\n$tree-\u003egetDescendants()\n     -\u003eexcludeFirstNLevel(1)\n     -\u003eget($nodeId);\n\n// exclude first two levels from result\n$tree-\u003egetDescendantsQueryBuilder()\n     -\u003eexcludeFirstNLevel(2)\n     -\u003eget($nodeId);\n\n// return first 4 level\n$tree-\u003egetDescendantsQueryBuilder()\n     -\u003elevelLimit(4)\n     -\u003eget($nodeId);\n\n// exclude branch from  result\n$tree-\u003egetDescendantsQueryBuilder()\n     -\u003eexcludeBranch(22)\n     -\u003eget($nodeId);\n```\n\n- Get Ancestors\n\n```\n$nodeId = 15;\n\n// get all\n$tree-\u003egetAncestorsQueryBuilder()\n     -\u003eget($nodeId);\n     \n// get all as nested array\n$tree-\u003egetAncestorsQueryBuilder()\n     -\u003eget($nodeId, true);\n\n// exclude last node($nodeId) from result\n$tree-\u003egetAncestorsQueryBuilder()\n     -\u003eexcludeLastNLevel(1)\n     -\u003eget($nodeId);\n\n// exclude first two levels from result\n$tree-\u003egetAncestorsQueryBuilder()\n     -\u003eexcludeFirstNLevel(2)\n     -\u003eget($nodeId);\n```\n\n### Validation and Rebuild broken tree\n\n- Check if tree is valid\n\n```\nuse StefanoTree\\Exception\\ValidationException;\n\ntry {\n    $satus = $tree-\u003eisValid($rootNodeId);\n} catch (ValidationException $e) {\n    $errorMessage = $e-\u003egetMessage();\n}\n```\n\n- Rebuild broken tree\n\n```\nuse StefanoTree\\Exception\\ValidationException;\n\ntry {\n    $tree-\u003erebuild($rootNodeId);\n} catch (ValidationException $e) {\n    $errorMessage = $e-\u003egetMessage();\n}\n```\n\n## Contributing\n\nAny contributions are welcome. If you find any issue don't hesitate to open a new issue or send a pull request.\n\n[![Buy me a coffee](./doc/buy-me-a-coffe.png)](https://www.buymeacoffee.com/bartko)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbartko-s%2Fstefano-tree","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbartko-s%2Fstefano-tree","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbartko-s%2Fstefano-tree/lists"}