skip to content

In Laravel, when would you use View::share, a view composer or a view creator to give every university page its department navigation?

level: seniorimportance: should knowfreq 45%

answer

  1. eager at boot versus lazy at render
  2. View::share has the lowest precedence
  3. composer: compose(View $view), resolved from container
  4. creator runs when the view is made
  5. '*' wildcard fires on every view

basics

~20 s

View::share sets a value once, in a provider's boot(), for every view. A view composer runs just before a named view renders, so it suits data that only some pages need. A creator runs when the view is created, before render.

solid answer

~50 s

`View::share('campusName', ...)` in `AppServiceProvider::boot()` stores a value that every view receives, but it is computed eagerly on every request, JSON endpoints included, and before middleware has run, so the session and the signed-in user are not available yet. A **view composer**, `View::composer('partials.nav', DepartmentNavComposer::class)`, is lazy: Laravel resolves the class from the container and calls `compose(View $view)` each time `partials.nav` is about to render, so the department query runs only on pages that show the menu, and request state is available. Two costs: a partial rendered several times runs its composer each time, and a `'*'` wildcard runs on every view, components and partials included. A **view creator** (`View::creator`) runs as soon as the view object is created, so data chained later with `->with()` can override it. Shared data has the lowest precedence of the three.

code

php · 22 lines
php
<?php

namespace App\View\Composers;

use App\Models\Department;
use Illuminate\Support\Facades\Cache;
use Illuminate\View\View;

class DepartmentNavComposer
{
    public function compose(View $view): void
    {
        $view->with('departments', Cache::remember(
            'nav.departments',
            3600,
            fn () => Department::orderBy('name')->get(['name', 'slug']),
        ));
    }
}

// In AppServiceProvider::boot():
// View::composer('partials.nav', DepartmentNavComposer::class);

go deeper

for a junior

Recall the three hooks: View::share for every view, View::composer for named views at render time, View::creator at view creation. They are usually registered in a provider's boot().

for a middle

Explain the timing: share is eager at boot, composers run just before render and resolve from the container, creators run when the view object is made; know the precedence.

for a senior

Show the production judgment: no queries or user lookups in boot-time sharing, memoized composers for repeated partials, no '*' composers doing work, and precedence surprises between controller and composer data.

for a principal

Set a team rule for where view data comes from, so controllers stay the obvious source and composers do not become hidden per-render query sites.

## The problem: data every layout needs A university site's layout shows a department menu, the campus name, and maybe the signed-in student's name. Passing those from every controller is repetitive and easy to forget. Laravel's view factory offers three hooks for supplying such data centrally: **shared data**, **view composers** and **view creators**. They differ in *when* they run, and that timing decides which one fits. ## View::share: one value for every view `View::share('campusName', config('app.name'))`, usually placed in `App\Providers\AppServiceProvider::boot()`, stores a key on the view factory. Every view rendered afterwards receives it, because the factory merges shared data into each view's data at render time. - It is **eager**: the value is computed when the provider boots, on every request, including API requests that never render a view. A database query here costs every request. - It runs **before middleware**. Providers boot before the HTTP middleware pipeline, so the session has not been started and the authenticated user is not known yet. Request-specific values do not belong here. - It has the **lowest precedence**: shared data is merged first, so any key a controller passes with the same name wins. It suits cheap, request-independent values such as a campus name or a support email address. ## View composers: data at render time A **view composer** is a closure or class registered for one or more view names: 1. Register it in a provider's `boot()`: `View::composer('partials.nav', DepartmentNavComposer::class)`. An array of names or a `'*'` wildcard also works. 2. For a class, Laravel resolves it from the **service container**, so its constructor can type-hint dependencies, and calls its `compose(View $view)` method. 3. The call happens right before that view renders, and the composer adds data with `$view->with('departments', ...)`. Because it is **lazy**, the department query runs only when the navigation partial is actually rendered, and by then middleware has run, so the session and the user are available. It also keeps data next to the view that needs it instead of in every controller. The costs are worth knowing in production: - The composer runs **every time** that view renders. A partial included three times per page runs its composer three times; memoize the result, for example with `Cache::remember`, or bind the composer class as a singleton and keep the loaded result in a property. - A `'*'` composer runs for **every view**, including each component and partial, which on a busy page is hundreds of calls. - Because it runs last, a composer's `with()` **overrides** a key the controller passed under the same name. ## Organising composers Laravel ships no default directory for composer classes; `app/View/Composers` is a common convention. Some practical rules: - register composers in a service provider's `boot()` method, next to other view setup; - prefer a **class** once the composer has dependencies, so they are injected through the constructor and the class can be unit tested; - attach a composer to the **smallest view** that needs the data, such as `partials.nav`, not to the whole layout or to `'*'`; - keep the registration next to the view name it targets, since renaming the partial without updating it leaves the menu's variable undefined and the render fails. ## View creators: data at creation time `View::creator('partials.nav', DepartmentNavCreator::class)` looks the same but fires **as soon as the view object is created**, when `view()` or `View::make()` builds it, before rendering. A class creator's method is `create(View $view)`. The practical difference is precedence: data attached after creation, such as `view('courses.index')->with('departments', $filtered)`, overrides what the creator set, while a composer would have overridden the controller. Use a creator for defaults a controller is allowed to replace. ## Choosing | Need | Hook | Why | |---|---|---| | cheap constant for every view | `View::share` | set once at boot, lowest precedence | | data for one partial, fetched only when shown | `View::composer` | lazy, runs after middleware, container-resolved | | a default that controllers may override | `View::creator` | runs at creation, later `with()` wins | | request-specific values like the current user | a composer, or data passed by the controller | boot-time sharing runs before the session exists | For the department menu, a class-based composer on `partials.nav` with a cached query is the usual answer: the data is fetched only where the menu appears, it sees the current request, and its cost is paid once per request rather than once per include.

  • Why does View::share('student', auth()->user()) in AppServiceProvider::boot() give the views null for a signed-in student?
    Service providers boot before the HTTP middleware pipeline runs, so the session middleware has not loaded the session yet and the guard cannot find the logged-in user. The call runs once, early, and shares null. Move it into a composer, which runs at render time after middleware, or pass the user from the controller.
  • A controller passes 'departments' and a view composer for the same view also sets 'departments'. Which value does the Blade view see?
    The composer's. Composers run immediately before the view renders, after the controller has attached its data, and `$view->with()` simply overwrites the key. A view creator is the opposite: it runs when the view is created, so a controller's later `->with('departments', ...)` wins. Shared data loses to both.

View::share is the notice pinned in every classroom before the day starts; a view composer is the porter who delivers today's handouts to one lecture hall the moment the lecture begins, every time that hall is used.

saying these in an interview costs you the question

  • View::share in boot() is the right place to share the logged-in user
  • A view composer runs once per request, however many times its view renders
  • A '*' composer is free because it only runs for top-level page views
  • Shared data overrides a key the controller passes with the same name
  • View creators and composers are aliases that run at the same moment