Optimize The Behavior Of View Composers In Laravel?

- 1 answer

I've set up a few view composers in order to pass general data to the master layout for each request but it has come to my attention this can be a performance drawback.

E.g. I have a CharityComposer which, in its __construct() method sets a protected property $charities with the result of Charity::all(). Each Charity model has a custom attribute totalAmountUnpaidDonations which is simple a calculation from all $charity->donations[$index]->amount where a Donation's property paid is set to 0.

When the totalAmountUnpaidDonations is greater than 0 I'd like to draw attention to that fact using a notification in my master layout.

But when I var_dump the variable in my CharityComposer I see it gets var_dumped 6 times. 4 of these 6 times are from partial includes in the Blade template and the other 2 are (I think) for the master layout and the view the controller actually returns for the given route.

Is there a way to prevent this and have a view composer run once per request? Like a sort of RequestComposer, but I don't believe these exists in the context of Laravel. Or should I set this up in a different way?



The fact that a composer class gets instantiated every time the view is rendered is not something you can get around, and if you have logic that is resource or time consuming, that will add up because of the multiple executions. As far as using view composer classes I don't see any quick ways around the problem.

However there is a way to easily fix this by setting up the composer to use a closure instead of a class, then moving the logic outside of the composer and only pass the result to the closure, so the only statement left to be executed before the view is rendered, is the one assigning the variable to the view.

So you could have this:

// Query the database for the information once
$data = Charity::all();

// Pass the information to the composer closure using the `use` construct
view()->composer(['all', 'your', 'views'], function ($view) use ($data) {
    // This still gets executed 6 times, but that's not a problem anymore
    $view->with('data', $data);