staudenmeir / laravel-adjacency-list

Recursive Laravel Eloquent relationships with CTEs
MIT License
1.36k stars 110 forks source link

Tree of Polymorphic relationship #121

Closed GregOstry closed 2 years ago

GregOstry commented 2 years ago

First of all i want to thank you for this awesome package. This helps me a lot to implement it in my use case.

I have a collections table that hold such polymorphic data:

id parent_id collectable_type collectable_id order
1 NULL article 60 1
2 1 attribute 1 1
3 1 attribute 2 2
4 1 attribute 3 3
5 1 attribute 4 4
6 2 text 1161 1
7 3 text 2548 1
8 4 text 2698 1
9 4 text 2906 2
10 5 text 3205 1
11 5 text 4497 2
12 5 text 6381 3
13 5 text 7164 4

Collection Model:

class Collection extends Model
{
    use HasRecursiveRelationships;

    public function collectable()
    {
        return $this->morphTo();
    }

}

Text\Attribute\Article Model:

public function collections()
{
    return $this->morphMany(Collection::class, 'collectable');
}

Is it possible to display Collection table (see above) with the Polymorphic data in the tree structure?

One solution is to eager load the relations, but this gives me an extra relationsship.

$tree = Collection::with('collectable')
        ->treeOf(function($query) {
            $query->whereNull('parent_id')->where('id', 1);
        })
        ->orderBy('order')
        ->get()
        ->toTree()
        ->first();

Maybe there is a more elegant solution for this?

staudenmeir commented 2 years ago

Hi @GregOstry, What do you mean by "but this gives me an extra relationship"? What do you do with the tree? Convert it to JSON? What should the tree look like?

GregOstry commented 2 years ago

Hi,

For each parent and child element I have a morp "collectable" relation. So instead of attributes from the origin table (collection) I would like to see the relation directly. tree

Is it possible to call the relation "collectable" recrusively?

The End Effect in UI should look like this: One Article has 4 or more attributes (In German: Bezeichgnung2, Grammatur, Material, Langtext). In this attributes there are several sections (like Allgemein, ash, sport grey, etc.). And finally, each section contains a text element.

end_effect

I hope I have written this understandably. :)

staudenmeir commented 2 years ago

If I understand you correctly, you can add a recursive method like this to your controller (?):

protected function collectableTree($tree) {
    $result = collect();

    foreach ($tree as $collection) {
        $collection->collectable->setRelation('children', $this->collectableTree($collection->children));

        $result[] = $collection->collectable;
    }

    return $result;
}

$tree = Collection::with('collectable')
        ->treeOf(function($query) {
            $query->whereNull('parent_id')->where('id', 1);
        })
        ->orderBy('order')
        ->get()
        ->toTree();
        //->first();

dump($this->collectableTree($tree));
dump($this->collectableTree($tree)->first());