ErrorException Maximum function nesting level of '512' reached, aborting!

I am using Laravel NestedSets for a multi-level quiz. If I put the Question Model as a Public Property I get an error ErrorException Maximum function nesting level of '512' reached, aborting!.

I have tested this outside of Livewire and it works fine. Only does it throw this error if I am using Livewire with $question as a public property.

If you change dump() to dd() it will output the data fine but obviously that kills the application and it can’t continue. The error seems to happen when render() returns.

Quiz.php

use App\Models\QuizDataSet as QuizSet;
public $question; // this kills Livewire
class Quiz extends Component
{
    public function mount() {
        $this->question = QuizSet::descendantsAndSelf(1)->toTree();
        dump($this->question);
    }
    public function render() {
        return view('livewire.quiz');
    }

You can try it for yourself by cloning my repo here https://github.com/jjjrmy/livewire-test

  • Composer Install
  • Artisan Migrate --Seed

It’s not a liveware issue, you have an infinite loop in your QuizSet model somewhere. When you dd(), it only nests out so far, that’s why you don’t get the error.

If I use the same code in a standard controller (not Livewire component) it will work fine.
If the property is private it will not error, you can even do $question = QuizSet::descendantsAndSelf(1)->toTree(); and it will not error. Only errors when it is in a Livewire component controller and set property to public.

Edit: I included a non-Livewire example of it working with the same code in a regular controller.

Can you post a share link from your error page to see the stack trace?

I can’t find the cause. Is there a reason that javascript would need to track $question? If not, I would let the view compiler handle it instead of livewire.

    public function render() {
        return view('livewire.quiz')
            ->withQuestion(QuizSet::descendantsAndSelf(1)->toTree());
    }

How would I access the Question inside the view with that?

The reason it needs to track $question is because the Quiz component handles all the Questions as sub-components. So on the quiz.php (view) would be this:

@livewire($question->objectable['component'], ['q' => $question], key($step))
// @livewire('custom-select, ['q' => $question], key($step))

And on the sub question it just uses the $question model to show all the answers like

<b>{{ $question->objectable['question'] }}</b>
@foreach ($question->descendants as $answer)
    <div wire:click="answer('{{ $answer }}')" wire:key="{{ $loop->index }}">
        {$answer->objectable['answer']}}
    </div>
@endforeach

I have a Github issue open about this with more details on my specific use case: https://github.com/livewire/livewire/issues/811

Properties can ONLY be either a JavaScript-friendly data types ( string , int , array , boolean ), OR an eloquent model (or collection of models).

I was checking in the Livewire SRC and see maybe this is causing the issue?
Because it is not triggering is_array() so maybe the data isn’t being converted into the right format to pass it to the view?

To start, I think the cause is the toTree(). It looks like it’s a method the package creates on a custom collection. I don’t know why it’s causing an infinite loop though. I don’t use them in my workflow, so I’ve never tried it with Livewire, but it’s very plausable Livewire doesn’t get along with them.

Edit: not the actual toTree() method, the fact it’s a custom collection.

It’s still a view component, you would do it the same exact way if Livewire wasn’t involved.

return view('livewire.quiz')
            ->withQuestion(QuizSet::descendantsAndSelf(1)->toTree());

is the same as (I just like the way it reads better)

return view('livewire.quiz', [
    'question' => QuizSet::descendantsAndSelf(1)->toTree()
]);

which gives you the $question variable in your view. In most cases, the only things that need to be public properties in your Livewire components are things that javascript needs to track so you can wire:model them to an input, which you are not using in any of your example code here. Everything else works the same as regular Laravel blade, and all of the blade code you have in this reply will work without javascript needing to track anything.

Yes I think it being a custom collection could be big part of the issue.
I will do some more testing and post back here.

So I did some testing with this and I’m running into another issue…
Because that data cannot be saved in public property it is lost on Hydrate.

Yes you can pass the data, as you mentioned, in like this

return view('livewire.quiz', [
    'question' => QuizSet::descendantsAndSelf(1)->toTree()
]);

and then on the view I can access it like this
@livewire($this->question->objectable->component, ['q' => $this->question], key($step))

BUT the issue comes around again that when the component or sub component are hydrated again the data is lost.

You are going to have to be more specific to what data is lost.

Any data not in a public property is lost. So the $question gets lost, especially in the sub component.