Laravel Get ancestors (URL)

后端 未结 2 1768
一生所求
一生所求 2021-01-19 18:08

In Laravel, I have a table which contains id, parent_id, slug (Self-referring),

When I have an ID, I need to get all its ancestors in a format like this (Separated b

相关标签:
2条回答
  • 2021-01-19 18:12

    After a little conversation in the comments I think this is a good solution:

    // YourModel.php
    
    // Add this line of you want the "parents" property to be populated all the time.
    protected $appends = ['parents'];
    
    public function getParentsAttribute()
    {
        $collection = collect([]);
        $parent = $this->parent;
        while($parent) {
            $collection->push($parent);
            $parent = $parent->parent;
        }
    
        return $collection;
    }
    

    Then you can retrieve your parents using:

    • YourModel::find(123)->parents (collection instance)
    • YourModel::find(123)->parents->implode('yourprop', '/') (imploded to string, see https://laravel.com/docs/5.4/collections#method-implode)
    • YourModel::find(123)->parents->reverse()->implode('yourprop', '/') (reversed order https://laravel.com/docs/5.4/collections#method-reverse)

    As noted by Nikolai Kiselev https://stackoverflow.com/a/55103589/1346367 you may also combine it with this to save a few queries:

    protected $with = ['parent.parent.parent'];
    // or inline:
    YourModel::find(123)->with(['parent.parent.parent']);
    

    This preloads the parent on object load. If you decide not to use this, the parent is (lazy) loaded as soon as you call $yourModel->parent.

    0 讨论(0)
  • 2021-01-19 18:20

    If you know how many levels maximum could be nested you can use Eager Loading. Let's say if maximum depth is 3 levels you can do:

    $model->with('parent.parent.parent');
    

    You can also use recursion instead of loop.

    public function getParentsAttribute()
    {
        if (!$this->parent) {
            return collect([]);
        }
    
        return collect($this->parent->parents)->push($this->parent);
    }
    

    In case you want to add the first one object too (self) the full call will be:

    $model->parents->push($model)->reverse->implode('attr_name', '/');
    

    Which you can also wrap into attribute

    public function getPathAttribute() {
        return $model->parents->push($model)->reverse->implode('attr_name', '/');
    }
    

    And call like $model->path;

    0 讨论(0)
提交回复
热议问题