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

andyjameswhite's avatar

Sharing URL DI across multiple view components.

I'll try and explain my issue with a simplified example.

  1. My app has "Levels" and "Topics".
  2. Inside the web.php I use DI to pass the releveant id (slug in my case) to the Controller method. So my urls look like
  • exampleapp.com
  • exampleapp.com/app/{level}
  • exampleapp.com/app/{level}/{topic}
  1. Then the controller happily picks up the injected object and passes it on to the view

However... in the resources part of the application the views are split up into many components, partials and so on and therefore the objects injected are available in the main view loaded from the controller but not in the components

I understand these components/partials are separate views and I know that using a service provider along with View::creator and View::share I can share data into some or all of these. (I am doing this with a variable named all_levels. Which unsurprisingly gets all Levels.)

However I would like to use the AppServiceProvider (or some other solution) to pass the Object Data which is available from the URL to some of the views as it is done in the controller.

This would be useful say in Breadcrumbs or Navigation to highlight which page the user is on.

Soutions I've Tried

I've tried 2 different solutions, which both feel very messy

A) Use request()->path() in the ServiceProvider to get the appropriate parts and query to get the Level and Topic and pass to selected views using View::creator and View::share. Pretty messy in the provider (especially my app is significantly more complicated than the example).

B) Pass the required data via a Component Attribute on the tag and use a __construct in the View/Component/BaseLayout.php Feels unpleasant as each blade for each page must include this attribute.

I feel like there is some tidy and best practice Laravel way to achieve this, which I am missing.

Can anyone help?

web.php

Route::middleware('auth')->group(function () {
    
    // Level pages
    Route::prefix('app')->name('levels.')->group(function () {
        Route::get('{level}', [LevelsController::class, 'show'])->name('show');
        
        // Topic pages
        Route::name('topics.')->group(function () {
            Route::get('{level}/{topic}', [TopicsController::class, 'show'])->name('show');

TopicsController.php

    public function show(Level $level, Topic $topic)
    {

        return view(
            'pages.topics.show',
            [
                'level' => $level,
                'topic' => $topic
            ]
        );
    }

AppServiceProvider.php

use App\Models\Level;

class AppServiceProvider extends ServiceProvider
{
    public function register()
    {
       
    }

    public function boot(Level $level)
    {
        View::creator(['*'], function ($view) {
            $all_levels = Cache::rememberForever('all_levels', function () {
                return Level::all();
            });
			
            View::share('all_levels', $all_levels);
			
        });
    }
}
0 likes
5 replies
tisuchi's avatar
tisuchi
Best Answer
Level 70

@andyjameswhite What if in a View Composer is a class that binds data to a view. You can create a new class for example ViewComposer and register it in the AppServiceProvider boot method.

class ViewComposer {
    public function compose(View $view) {
        $level = request()->route('level');
        $topic = request()->route('topic');
        $view->with(compact('level', 'topic'));
    }
}

Then in the AppServiceProvider boot method, you can register the View Composer with the views you want to share the data with.

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        View::composer(['pages.topics.show', 'partials.navigation'], ViewComposer::class);
    }
}
1 like
webrobert's avatar

Not sure I follow

However I would like to use the AppServiceProvider (or some other solution) to pass the Object Data which is available from the URL to some of the views as it is done in the controller.

But that’s what a controller is for. You pass the required data to the view. And it’s perfectly illustrated in your topic controller.

The problem with breadcrumbs is assumptive. The path to any given page is not the same. So you have to build paths for each url. Even writing this that sounds silly. But it’s been my experience. Also look at some breadcrumb packages.

To handle blade files I don’t know your structure but I will sometimes use a dynamic component based on the model. And it doesn’t have to be dynamic component . Other times I pass the model into the component or use the model name to load a partial.

and for current page I also use named routes.

I hope I’m not off in the weeds.

andyjameswhite's avatar

@webrobert Understand your points on the practicality of things, it was a conceptual thing I was completely missing about ViewComposers

1 like
andyjameswhite's avatar

Thanks guys,

@tisuchi has the solution I was after, a massive gap in my knowledge regarding View Composers, I had no idea you could pick up the data here using request()->route('level'), which doesn't appear to work in the AppServiceProvider;

A couple of small points for anyone else using this solution

  1. use Illuminate\View\View; at the top of the ViewComposer class file
  2. I'll end up putting this code in a new ViewServiceProvider

Please or to participate in this conversation.