imJohnBon's avatar

[L5] Service provider for sharing view variables

Has anyone successfully made a service provider for sharing view variables in L5 yet? I was trying to do it with this:

namespace App\Providers;

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

class ViewServiceProvider extends ServiceProvider {

    public function boot()
    {
        View::share('currentUser', Auth::user());
    }

    public function register()
    {
        //
    }

}

And ideally, I wouldn't even want to use the facades. But I can't seem to get this to work, Auth::user() returns null even when you're logged in.

0 likes
16 replies
fenos's avatar

I personally use the class / template approach, but you can use share method too, i register them like so:

Service Provider

        use Illuminate\Contracts\View\Factory as ViewFactory;

    public function boot(ViewFactory $view)
    {
        // All view Share - (Global)
        $view->composer('*','App\Http\ViewComposer\MasterSiteComposer');

        // Top NavBar
        $view->composer('layouts.site.partials._navbar','App\Http\ViewComposer\NavBarComposer');

        // User Cover
        $view->composer('site.user.partials.profile.cover','App\Http\ViewComposer\UserCover');

        // Show Cover
        $view->composer('site.show.partials.profile.cover','App\Http\ViewComposer\ShowCover');

              // View share 
              $view->share('hello','helloString');
    }

In the class referenced in the composer method we are going to have a method called composer(View $view) and there you can pass variables to the view, example:

use Illuminate\View\View;

public function compose(View $view)
{
        $dataToBeShared = 'Hello';

        $view->with('variable', $dataToBeShared); // $variable will be the shared data in your view
}
1 like
pmall's avatar

You have to use view composers to share view logic. And register them in a service provider.

christopher's avatar

I solved it like it is descriped in the doc and with the help from @bestmomo :) :

App/Providers/ComposerServiceProvider.php

<?php
namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Contracts\View\Factory as ViewFactory;

class ComposerServiceProvider extends ServiceProvider {

    /**
     * Register bindings in the container.
     *
     * @return void
     */
    public function register()
    {
        $this->app->view->composers([
            'App\Http\ViewComposers\YourComposer' => 'your.view',
        ]);
    }

}

And App/Http/ViewComposers/YourComposer ( here are all Composers stored )

<?php namespace App\Http\YourComposer;

use Illuminate\Contracts\View\View;

class YourComposer {

    /**
     * Bind data to the view.
     *
     * @param  View  $view
     * @return void
     */
    public function compose(View $view)
    {
        $hello = "hello world";
        $view->with('hello', $hello);
    }

}

Now each time your view is rendered you can access the $hello variable

christopher's avatar

With view()->share is this variable globally, means i can access this variable on each view and it`s not binded to a special view ?

pmall's avatar

It is available in the view you are rendering. You are not supposed to render two views.

bestmomo's avatar

Issue is no related to view but auth. You should share in a middleware :

public function handle($request, Closure $next)
{
    view()->share('currentUser', \Auth::user());
}
1 like
christopher's avatar

Yep - But how would i do it if i want a global variable for all of my views ?

pmall's avatar

You are always rendering one view per request. The purpose of view share is to make a value available in addition to those you specify when you use View::make

1 like
bestmomo's avatar

Yes share across all views but not at the same time ;)

1 like
christopher's avatar

But for example if i write this to my ComposerServiceProvider i`m getting a Trying to get property of non-object

use Auth;
....
public function boot()
    {
        view()->share('currentUser', $user = Auth::user()->name);
    }

With a hello world variable it`s working

imJohnBon's avatar
imJohnBon
OP
Best Answer
Level 5

@bestmomo Interesting solution. Seems a little odd to put that in middleware though doesn't it? I think I managed to solve this issue by creating 2 files. First a ComposerServiceProvider which uses a wildcard to be applied to every view and not just particular views:

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Contracts\View\Factory as ViewFactory;

class ComposerServiceProvider extends ServiceProvider {

    /**
     * Register bindings in the container.
     *
     * @return void
     */
    public function boot(ViewFactory $view)
    {
        $view->composer('*', 'App\Http\ViewComposers\GlobalComposer');
    }

    public function register()
    {
        //
    }

}

And then the corresponding GlobalComposer where I share variables that should be available in all views:

namespace App\Http\ViewComposers;

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

class GlobalComposer {

    /**
     * Bind data to the view.
     *
     * @param  View  $view
     * @return void
     */
    public function compose(View $view)
    {
        $view->with('currentUser', Auth::user());
    }

}

So far so good, you see any downside in doing it this way over middleware?

7 likes
bestmomo's avatar

@imJohnBon I agree that middleware, that is to decorate the requests, is not the good place for this stuff and your solution is better. Anyway now I'd like to find a good place for this with share, maybe in base Controller.

Please or to participate in this conversation.