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

dhermann's avatar

View Composer data not available when assigned to layout

I was taking the advice of @Snapey and @Cronix to assign my View Composer to my master layout, instead of a wildcard, but it doesn't seem to be working.

ComposerServiceProvider.php

<?php

namespace App\Providers;

use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;

class ComposerServiceProvider extends ServiceProvider
{
    /**
     * Register bindings in the container.
     *
     * @return void
     */
    public function boot()
    {
        View::composer(['layouts.app'], function ($view) {
            $year = \App\Year::where('is_current', '1')->first();
            $view->with('year', $year);
...
        });

    }

    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

ErrorException (E_ERROR) Undefined variable: year (View: /home/vagrant/code/resources/views/campcost.blade.php)

I can see from the debug bar that the ComposerServiceProvider database calls are not happening. Any ideas?

0 likes
12 replies
tykus's avatar

Does the campcost template extend the resources/views/layouts/app.blade.php layout?

dhermann's avatar

Yes.

@extends('layouts.app')

@section('title')
    Camp Cost Calculator
@endsection

@section('heading')
    Use this tool to easily estimate the cost of your fees for {{ $year->year }}.
@endsection
...
tykus's avatar
tykus
Best Answer
Level 104

Are you using the variable in the layout or in the view that extends the layout?

The data that is composed for the layout.app template is scoped to that template and is not inherited by the yielded views.

1 like
dhermann's avatar

Aha, that's it @tykus . Is there a way to pass it into the yielded views or do I need to change the @yield to @include directives and pass in the data manually?

tykus's avatar

Only way I can think to do this is to use view composer on the directory path rather than to a layout template, i.e.

View::composer('camps.*', function ($view) {
    $year = \App\Year::where('is_current', '1')->first();
    $view->with('year', $year);
});

Where your directory structure is something like: /resources/views/camps/campcost.blade.php

Your variable will be composed only for view template files under that directory structure, and will be available to the layout(s) they extend.

2 likes
dhermann's avatar

A good idea @tykus but I still hit the same problem with child views either a) not having access due to scope or b) running the composer more than once, defeating the purpose of the optimization. I'm beginning to think composers were just not meant to house database calls.

tykus's avatar

I'm beginning to think composers were just not meant to house database calls

Not necessarily true, but it might be that instead you need to specify all of the individual views that will use that composer:

View::composer(['campcost', ... 'nth-view'], function ($view) {
    $year = \App\Year::where('is_current', '1')->first();
    $view->with('year', $year);
});
1 like
dhermann's avatar

@tykus I have over 30 views for this site, plus I'd end up having to pass it into all the child views anyway. It doesn't seem worth it.

tykus's avatar

I understand. Last shot... service injection will allow you to extract the computation of the $year to a class and @inject it in any view template that requires it. Not sure if your query is sufficiently complex to necessitate service injection, but you get the idea.

Good luck!

1 like
dhermann's avatar

@tykus Yep, that's what I was trying to refactor away from. I'll just revert to an @inject directive on every view.

Please or to participate in this conversation.