Search code examples
phplaravellaravel-5eloquent

Laravel Get ancestors (URL)


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 by "/").

level1/level2/level3

But in an efficient way without a package like "laravel-nestedset ".

I have implemented it like this.

public function parent()
{
    return $this->belongsTo('Collection', 'parent_id');
}

public function getParentsAttribute()
{
    $parents = collect([]);

    $parent = $this->parent;

    while(!is_null($parent)) {
        $parents->push($parent);
        $parent = $parent->parent;
    }

    return $parents;
}

Any other way to do it efficiently and separated by "/" ?


Solution

  • 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:

    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.