Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

JeroenVanOort's avatar

Executing a View Composer only once

I'm working on a project where we have View Composers attached to multiple views rendered on the same page. The composer and it's queries are executed multiple times. I want it to run only once to optimize performance.

I.e. the ContactPageComposer might look up the link and contents of the site's contact page and can be attached the top and bottom navigation views. However, the ContactPageComposer would be ran twice.

I've looked around and some say it can't be done and a Laravel 4 solution doesn't work with our L5 application.

I feel like there is a possibility to do this, but I haven't found it yet.

0 likes
8 replies
bobbybouwmann's avatar

Have you tried to use caching? So the query will only be called once in a while

JeroenVanOort's avatar

I thought of that, but for this specific project the invalidation of the cache would be very complicated. The navigation we're rendering is dependent on about 7 or 8 models, which would all need triggers to invalidate the cache.

For now, I consider that to be more work than trying to run the composer only once. We will do it if there if performance is a major problem and if there is no other option.

JeroenVanOort's avatar
JeroenVanOort
OP
Best Answer
Level 6

Eureka!

What I forgot about singletons is that while the same object is returned every time, the compose function is still called multiple times. With that in mind, I've found this solution:

In ComposerServiceProvider:

public function register()
    {
        $this->app->singleton(\App\Http\Composers\CountriesComposer::class);
    }

And the composer class itself:

namespace App\Http\Composers;

use Illuminate\Contracts\View\View;
use App\Country;

class CountriesComposer
{
    private $countries;

    public function compose(View $view)
    {
        if (!$this->countries) {
            $this->countries = Country->all();
        }

        return $view->with('countries', $this->countries);
    }
}
18 likes
ralphmrivera's avatar

This doesn't seem to work on Laravel 8. Has anyone had any luck with Laravel 8?

hamidabbasnia's avatar

it works in laravel 8 too ... follow the steps below:

first: put your code inside __construct() instead of compose() so that it is executed only one time once class is initiated as a singleton, then assign class properties with obtained values

use App\Models\User;

protected $users;

public function __construct()
{

   $users = User::get();

   $this->$users= $users;

}


then: pass data to views using compose method:

public function compose()
{

   $view->with('users', $this->users);

}

Please or to participate in this conversation.