lazychaser / laravel-nestedset

Effective tree structures in Laravel 4-8
3.64k stars 473 forks source link

502 error with livewire #487

Open Roywcm opened 3 years ago

Roywcm commented 3 years ago

I tried to use this package in combination with Livewire. It works great until my tree has child elements. That's when I get a 502 error for some reason.

Strange thing is, it works when I dump the result in Livewire. But when the result is send to the Livewire view, I got this nginx error:

upstream prematurely closed connection while reading response header from upstream

Any idea why this is happening? Or is this a bug in Livewire? Not sure where to look. It happens when the function LinkNodes is fired on this piece of code:

foreach ($children as $child) {
        $child->setRelation('parent', $node);
}
kzgzhn commented 3 years ago

I think this problem is similar #17 fix commit

And maybe need to add something like this to Kalnoy\Nestedset\NodeTrait:

public function getQueueableRelations()
{
    $relations = $this->getRelations();

    if (!isset($relations['parent'])) {
        return parent::getQueueableRelations();
    }

    $parent = $relations['parent'];
    unset($relations['parent']);

    $this->setRelations($relations);
    $result = parent::getQueueableRelations();

    $relations['parent'] = $parent;
    $this->setRelations($relations);

    return $result;
}

Problem: 1. Livewire uses trait \Illuminate\Queue\HydratePublicProperties https://github.com/livewire/livewire/blob/master/src/HydrationMiddleware/HydratePublicProperties.php#L18

method getSerializedPropertyValue() https://github.com/livewire/livewire/blob/master/src/HydrationMiddleware/HydratePublicProperties.php#L152 https://github.com/livewire/livewire/blob/master/src/HydrationMiddleware/HydratePublicProperties.php#L176

  1. method getSerializedPropertyValue() run Model::getQueueableRelations()

And all this goes into a infinite cycle =(

up: or add to livewire component:

public function dehydrate()
{
    $this->model->unsetRelations();
}
briavers commented 3 years ago

@kzgzhn solutions didn't work for me, but

After a few hours of debugging I think I found a way to get this done (I needed a collection of categories) using a private Collection $categories; instead of a public and passing it with the render method (return view('livewire.category.index', ['categories' => $this->categories]);) worked for me

This is however something that still should get looked at / documented, specially since most laravel 8 applications will use livewire (or inertia depending on your setup)

If anyone finds a better way, so I can keep my parameter public, please do share :pray:

sawirricardo commented 3 years ago

Hi, any solutions to this? I stumble to a problem with infinite loop, though.

fer-ri commented 2 years ago

@kzgzhn solutions didn't work for me, but

After a few hours of debugging I think I found a way to get this done (I needed a collection of categories) using a private Collection $categories; instead of a public and passing it with the render method (return view('livewire.category.index', ['categories' => $this->categories]);) worked for me

This is however something that still should get looked at / documented, specially since most laravel 8 applications will use livewire (or inertia depending on your setup)

If anyone finds a better way, so I can keep my parameter public, please do share pray

Works for me. Thanks :+1:

vildanbina commented 2 years ago

+1

stefanocurnis commented 2 years ago

I have this problem too. Private properties do not persists between requests so it's not working properly for me.

Riari commented 6 months ago

I had this issue and found an alternative workaround. In my case, my query looks like this:

$categories = Category::select(array_merge($select, ['is_private', 'parent_id']))
            ->with($with)
            ->defaultOrder()
            ->get()
            ->keyBy('id');

The problem I had was with calling toTree() (which in turn calls linkNodes()) on the resulting collection. However, I noticed the collection is already a tree structure, just with nested nodes also appearing at the top level. Removing those nodes seems to give the same result as toTree() without causing an infinite loop when it's serialised:

foreach ($categories as $id => $category) {
    if ($category->parent_id != null) {
        $categories->forget($id);
    }
}

It's not ideal, but none of the other suggestions worked for me.

EDIT: I realised this doesn't work as the nodes are not ordered correctly. I ended up writing a recursive function to null the parent relationships after calling toTree():

function removeParentRelationships(Collection $categories): Collection
{
    $categories->each(function ($category) {
        $category->setRelation('parent', null);
        if ($category->children) {
            $category->children = removeParentRelationships($category->children);
        }
    });

    return $categories;
}

I don't know why, but using makeHidden('parent') / setHidden(['parent']) on the collection (or specifying $hidden = ['parent'] in the model) wouldn't work for me.