staudenmeir/laravel-adjacency-list

withRecursiveQueryConstraint meaning

decadence opened this issue · 2 comments

Hello.

Thanks for the great package. I try different scenarios and have doubt about how withRecursiveQueryConstraint method works.

For example I want to get categories that have in descendantsOrSelf category with ID 1 or 10.

Category::withRecursiveQueryConstraint(function($category) {
    $category->whereHas("descendantsAndSelf", function($descendant) {
        $descendant->whereKey([1, 10]);
    });
}, function() {
    return Category::tree()->get();
});

This gives 500 error with PHP Fatal error: Allowed memory size of 1610612736 bytes exhausted (tried to allocate 20480 bytes) in \vendor\staudenmeir\laravel-adjacency-list\src\Eloquent\Traits\HasAdjacencyList.php on line 44 in logs. Seems like there is endless recursion somewhere because of descendantsAndSelf. Is it limitation or I'm doing something wrong?

If query is like this:

Category::tree()->whereHas("descendantsAndSelf", function($descendant) {
            $descendant->whereKey([1, 10]);
        })
        ->get();

It works ok.

So:

  1. Does withRecursiveQueryConstraint support whereHas method or just simple where conditions?
  2. What is difference between withRecursiveQueryConstraint and whereHas directly on tree query?

Thanks.

Hi @decadence,

  1. Does withRecursiveQueryConstraint support whereHas method or just simple where conditions?

whereHas() works with withRecursiveQueryConstraint() but not with recursive relationships like descendants. I don't know where exactly the endless recursion is coming from, but the generated SQL wouldn't work anyway.

For your case, the second query is the correct one.

  1. What is difference between withRecursiveQueryConstraint and whereHas directly on tree query?

When you add a constraint to the tree() query, the query first builds the whole tree and then applies the constraint.

With withRecursiveQueryConstraint(), the query stops building the tree as soon as it encounters a record that doesn't match the constraint.

Consider the example from the README:

  • User::tree()->where('active', true)->get() gives you all active users.
  • When you add the constraint to withRecursiveQueryConstraint(), you only get active users whose ancestors are also active, i.e. you don't get active users with inactive ancestors.

@staudenmeir
Thanks for your reply, I got it.

I don't know where exactly the endless recursion is coming from

src\Eloquent\Traits\HasAdjacencyList.php on line 44

but not with recursive relationships like descendants ... the generated SQL wouldn't work anyway

maybe this should be mentioned in documentation :)