{"id":15489396,"url":"https://github.com/arodax/doctrine-extensions-tree","last_synced_at":"2026-03-05T22:31:52.827Z","repository":{"id":313497307,"uuid":"1044938108","full_name":"arodax/doctrine-extensions-tree","owner":"arodax","description":null,"archived":false,"fork":false,"pushed_at":"2025-08-26T12:23:23.000Z","size":62,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"1.0","last_synced_at":"2026-01-01T12:20:52.432Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/arodax.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-08-26T12:23:06.000Z","updated_at":"2025-08-26T12:25:02.000Z","dependencies_parsed_at":"2025-09-06T13:38:13.343Z","dependency_job_id":"18bac65d-dbc7-4e3a-9421-969c54e4a1c5","html_url":"https://github.com/arodax/doctrine-extensions-tree","commit_stats":null,"previous_names":["arodax/doctrine-extensions-tree"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/arodax/doctrine-extensions-tree","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arodax%2Fdoctrine-extensions-tree","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arodax%2Fdoctrine-extensions-tree/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arodax%2Fdoctrine-extensions-tree/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arodax%2Fdoctrine-extensions-tree/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/arodax","download_url":"https://codeload.github.com/arodax/doctrine-extensions-tree/tar.gz/refs/heads/1.0","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arodax%2Fdoctrine-extensions-tree/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30152856,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-05T21:15:50.531Z","status":"ssl_error","status_checked_at":"2026-03-05T21:15:11.173Z","response_time":93,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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","orm","symfony","tree"],"created_at":"2024-10-02T07:05:27.444Z","updated_at":"2026-03-05T22:31:52.788Z","avatar_url":"https://github.com/arodax.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Hierarchical Tree extension for Doctrine\n\n![Licence MIT](https://img.shields.io/packagist/l/arodax/doctrine-extensions-tree?style=flat)\n![Build Status](https://api.travis-ci.org/arodax/doctrine-extensions-tree.svg?branch=master\u0026style=flat \"Build Status\")\n![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat\u0026color=orange)\n![downloads total](https://img.shields.io/packagist/dt/doctrine-extensions/tree?color=blue\u0026style=flat)\n\nThis extension allows you to store your data in hierarchicaly in your database using Doctrine ORM.\n\nNote: this code is the hard fork of \n[Atlantic18/DoctrineExtensions](https://github.com/Atlantic18/DoctrineExtensions) 2.4.x branch of the Tree extension only.\n\n## Licence\n\nMIT\n\n## Changelog\n- 3.2.3 Fixed cache item id generator\n- 3.2.2 Automatically cache entity metadata when symfony/cache is installed.\n- 3.2.1 Fixed class and file name mismatch for XML driver\n- 3.2.0 Deprecated TreeRight, TreeLeft, TreeClosure, TreeRoot, TreePath, TreeLevel annotations, use them without \"Tree\" prefix (e.g. Right, Left, Closure ...)\n- 3.2.0 Added native PHP attributes support \n- 3.1.0 Renamed **TreeAdapterInterface** to **AdapterInterface**\n- 3.0.0 Changed namespace to `Arodax\\Doctrine\\Extensions\\Tree`, package has been renamed to `arodax/doctrine-extensions-tree`.\n  Make sure you **change path and the namespace in config/packages/doctrine.yaml** - see installation guide bellow for the example!\n- 2.0.0 Minimum compatible version of doctrine/common package has been increased to 3.0.*\n- 1.0.3 Implementation of [#2020](https://github.com/Atlantic18/DoctrineExtensions/pull/2020) removed instances of hard coded parent column in queries\n- 1.0.2 Added missing repositories from the original extension\n\n- 1.0.1 Implementation of [#2001](https://github.com/Atlantic18/DoctrineExtensions/pull/2001) fixing problem causing wrong left/right order.    \n\n## Installation\nInstall the extension with the [composer](https://getcomposer.org)\n\n`composer require arodax/doctrine-extensions-tree`\n\n### Using in the Symfony project\nThere is no flex recipe yet, so you need to manually enable extension by adding the following into your configuration files\n\n**config/packages/doctrine.yaml**\n```yaml\nparameters:\n    ...   \ndoctrine:\n    dbal:\n        ...\n    orm:\n        ...\n        mappings:\n            ...                \n            Arodax\\Doctrine\\Extensions\\Tree:\n                is_bundle: false\n                type: annotation #attribute\n                dir: '%kernel.project_dir%/vendor/arodax/doctrine-extensions-tree/src/Entity'\n                prefix: 'Arodax\\Doctrine\\Extensions\\Tree\\Entity'\n```\n\n**config/services/doctrine.yaml**\n\n```yaml\nparameters:\n    ...\n\nservices:\n    ...\n    Arodax\\Doctrine\\Extensions\\Tree\\TreeSubscriber:\n        class: Arodax\\Doctrine\\Extensions\\Tree\\TreeSubscriber\n        tags:\n            - { name: doctrine.event_subscriber, connection: default }\n        calls:\n            - [ setAnnotationReader, [ '@annotation_reader' ] ]\n```\n\n## Prepare entity for the hierarchical tree\n\n### Annotate your entity:\n\n```php\n\u003c?php\n\nnamespace App\\Entity;\n\nuse Doctrine\\ORM\\Mapping as ORM;\nuse Arodax\\Doctrine\\Extensions\\Tree\\Mapping\\Annotation as Tree;\n\n/**\n * @ORM\\Entity(repositoryClass=\"App\\Repository\\CategoryRepository\")\n * @Tree\\Tree(type=\"nested\")\n */\nclass Category\n{\n\n    /**\n     * @var integer\n     *\n     * @ORM\\Id()\n     * @ORM\\GeneratedValue()\n     * @ORM\\Column(type=\"integer\")\n     */\n    private $id;\n\n    /**\n     * @Tree\\Left\n     * @ORM\\Column(name=\"lft\", type=\"integer\")\n     */\n     #[Tree\\Left]\n    private $lft;\n\n    /**\n     * @Tree\\Level\n     * @ORM\\Column(name=\"lvl\", type=\"integer\")\n     */\n     #[Tree\\Level]\n    private $lvl;\n\n    /**\n     * @Tree\\Right()\n     * @ORM\\Column(name=\"rgt\", type=\"integer\")\n     */\n     #[Tree\\Right]\n    private $rgt;\n\n    /**\n     * @Tree\\Root()\n     * @ORM\\ManyToOne(targetEntity=\"MenuItem\")\n     * @ORM\\JoinColumn(name=\"tree_root\", referencedColumnName=\"id\", onDelete=\"CASCADE\")\n     */\n     #[Tree\\Root]\n    private $root;\n\n    /**\n     * @Tree\\ParentNode()\n     * @ORM\\ManyToOne(targetEntity=\"MenuItem\", inversedBy=\"children\")\n     * @ORM\\JoinColumn(name=\"parent_id\", referencedColumnName=\"id\", onDelete=\"CASCADE\")\n     */\n     #[Tree\\ParentNode]\n    private $parent;\n\n    /**\n     * @ORM\\OneToMany(targetEntity=\"MenuItem\", mappedBy=\"parent\")\n     * @ORM\\OrderBy({\"lft\" = \"ASC\"})\n     */\n    private $children;\n```\n\n### Extend the repository\n\nExtend your entity repository from `Arodax\\Doctrine\\Extensions\\Tree\\Entity\\Repository\\NestedTreeRepository` this allows you to use special methods for working with the tree:\n\n```php\n\u003c?php\n\nnamespace App\\Repository\\Core\\Menu;\n\nuse App\\Entity\\Category;\nuse Arodax\\Doctrine\\Extensions\\Tree\\Entity\\Repository\\NestedTreeRepository;\n\nclass MenuItemRepository extends NestedTreeRepository\n{\n    //\n}\n\n```\n\n## Usage\n\n### Saving tree\n\nSave some categories:\n\n```php\n\u003c?php\n\n$food = new Category();\n$food-\u003esetTitle('Food');\n\n$fruits = new Category();\n$fruits-\u003esetTitle('Fruits');\n$fruits-\u003esetParent($food);\n\n$vegetables = new Category();\n$vegetables-\u003esetTitle('Vegetables');\n$vegetables-\u003esetParent($food);\n\n$carrots = new Category();\n$carrots-\u003esetTitle('Carrots');\n$carrots-\u003esetParent($vegetables);\n\n$this-\u003eem-\u003epersist($food);\n$this-\u003eem-\u003epersist($fruits);\n$this-\u003eem-\u003epersist($vegetables);\n$this-\u003eem-\u003epersist($carrots);\n$this-\u003eem-\u003eflush();\n```\n\nThe result after flush will generate the food tree:\n\n```\nfood (1-8)\n    /fruits (2-3)\n    /vegetables (4-7)\n        /carrots (5-6)\n```\n\n### Inserting node in different positions      \n```php      \n\u003c?php\n\n$food = new Category();\n$food-\u003esetTitle('Food');\n\n$fruits = new Category();\n$fruits-\u003esetTitle('Fruits');\n\n$vegetables = new Category();\n$vegetables-\u003esetTitle('Vegetables');\n\n$carrots = new Category();\n$carrots-\u003esetTitle('Carrots');\n\n$treeRepository\n    -\u003epersistAsFirstChild($food)\n    -\u003epersistAsFirstChildOf($fruits, $food)\n    -\u003epersistAsLastChildOf($vegetables, $food)\n    -\u003epersistAsNextSiblingOf($carrots, $fruits);\n\n$em-\u003eflush();\n```\n\n### Using repository functions\n\n```php\n\u003c?php\n\n$repo = $em-\u003egetRepository('Entity\\Category');\n\n$food = $repo-\u003efindOneByTitle('Food');\necho $repo-\u003echildCount($food);\n// prints: 3\necho $repo-\u003echildCount($food, true/*direct*/);\n// prints: 2\n$children = $repo-\u003echildren($food);\n// $children contains:\n// 3 nodes\n$children = $repo-\u003echildren($food, false, 'title');\n// will sort the children by title\n$carrots = $repo-\u003efindOneByTitle('Carrots');\n$path = $repo-\u003egetPath($carrots);\n/* $path contains:\n   0 =\u003e Food\n   1 =\u003e Vegetables\n   2 =\u003e Carrots\n*/\n\n// verification and recovery of tree\n$repo-\u003everify();\n// can return TRUE if tree is valid, or array of errors found on tree\n$repo-\u003erecover();\n$em-\u003eflush(); // important: flush recovered nodes\n// if tree has errors it will try to fix all tree nodes\n\n// UNSAFE: be sure to backup before running this method when necessary, if you can use $em-\u003eremove($node);\n// which would cascade to children\n// single node removal\n$vegies = $repo-\u003efindOneByTitle('Vegetables');\n$repo-\u003eremoveFromTree($vegies);\n$em-\u003eclear(); // clear cached nodes\n// it will remove this node from tree and reparent all children\n\n// reordering the tree\n$food = $repo-\u003efindOneByTitle('Food');\n$repo-\u003ereorder($food, 'title');\n// it will reorder all \"Food\" tree node left-right values by the title\n```\n\n\n\nFor more examples and usage check original package documentation:\nhttps://github.com/Atlantic18/DoctrineExtensions/blob/v2.4.x/doc/tree.md     \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farodax%2Fdoctrine-extensions-tree","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Farodax%2Fdoctrine-extensions-tree","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farodax%2Fdoctrine-extensions-tree/lists"}