Ever been in a situation where you have to share some data with multiple views? I have. If you are passing it in every controller pretty soon it will get very messy since you end up duplicating same code in multiple controllers which is against the DRY principle. Let’s learn about view composer provider by Laravel which eliminate this issue and gives you a single place to attach your logic for view data.
What is View Composer?
You can think View composer as a callback which will run when an attached view is rendered, here you can run some code and pass data when a view is requested.
For example, If you have a nav
view in sidebar view which needs a list of menu items from the database, you bind a callback to partials.nav
which fetch the data from DB and show it. So no matter in how many places you need this view partial you can just include without worrying about passing any data item through a controller, this view will be composed of with data by View Composer.
Passing data into View
You can pass data into Laravel views using one of following options.
Pass Data using with
method on view.
public function index()
{
$nav = Nav::active()->get();
return view('partials.nav')->with('nav', $nav);
}
Pass data as the second argument in the view()
helper.
public function index()
{
$nav = Nav::active()->get();
return view('partials.nav', ['nav' => $nav]);
}
Pass data as with compact
method which turns variable into a key-value array.
public function index()
{
$nav = Nav::active()->get();
return view('partials.nav', compact('nav'));
}
It’s all good, but things get tricky when we find yourself doing this in every controller method which needs the menu, to solve this kind of situation we can use View Composer.
Setup View Composer
Let’s see an example, where you want to show some navigation menu items in the sidebar, it will be a partial view which you can use in many places throughout the app.
By default laravel don’t have a directory for View Composer it’s up to you. Laravel recommends to create an app/Http/ViewComposers
folder to store your view composers.
Create NavComposer
This composer will simply attach the menu items to view from database.
namespace App\Http\ViewComposers;
use App\Nav;
class NavComposer
{
public function compose($view)
{
$view->with('menu', Nav::all());
}
}
Now run the php artisan make:provider ComposerServiceProvider
to create the our view composer provider in app/Providers
folder.
Register Service Provider
Like any other provider add the ComposerServiceProvider
class to config/app.php
array for providers so that laravel is able to resolve it.
'providers' => [
...
App\Providers\ComposerServiceProvider::class,
]
In order to make composer work, we will need to register it in ComposerServiceProvider@boot
method.
namespace App\Providers;
use App\Nav;
use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;
class ComposerServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* @return void
*/
public function boot()
{
// You can use a class for composer
// you will need NavComposer@compose method
// which will be called everythime partials.nav is requested
View::composer(
'partials.nav', 'App\Http\ViewComposers\NavComposer'
);
// You can use Closure based composers
// which will be used to resolve any data
// in this case we will pass menu items from database
View::composer('partials.nav', function ($view) {
$view->with('menu', Nav::all());
});
}
}
You will need to use one of above option to compose the view, first is to use a dedicated class NavComposer
with compose method, or you can use a Closure which is most ideal in most of case since you should already have a repository to get the data from database.
Make sure to provide full path of your view in View::composer('partials.nav', handler)
to resolve it, in this case I have nav.blade.php
inside resoources/views/partials
folder.
Attach a Composer to multiple views
If same data is needed in multiple views you can pass views as array View::composer(['partials.nav', 'partials.top-nav'], handler)
this will bind it to both views.
And you can also pass *
wildcard to make this data available in all views.
View::composer('*', function ($view) {
$view->with('menu', Nav::all());
});
View Creators
View creators are similar to composer with slight difference, they are executed immediately after the view is instantiated instead of waiting until the view is about to render. You can use theme exactly the same way as view composer but you will need to call creator method instead of composer.
View::creator('partials.nav', function ($view) {
$view->with('menu', Nav::all());
});
Conclusion
View composer can make your views more independent since data needed by a view can be bind directly without need of passing it from controller. This will make your code cleaner and maintainable in long run. I hope it helps and let me know if you need any help.
View::share(‘data’, ‘value’);
Sharing data with all views makes the site slightly slower since it will visit the the database one time every page reload even if you didn’t need that variable, but Sharing the data with partial views TRUE a better idea. Thanks Saqueib Ansari for making that clear.