Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

LonnieD's avatar

Recursive Eloquent using "with" Method?

I'm building an application that uses animal taxonomy data using the adjacency list method of representing the hierarchy in a MySQL database.


id | name | parent_id
---------------------------------
1 | Family | null
2 | Subfamily_1| 1
3 | Subfamily_2 | 1
4 | Genus_1 | 2
5 | Genus_2 | 3

After reading through several tutorials on getting the parent and children of an Eloquent model using adjacency list, I am able to get a single parent and the immediate children of a model using the following.


app\Taxon.php;

// Returns the parent of a taxon
public function parent()
{
        return $this->belongsTo('App\Taxon', 'parent_id', 'id');
}

// Returns all of the immediate children of a taxon
public function children()
{
        return $this->hasMany('App\Taxon', 'parent_id', 'id');
}

Then after further research in getting all parents and children of a given model recursively, I came across a technique using the "with" method for Eloquent Relationships to do this.


app\Taxon.php

// Returns all parents of a Taxon model
public function allParents()
{
     return $this->parent()->with('allParents');
}

The above method, allParents() returns something interesting I can't make sense of and need help understanding so I can send a list of "parents" to a view.

The above "allParents()" method returns an Eloquent collection with all properties of the immediate parent Taxon along with an additional property called "allParents" which itself is an Eloquent collection containing Taxon properties and so on until there are no more "parents" for my chosen Taxon. So the allParents() method works just fine in returning all of the "parents", but I don't know how to send the whole collection to a view to list out all of the parents.

This is a sample of what is returned from php artisan tinker


>>> $parents = $taxon->allParents;
=> App\Taxon {#3038
     id: 53,
     name: "Acanthopelma",
     parent_id: 5,
     allParents: App\Taxon {#3030
       id: 5,
       name: "Ischnocolinae",
       parent_id: 1,
       allParents: App\Taxon {#3024
         id: 1,
         name: "Theraphosidae",
         parent_id: null,
         allParents: null,
       },
     },
   }

How do I return a collection or array to a view given this kind of output so that I can display the entire hierarchy as a list such as the one below. You will notice that the list below contains only the name property from the collection above, but in reverse order.

  • Theraphosidae
  • Ischnocolinae
  • Acanthopelma
0 likes
4 replies
GeordieJackson's avatar

For all parents try:

public function parents()
{
    return $this->belongsTo('App\Taxon', 'parent_id', 'id')->with('parents');
}

And for descendants:

public function descendants()
{
    return $this->hasMany('App\Taxon', 'parent_id', 'id')->with('descendants');
}
LonnieD's avatar

Thank you for your quick response. The code you provided generated the exact same output as mine did. The problem isn't how to retrieve all "parents" or "descendants" of a given Taxon, but how to loop through the results in either a Controller method or in a View foreach loop to generate a simple list. That is what I am stuck on.

I was hoping the Eloquent "with" method would return one collection per "parent" so I can do a simple view foreach like so...

@foreach ($parents as $parent)
	{{ $parent->name }}
@endforeach

But since I get nested Eloquent collections, I don't know how to list out each parent's name when I don't know in advance how many parents there are. It would seem I need another recursive function somewhere, but not sure.

Basically, my question is what do I do with the results in order to list the name of each parent in a view?

GeordieJackson's avatar
Level 18

As the relationship is a One to Many, the inverse will mean that each category will only have one parent and each parent will have only one parent etc...

So in order to get a sequential list, the results will need to be looped through and built up. e.g.

$taxon = Taxon::with('parents')->find($id);

$parents = collect();
$currentTaxon = $taxon;

do {
    $parents[] = ['name' => $currentTaxon->name];
} while ($currentTaxon = $currentTaxon->parents);

Then just return $parents or $parents->reverse() depending on which order you want them in.

@foreach ($parents as $parent)
    {{ $parent['name'] }}
@endforeach

Should now work OK

LonnieD's avatar

Worked perfectly! Thank you so much for your quick responses.

Please or to participate in this conversation.