The Laravel 5.1 documentation’s approach to sharing data with every view works for most circumstances, but I recently learned of a case where it breaks things: running artisan.
The documented approach to sharing data with all views tells us to add code to AppServiceProvider->boot()
:
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
view()->share('key', 'value');
}
}
This approach is fine, for certain values.
view()->share('siteName', 'Banana Bill's Boat Boutique');
````
Literal values won't be a problem.
```php
view()->share('currentUser', Auth::user());
Here, if someone’s logged in, Auth:user()
will be an instance of the User
model. If not, it’ll be null. No problem here either.
view()->share('openingHours', OpeningHours::currentHours());
Here’s our problem. We’re asking the OpeningHours
model to get the current opening hours. And most of the time, this will work. However, if you haven’t run your migrations yet, your pages will give you an SQL error saying the opening_hours table is missing.
And so you get the hint and run your migrations to create the table. php artisan migrate
…
…and you get the same error. You say to the computer “I’m trying to make the table right now! Lay off!”. But no dice, you continue to get the same error.
The issue here is that everything in AppServiceProvider->boot()
runs even when you run artisan commands. It’s not normally an issue, but if you’re a new developer installing a project on your dev machine for the first time, this could really throw you.
Create a new service provider and have that create a View Composer for us instead.
In the example above, we’d comment out our share command, and we’ll get the use of artisan
back:
php artisan make:provider ViewComposerServiceProvider
This will create /app/Providers/ViewComposerServiceProvider.php
Add the new service provider to /config/app.php
‘s providers
array:
'providers' => [
...
App\Providers\RouteServiceProvider::class,
...
]
And then in ViewComposerServiceProvider->boot()
create a view composer:
public function boot()
{
View::composer('*', function($view)
{
$view->with('openingHours', OpeningHours::currentHours());
});
}
ViewComposerServiceProvider->boot()
will still be called when you invoke artisan
, but OpeningHours::currentHours() will only be called when you a view is created. Now your app won’t break during a first time deployment. Hooray!
TL;DR view()->share() with models works great until your database isn’t there. Use view composers instead.
]]>