71

How can I in Laravel 5 make global variable which will be available in all Blade templates?

Limon Monte
  • 52,539
  • 45
  • 182
  • 213

9 Answers9

103

Option 1:

You can use view::share() like so:

<?php namespace App\Http\Controllers;

use View;

//You can create a BaseController:

class BaseController extends Controller {

    public $variable1 = "I am Data";

    public function __construct() {

       $variable2 = "I am Data 2";


       View::share ( 'variable1', $this->variable1 );
       View::share ( 'variable2', $variable2 );
       View::share ( 'variable3', 'I am Data 3' );
       View::share ( 'variable4', ['name'=>'Franky','address'=>'Mars'] );
    }  

}

class HomeController extends BaseController {

    //if you have a constructor in other controllers you need call constructor of parent controller (i.e. BaseController) like so:

    public function __construct(){
       parent::__construct();
    }

    public function Index(){
      //All variable will be available in views
      return view('home');
    }

}

Option 2: Use a composer:

  1. Create a composer file at app\Composers\HomeComposer.php

NB: create app\Composers if it does not exists

<?php namespace App\Composers;

class HomeComposer
{

    public function compose($view)
    {
        //Add your variables
        $view->with('variable1',      'I am Data')
             ->with('variable2',      'I am Data 2');
    }
}

Then you can attached the composer to any view by doing this

<?php namespace App\Http\Controllers;

use View;

class HomeController extends Controller{


    public function __construct(){

        View::composers([
            'App\Composers\HomeComposer'  => ['home'] //attaches HomeComposer to home.blade.php
        ]);

    }

    public function Index(){
        return view('home');
    }

}

Option 3: Add Composer to a Service Provider, In Laravel 5 I prefer having my composer in App\Providers\ViewServiceProvider

  1. Create a composer file at app\Composers\HomeComposer.php

  2. Add HomeComposer to App\Providers\ViewServiceProvider

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use View;
use App\Composers\HomeComposer;
use Illuminate\Support\Facades\Blade;

class ViewServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
 *
     * @return void
     */
    public function register()
    {
        //
    }

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        //add to all views
        view()->composer('*', HomeComposer::class);
        //add to only home view 
        //view()->composer('home', HomeComposer::class);
    }
}
Emeka Mbah
  • 16,745
  • 10
  • 77
  • 96
  • 1
    Your response really helped me with Option 1, although what if you're trying to access `$user = Auth::user();` and pass the $user variable to all of the blade templates including the header and the content part? I tried this by putting the $user variable in the BaseController and then sharing it, but if I var_dump $user I get a bunch of protected values in the array. Basically I want to be able to access all of the auth user variables throughout the app in all templates and views. Seems simple but have spent hours trying to figure it out. – Chad Priddle Aug 31 '15 at 15:22
  • 1
    Actually this worked: `= $user['name']; ?>` but this didn't work: `{{ $user->name }}` – Chad Priddle Aug 31 '15 at 15:27
  • @Chad Priddle This should work for an array `{{ $user['name'] }}` while this works for an object `{{ $user->name }}` – Emeka Mbah Sep 03 '15 at 11:41
  • For option 1 I get: `Class 'App\Http\Controllers\View' not found` – Kokodoko Mar 09 '19 at 12:22
  • The recommended way should be : a service provider with View::share. Note that the composer "*" option is called for every template loaded : if you do a DB call, it will be done for every views and subviews ! – Neekobus Mar 19 '20 at 08:26
40

Create a new Service Provider as suggested in here

Add your new Service Provider to the configuration file (config/app.php).

In the boot method of your new Service Provider use:

View::share( 'something_cool', 'this is a cool shared variable' );

Now you are ready to use $something_cool in all of your views.

Hope this helps.

castis
  • 8,154
  • 4
  • 41
  • 63
