Laravel View Composer duplicating SQL queries for every view
Asked Answered
C

3

5

I need to access some data (User details) in most views. What I have done:

I created ComposerServiceProvider

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class ComposerServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap the application services.
     *
     * @return void
     */
    public function boot()
    {
        view()->composer(
            ['includes.header','profile'],
            'App\Http\ViewComposers\CustomerComposer'
        );

    }

    /**
     * Register the application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

Created CustomerComposer class

<?php

namespace App\Http\ViewComposers;

use Illuminate\Support\Facades\Auth;
use Illuminate\View\View;
use Modules\Customers\Entities\CustomerDetail;

class CustomerComposer
{
    public $customer = [];

    /**
     * Bind data to the view.
     *
     * @param  View  $view
     * @return void
     */
    public function compose(View $view)
    {
        $user = Auth::guard('customer');

        $this->customer = CustomerDetail::where('user_id',$user->id())->first();

        $view->with( 'customer', $this->customer );
    }
}

Everything works but when I look at Debug bar it shows me same queries excecuted per view, so for example if I define ['includes.header','profile'] Same SQL will be excecuted twice if ['includes.header','profile','something_else'] 3 times and so on...

In this case query's is

select * from `customer_details` where `user_id` = '1' limit 1
select * from `customer_details` where `user_id` = '1' limit 1

If I provide wildcard in

view()->composer(
            ['*'],
            'App\Http\ViewComposers\CustomerComposer'
        );

It will generate 23 queries! I missed something here?

Chromate answered 29/9, 2017 at 18:26 Comment(0)
C
6

Ok I think I found solution. In ComposerServiceProvider class:

/**
* Register the application services.
*
* @return void
*/
public function register()
{
    $this->app->singleton(\App\Http\ViewComposers\CustomerComposer::class);
}

That it.

In Laravel Docs

Registering A Singleton

Sometimes, you may wish to bind something into the container that should only be resolved once, and the same instance should be returned on subsequent calls into the container:

Chromate answered 29/9, 2017 at 19:25 Comment(0)
I
1

Per the manual at https://laravel.com/docs/5.5/views#view-composers:

"View composers are callbacks or class methods that are called when a view is rendered. If you have data that you want to be bound to a view each time that view is rendered, a view composer can help you organize that logic into a single location."

(emphasis mine)

In this case:

    view()->composer(
        ['includes.header','profile'],
        'App\Http\ViewComposers\CustomerComposer'
    );

you're attaching the includes.header view and the profile view, which I guess includes the includes.header view. So, since the composer is executed when the view is rendered, it'll execute twice, one when rendering of the profile view and again another when rendering the includes.header view.

Incommensurable answered 29/9, 2017 at 19:9 Comment(1)
I understand that, but what is most efficient way to pass data from Model to all views? I though this implementation is made for this, I must be missing something obvious here.Chromate
C
0

You can use config here to resolve multiple times query run issue for view compose. For example show below code.

public function compose(View $view) {

if(!Config::has('composeVars')) 
{
    Config::set('composeVars') = [
      'users' => User::all();  
    ];
}

$view->with('*', Config::get('composeVars'));

}

Cane answered 24/2, 2021 at 11:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.