Search code examples
laravellaravel-livewire

Why using compact method in Livewire view raised error?


On a Laravel site I pass 2 parameters to Blade file:

class CrudAppImages extends Component
{
    ...
    public function render()
    {
        $appImageRowsCount = AppImage
            ::getByTitle($this->filters['title'], $this->filters['extended_search'])
            ->count();

        $backendPerPage = (int)Cache::get("backend_per_page", 20);
        $appImageDataRows = AppImage
            ::orderBy('created_at', 'desc')
            ->with('creator')
            ->getByTitle($this->filters['title'], $this->filters['extended_search'])
            ->paginate($backendPerPage);

        return view('admin.app-images.crud-app-images', [
            'appImageDataRows' => $appImageDataRows,
            'appImageRowsCount' => $appImageRowsCount
        ])->layout('components.admin');
    }

and that work OK. But when I tried to use compact method:

return view('admin.app-images.crud-app-images', [
    compact('appImageDataRows', 'appImageRowsCount')
])->layout('components.admin');

I got error in Blade page:

Undefined variable $appImageRowsCount

What is wrong and how to fix it?

"laravel/framework": "^10.45.1",
"livewire/livewire": "^3.4.6",

Solution

  • I've already commented but will also provide a more in-depth answer.


    compact() is a PHP array function, in short, it creates an array from user-defined variables and their values. Documentation can be found here

    You are creating an array of the compact() array instead of directly passing the compact() array to your view.

    To solve your issue you should remove the [] as follows.

    return view('admin.app-images.crud-app-images', [
        compact('appImageDataRows', 'appImageRowsCount')
    ])->layout('components.admin')
    

    To

    return view('admin.app-images.crud-app-images',
        compact('appImageDataRows', 'appImageRowsCount')
    )->layout('components.admin')
    

    Why does this happen?

    I'm not completely sure how Laravel internally interprets the values a user passes to a view, so I can't give a definitive answer. Below is an assumption.

    In your original code, you are effectively passing the following to the view;

    array:1 [
      0 => array:1 [
        "variable" => "value",
        "variable" => "value",
        "variable" => "value",
      ]
    ]
    

    This means that the variables you've passed are nested in an array, I guess Laravel tries something like $viewData["your_variable"], but since you've passed them wrong it has to do something like $viewData[0]["your_variable'] which it cannot do.

    Keep in mind that this is purely hypothetical, if someone does know the answer I would love to be enlightened.

    Update

    I've found that passing the variables like so; [compact(...)] actually causes Laravel to not even interpret those variables.

    Another assumption, I guess Laravel looks at the __data array, which obviously gets incorrect values.

    Example 1 (wrong);

    // Controller
    return view('a-view', [compact('foo', 'bar')]);
    
    // View:
    dd(get_defined_vars());
    
    // Output:
    array:5 [
      "__path" => "some_path"
      "__data" => array:3 [
        "__env" => Illuminate\View\Factory {#460 …23}
        "app" => Illuminate\Foundation\Application {#2 …40}
        "errors" => Illuminate\Support\ViewErrorBag {#2039 ▶}
      ]
      "__env" => Illuminate\View\Factory {#460 …23}
      "app" => Illuminate\Foundation\Application {#2 …40}
      "errors" => Illuminate\Support\ViewErrorBag {#2039 ▶}
    ]
    

    Example 2 (right)

    // Controller
    return view('a-view', compact('foo', 'bar'));
    
    // View:
    dd(get_defined_vars());
    
    // Output:
    array:7 [
      "__path" => "some_path"
      "__data" => array:12 [
        "__env" => Illuminate\View\Factory {#460 …23}
        "app" => Illuminate\Foundation\Application {#2 …40}
        "errors" => Illuminate\Support\ViewErrorBag {#2039 ▶}
        "foo" => array:2 [▶]
        "bar" => array:2 [▶]
      ]
      "__env" => Illuminate\View\Factory {#460 …23}
      "app" => Illuminate\Foundation\Application {#2 …40}
      "errors" => Illuminate\Support\ViewErrorBag {#2039 ▶}
      "foo" => array:2 [▶]
      "bar" => array:2 [▶]
    ]