I have started using Laravel's View Composers which come in handy when you have a navigation bar that constantly needs certain data. For example, you have an ecommerce store and you need to poll how many items a user has in their basket on pretty much every page they move onto, or you need a login/register button when a user isn't logged in and then a profile options button when they are.
You could be really lazy and add the same code/query into every single controller, which yes, that will work, but then that's not DRY (Don't Repeat Yourself). To fix this, we can complete a couple of simple steps and have one bit of code which will constantly be in use every time a certian partial is called.
If you currently have a layout/template view which has the navigation menu already written in, then you will need to move this out into a partial. Within your "resources > views" directory, you will need to create a new directory called "partials". Once done, you will need to create a "nav.blade.php" file and paste in your navigation code. It should look something like this...
<nav class="navbar navbar-default">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Brand</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li class="active"><a href="#">Link <span class="sr-only">(current)</span></a></li>
<li><a href="#">Link</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">Separated link</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">One more separated link</a></li>
</ul>
</li>
</ul>
<form class="navbar-form navbar-left" role="search">
<div class="form-group">
<input type="text" class="form-control" placeholder="Search">
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
<ul class="nav navbar-nav navbar-right">
<li><button type="button" class="btn btn-primary navbar-btn">Basket <span class="badge">0</span></button></li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
Next, in your layout or template blade, you can add...
require('partials.nav')
This will include your navigation file.
Now for setting up the View Composer, firstly we need to setup a ServiceProvider (for the sake of this tutorial I will show a example for counting a basket)...
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class ComposerServiceProvider extends ServiceProvider
{
/**
* Register bindings in the container.
*
* @return void
*/
public function boot()
{
// Using Closure based composers...
view()->composer(
'partials.nav', 'App\Http\ViewComposers\BasketComposer'
);
}
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
//
}
}
The service provider will run whenever you use the nav partial and in the next attribute, it will use your BasketComposer which should look something like this...
<?php
namespace App\Http\ViewComposers;
use Illuminate\View\View;
use Illuminate\Users\Repository as UserRepository;
use Cart;
class BasketComposer
{
/**
* The user repository implementation.
*
* @var UserRepository
*/
protected $cart;
/**
* Create a new profile composer.
*
* @param UserRepository $users
* @return void
*/
public function __construct()
{
// Dependencies automatically resolved by service container...
$this->cart = Cart::Contents();
}
/**
* Bind data to the view.
*
* @param View $view
* @return void
*/
public function compose(View $view)
{
$view->with('cart', $this->cart['result']['total_items']);
}
}
Obviously, depending on your API or personal use, your code should vary here, but you should get an idea of how this is working. Everytime we need the nav partial, the view will be rendered with our given items. This can also be passed to many views at once which makes it work really well. I also believe you can pass many different constant data sets into a single view, so you could in theory also add a user constant for log in and edit profile data.
For more information, feel free to visit Laravel's documentation on View Composers and this nice Laracasts video which helped me figure out how to use it correctly.
If you have a unique use case, please let me know and we can discuss as a community just how useful these View Composers are.
