Currently, I’m working on my first Laravel package. So, it was time to dive into the wonderful world of the service container and service providers.
Laravel has some great docs about, but I wanted to see some real-world examples for myself. And what better way than to have a look at the packages that you already depend on?
This post details the different things that a service provider can be used for, each taken from a real open-source project. I’ve linked to the source of each example.
Additions: 15/11: defining an alias. 15/11: registering sub-dependencies. 16/11: registering middleware. 16/11: registering an event handler.
Docs
First of, you should probably have a look at the docs for the service container, service providers and package development.
You can register a service provider by adding it to the providers
array in config/app.php
like so:
'providers' => [
// Other Service Providers
App\Providers\MyCustomServiceProvider::class,
],
Now, let’s look at some common scenario’s that you can find in service providers.
Binding
Common binding. Taken from spatie/laravel-glide.
public function register()
{
$this->app->bind('laravel-glide-image', function () {
return new GlideImage();
});
}
Singleton binding. Taken from cviebrock/eloquent-sluggable.
public function register()
{
$this->app->singleton(SluggableObserver::class, function ($app) {
return new SluggableObserver(new SlugService(), $app['events']);
});
}
Instance binding. Taken from spatie/laravel-googletagmanager.
public function register()
{
$googleTagManager = new GoogleTagManager(config('googletagmanager.id'));
if (config('googletagmanager.enabled') === false) {
$googleTagManager->disable();
}
$this->app->instance('Spatie\GoogleTagManager\GoogleTagManager', $googleTagManager);
}
Define an alias. Taken from graham-campbell/htmlmin.
public function register()
{
$this->app->alias('htmlmin.css', CssMinifier::class);
}
Register and alias for a sub-dependency. Found on http://stackoverflow.com/a/22749871/404423.
public function register()
{
$this->app->register('LucaDegasperi\OAuth2Server\OAuth2ServerServiceProvider');
$this->app->alias('AuthorizationServer', 'LucaDegasperi\OAuth2Server\Facades\AuthorizationServerFacade');
$this->app->alias('ResourceServer', 'LucaDegasperi\OAuth2Server\Facades\ResourceServerFacade');
}
Resources
The following examples are about publishing resources so they can be used throughout the application.
Configuration. Taken from mcamara/laravel-localization.
public function boot()
{
$this->publishes([
__DIR__ . '/../../config/config.php' => config_path('laravellocalization.php'),
], 'config');
}
public function register()
{
$packageConfigFile = __DIR__ . '/../../config/config.php';
$this->mergeConfigFrom(
$packageConfigFile, 'laravellocalization'
);
}
Views. Taken from laracasts/flash.
public function boot()
{
$this->loadViewsFrom(__DIR__ . '/../../views', 'flash');
$this->publishes([
__DIR__ . '/../../views' => base_path('resources/views/vendor/flash')
]);
}
Commands. Taken from jeroen-g/laravel-packager.
protected $commands = [
'JeroenG\Packager\PackagerNewCommand',
...
'JeroenG\Packager\PackagerTestsCommand',
];
public function register()
{
$this->commands($this->commands);
}
Migrations. Taken from: waavi/translation.
public function boot()
{
$this->publishes([
__DIR__ . '/../database/migrations/' => database_path('migrations'),
], 'migrations');
}
Translations. Taken from: laravelrus/localized-carbon.
public function boot()
{
$this->loadTranslationsFrom(__DIR__.'/../../lang', 'localized-carbon');
$this->publishes([
__DIR__.'/../../lang' => base_path('resources/lang'),
]);
}
Middleware. Taken from: barryvdh/laravel-cors.
public function boot()
{
$this->app['router']->middleware('cors', HandleCors::class);
}
Others
Defer loading. Register bindings only if they are requested. Can only be used for registering bindings. Taken from antonioribeiro/google2fa.
protected $defer = true;
public function register()
{
$this->app->bind(
'PragmaRX\Google2FA\Contracts\Google2FA',
'PragmaRX\Google2FA\Google2FA'
);
}
public function provides()
{
return ['PragmaRX\Google2FA\Contracts\Google2FA'];
}
Register an event handler. Taken from sentry/sentry-laravel.
public function boot()
{
...
$this->bindEvents($this->app);
...
}
protected function bindEvents($app)
{
$handler = new SentryLaravelEventHandler($app['sentry'], $app['sentry.config']);
$handler->subscribe($app->events);
}
Set event listener. Taken from: jenssegers/date.
public function boot()
{
$this->app['events']->listen('locale.changed', function () {
$this->setLocale();
});
$this->setLocale();
}
protected function setLocale()
{
$locale = $this->app['translator']->getLocale();
Date::setLocale($locale);
}
Adding a Blade directive. Taken from spatie/laravel-blade-javascript.
public function boot()
{
Blade::directive('javascript', function ($expression) {
$expression = $this->makeBackwardsCompatible($expression);
return "<?= app('\Spatie\BladeJavaScript\Renderer')->render{$expression}; ?>";
});
}