webhappens / traverser
轻松遍历嵌套对象结构,无需担心递归。
Requires
- php: ^8.0
- illuminate/support: ^8.0|^9.0|^10.0|^11.0
Requires (Dev)
- phpunit/phpunit: ^8.5.19|^9.5.8
- symfony/var-dumper: ^5.0|^6.0
README
Traverser
轻松遍历嵌套对象结构,无需担心递归。非常适合构建菜单、导航、网站地图等!
安装
通过 composer 安装
composer require webhappens/traverser
将类导入您的命名空间
use WebHappens\Traverser\Traverser;
入门
为了让遍历器理解您的层次结构,您必须确保它可以为该层次结构中的每个类解析 "id","parent" 和 "children"。
默认情况下,它将按照该顺序查找每个这些名称的 "methods" 或 "properties"。如果您的类扩展自 Illuminate\Database\Eloquent\Model
,它将自动从 getKey
方法解析 "id"。
您的类通常看起来像这样
public $id; /** * @return object|null */ public function parent() { // } /** * @return array */ public function children() { // }
接下来,创建遍历器类的新实例,并传入您用作遍历起点的类的实例。
$traverser = Traverser::make($current);
您现在可以调用此实例上的各种遍历方法。
$descendants = $traverser->descendants();
为了方便起见,您可能想要将其放在基类或特质中
// Within a base class or trait public function traverser() { return Traverser::make($this); }
然后按如下方式调用它
// Within a class that extends the base class / uses the trait $this->traverser()->descendants();
要深入了解如何使用遍历器,您应该查看测试。
自定义映射名称
如果您想为每个类重写默认的 "id"、"parent" 和 "children" 映射名称,您可以这样做。
为此,将一个包含自定义映射数组的第二个参数传递给构造函数。
$traverser = Traverser:make($current, [ Page::class => ['id' => 'uri'], Post::class => ['parent' => 'category', 'children' => 'comments'], Comment::class => ['parent' => 'post'], ]);
如果您使用 Laravel,您可能希望将其绑定到服务容器。
// Within AppServiceProvider.php $this->app->bind('traverser', function () { return \WebHappens\Traverser\Traverser::make()->maps([...]); });
然后按如下方式解析
// Within your application code $traverser = resolve('traverser')->current($current);
注意,您可以在不传递任何参数的情况下构造一个新的遍历器实例,并使用 maps
和 current
方法。
推断父级和子级
在大多数情况下,您的对象只会有关其 "parent" 或 "children" 的数据,而不会同时有关。因此,遍历器允许您轻松地从一个推断出另一个。
要推断父级,您应将所有可能的父级数组传递给 inferParent
方法。这些对象中的每一个都必须能够解析其自己的子级。
// Within Category.php public function parent() { return $this->traverser()->inferParent(static::all()); } public function children() { return array_merge($this->categories(), $this->posts()); } // Within Post.php public function category() { return $this->traverser()->inferParent(Category::all()); }
要推断子级,您应将所有可能的子级数组传递给 inferChildren
方法。这些对象中的每一个都必须能够解析其自己的父级。
// Within Page.php public function parent() { // ... return new static($parentId); } public function children() { return $this->traverser()->inferChildren(static::all()); }
遍历方法
$parent = $this->traverser()->parent(); $children = $this->traverser()->children(); $ancestors = $this->traverser()->ancestors(); $ancestorsAndSelf = $this->traverser()->ancestorsAndSelf(); $descendants = $this->traverser()->descendants(); $descendantsAndSelf = $this->traverser()->descendantsAndSelf(); $siblings = $this->traverser()->siblings(); $siblingsAndSelf = $this->traverser()->siblingsAndSelf(); $siblingsNext = $this->traverser()->siblingsNext(); $siblingsAfter = $this->traverser()->siblingsAfter(); $siblingsPrevious = $this->traverser()->siblingsPrevious(); $siblingsBefore = $this->traverser()->siblingsBefore(); $siblingsPosition = $this->traverser()->siblingsPosition();
鸣谢
- Ben Gurney: ben@webhappens.co.uk
- Sam Leicester: sam@webhappens.co.uk
- 所有贡献者
许可证
MIT 许可证 (MIT)。有关更多信息,请参阅 许可证文件。