arodax / doctrine-extensions-tree
Doctrine 的树形扩展
Requires
- php: >=8.0
Requires (Dev)
- doctrine/orm: ^2.8
Suggests
- doctrine/doctrine-bundle: to be used with doctrine bundle
- symfony/cache: to cache annotations
Conflicts
README
此扩展允许您使用 Doctrine ORM 在数据库中以层次结构存储数据。
注意:此代码是 Atlantic18/DoctrineExtensions 2.4.x 分支的树形扩展的硬分支。
许可
MIT
变更日志
-
3.2.3 修复了缓存项 ID 生成器
-
3.2.2 当安装 symfony/cache 时,自动缓存实体元数据。
-
3.2.1 修复了 XML 驱动程序中类和文件名不匹配的问题
-
3.2.0 废弃了 TreeRight、TreeLeft、TreeClosure、TreeRoot、TreePath、TreeLevel 注解,使用不带 "Tree" 前缀的它们(例如,Right、Left、Closure ...)
-
3.2.0 添加了对原生 PHP 属性的支持
-
3.1.0 将 TreeAdapterInterface 重命名为 AdapterInterface
-
3.0.0 将命名空间更改为
Arodax\Doctrine\Extensions\Tree
,包已重命名为arodax/doctrine-extensions-tree
。请确保您在 config/packages/doctrine.yaml 中更改路径和命名空间 - 以下安装指南中有示例! -
2.0.0 doctrine/common 包的最低兼容版本已提高至 3.0.*
-
1.0.3 实现了 #2020,删除了查询中的硬编码父列实例
-
1.0.2 添加了原始扩展中缺少的存储库
-
1.0.1 实现了 #2001,修复了导致左/右顺序错误的问题
安装
使用 composer 安装扩展
composer require arodax/doctrine-extensions-tree
在 Symfony 项目中使用
目前还没有 flex 脚本,因此您需要手动通过将以下内容添加到配置文件中来启用扩展
config/packages/doctrine.yaml
parameters: ... doctrine: dbal: ... orm: ... mappings: ... Arodax\Doctrine\Extensions\Tree: is_bundle: false type: annotation #attribute dir: '%kernel.project_dir%/vendor/arodax/doctrine-extensions-tree/src/Entity' prefix: 'Arodax\Doctrine\Extensions\Tree\Entity'
config/services/doctrine.yaml
parameters: ... services: ... Arodax\Doctrine\Extensions\Tree\TreeSubscriber: class: Arodax\Doctrine\Extensions\Tree\TreeSubscriber tags: - { name: doctrine.event_subscriber, connection: default } calls: - [ setAnnotationReader, [ '@annotation_reader' ] ]
为层次结构树准备实体
注释您的实体
<?php namespace App\Entity; use Doctrine\ORM\Mapping as ORM; use Arodax\Doctrine\Extensions\Tree\Mapping\Annotation as Tree; /** * @ORM\Entity(repositoryClass="App\Repository\CategoryRepository") * @Tree\Tree(type="nested") */ class Category { /** * @var integer * * @ORM\Id() * @ORM\GeneratedValue() * @ORM\Column(type="integer") */ private $id; /** * @Tree\Left * @ORM\Column(name="lft", type="integer") */ #[Tree\Left] private $lft; /** * @Tree\Level * @ORM\Column(name="lvl", type="integer") */ #[Tree\Level] private $lvl; /** * @Tree\Right() * @ORM\Column(name="rgt", type="integer") */ #[Tree\Right] private $rgt; /** * @Tree\Root() * @ORM\ManyToOne(targetEntity="MenuItem") * @ORM\JoinColumn(name="tree_root", referencedColumnName="id", onDelete="CASCADE") */ #[Tree\Root] private $root; /** * @Tree\ParentNode() * @ORM\ManyToOne(targetEntity="MenuItem", inversedBy="children") * @ORM\JoinColumn(name="parent_id", referencedColumnName="id", onDelete="CASCADE") */ #[Tree\ParentNode] private $parent; /** * @ORM\OneToMany(targetEntity="MenuItem", mappedBy="parent") * @ORM\OrderBy({"lft" = "ASC"}) */ private $children;
扩展仓库
从 Arodax\Doctrine\Extensions\Tree\Entity\Repository\NestedTreeRepository
扩展您的实体仓库,这允许您使用特殊方法来处理树
<?php namespace App\Repository\Core\Menu; use App\Entity\Category; use Arodax\Doctrine\Extensions\Tree\Entity\Repository\NestedTreeRepository; class MenuItemRepository extends NestedTreeRepository { // }
用法
保存树
保存一些类别
<?php $food = new Category(); $food->setTitle('Food'); $fruits = new Category(); $fruits->setTitle('Fruits'); $fruits->setParent($food); $vegetables = new Category(); $vegetables->setTitle('Vegetables'); $vegetables->setParent($food); $carrots = new Category(); $carrots->setTitle('Carrots'); $carrots->setParent($vegetables); $this->em->persist($food); $this->em->persist($fruits); $this->em->persist($vegetables); $this->em->persist($carrots); $this->em->flush();
flush 后的结果将生成食品树
food (1-8)
/fruits (2-3)
/vegetables (4-7)
/carrots (5-6)
在不同位置插入节点
<?php $food = new Category(); $food->setTitle('Food'); $fruits = new Category(); $fruits->setTitle('Fruits'); $vegetables = new Category(); $vegetables->setTitle('Vegetables'); $carrots = new Category(); $carrots->setTitle('Carrots'); $treeRepository ->persistAsFirstChild($food) ->persistAsFirstChildOf($fruits, $food) ->persistAsLastChildOf($vegetables, $food) ->persistAsNextSiblingOf($carrots, $fruits); $em->flush();
使用仓库函数
<?php $repo = $em->getRepository('Entity\Category'); $food = $repo->findOneByTitle('Food'); echo $repo->childCount($food); // prints: 3 echo $repo->childCount($food, true/*direct*/); // prints: 2 $children = $repo->children($food); // $children contains: // 3 nodes $children = $repo->children($food, false, 'title'); // will sort the children by title $carrots = $repo->findOneByTitle('Carrots'); $path = $repo->getPath($carrots); /* $path contains: 0 => Food 1 => Vegetables 2 => Carrots */ // verification and recovery of tree $repo->verify(); // can return TRUE if tree is valid, or array of errors found on tree $repo->recover(); $em->flush(); // important: flush recovered nodes // if tree has errors it will try to fix all tree nodes // UNSAFE: be sure to backup before running this method when necessary, if you can use $em->remove($node); // which would cascade to children // single node removal $vegies = $repo->findOneByTitle('Vegetables'); $repo->removeFromTree($vegies); $em->clear(); // clear cached nodes // it will remove this node from tree and reparent all children // reordering the tree $food = $repo->findOneByTitle('Food'); $repo->reorder($food, 'title'); // it will reorder all "Food" tree node left-right values by the title
有关更多示例和用法,请参阅原始包文档: https://github.com/Atlantic18/DoctrineExtensions/blob/v2.4.x/doc/tree.md