Nicolas
  • 884
  • 5
  • 13
  • 1
    plus, it's the ultimate solution for **variables used on multiple occasionson a 503 page after `artisan down`.** Injecting an app's version string as cache buster parameter or having it displayed in the footer whilst updating is a chore with other solutions. (using an env variable for that would probably be the cleanest solution though) – luchaos Mar 30 '16 at 22:36
  • 2
    this is a better solution than the approved answer – Christophvh Aug 12 '16 at 13:17
  • I think the main difference is that the user is asking on how to have a *global* variable available in all templates. With the accepted solution the user needs to remember to extend BaseController and call parent::construct and with the ViewComposer solution he needs to call View::composers in every controller construct method in order to make the variables available. – Nicolas Aug 23 '16 at 11:37
  • 1
    This should be chosen as an answer! – lewis4u Oct 27 '16 at 08:32
  • 1
    This is best I answer and easy to use. – Ariful Islam Aug 09 '21 at 11:22
18

Searching for solution of the same problem and found the best solution in Laravel documentation. Just use View::share in AppServiceProvider like this:

View::share('key', 'value');

Details here.

sha-1
  • 1,954
  • 2
  • 17
  • 23
  • 2
    Did not work for Auth::user() - in that state it was null - however the place is correct, I just needed to add it through composer `View::composer('*', function($view) { $view->with('current_user', Auth::user()); }` instead of the share. – jave.web Oct 08 '19 at 19:35
11

You can do this with view composers. View composers are executed when a template is loaded. You can pass in a Closure with additional functionality for that view. With view composers you can use wildcards. To make a view composer for every view just use a *.

View::composer('*', function($view)
{
    $view->with('variable','Test value');
});

You can also do this without a closure as you can see in the docs.

View::composer('*', 'App\Http\ViewComposers\ProfileComposer');

The profile composer class must have a compose method.

View composers are executed when a view is rendered. Laravel has also view creators. These are executed when a view is instantiated.

You can also choose to use a BaseController with a setupLayout method. Then every view which you will load is loaded through the setupLayout method which adds some additional data. However, by using view composers you're pretty sure that the code is executed. But with the BaseController approach you've more flexibility because you can skip the loading of the extra data.

EDIT: As mentioned by Nic Gutierrez you can also use view share.

ArjanSchouten
  • 1,360
  • 9
  • 23
  • The difference between this and `view()->share` is that this is only run when a view is used - but with `view()->share` it's ran no matter what - you might be returning some JSON in an API call for example - which doesn't use a view. – Petecoop Mar 02 '16 at 13:54
4

Also, you can do this in the Route.php file:

view()->share('variableName', $variable);
Limon Monte
  • 52,539
  • 45
  • 182
  • 213
Jodeveloper8
  • 104
  • 1
  • 5
2

I would rather use middleware with the view() facade helper. (Laravel 5.x)

Middleware is easier to mantain and does not make a mess in the controllers class tree.

Steps

Create the Middleware

/app/Http/Middleware/TimezoneReset.php

To create a middleware you can run php artisan make:middleware GlobalTimeConfig

share() the data you need shared

 <?php

    namespace App\Http\Middleware;

    use Closure;

    class GlobalTimeConfig
    {
        /**
         * Handle an incoming request.
         *
         * @param  \Illuminate\Http\Request  $request
         * @param  \Closure  $next
         * @return mixed
         */
        public function handle($request, Closure $next)
        {
            $time_settings = [
                'company_timezone' => 'UTC',
                'company_date_format' => 'Y-m-d H:i:s',
                'display_time' => true,
            ];

            view()->share('time_settings', $time_settings);

            return $next($request);
        }
    }

Register the newly created middleware

Add the middleware to your middleware route group as per example below

/app/Http/Kernel.php

    protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\GlobalTimeConfig::class,
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            // \Illuminate\Session\Middleware\AuthenticateSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],

        'api' => [
            'throttle:60,1',
            'bindings',
        ],
    ];

Access data from templates

Access the data from any template with the given key in the View::share() method call

eg.:

    Company timezone: {{ $time_settings['company_timezone'] }}

EDIT: Nic Gutierrez's Service Provider answer might be a better (or the best) solution.

Gabi Dj
  • 645
  • 6
  • 15
1

and you can give array not just View::share('key', 'value'); can put array like View::share(['key'=>'value','key'=>'value'])

Ehab Elzeny
  • 234
  • 4
  • 6
-2

You can add in Controller.php file:

use App\Category;

And then:

class Controller extends BaseController {
     public function __construct() {
        $categories = Category::All();
        \View::share('categories', $categories);
     }
}
-7

you can flash it into the session, you can define it in the .env file (static vars)

Jeff
  • 151
  • 1
  • 1
  • 3