Laravel service provider examples

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}; ?>";
    });
}