Conditionally Loading Service Providers in Laravel 5

Posted on March 09, 2015 | By Matt Stauffer

Warning: This post is over a year old. I don't always update old posts with new information, so some of this information may be out of date.

Since Laravel 5 flattened a lot of the environment-specific structures, much of the configuration that was once stored in different config directories for each environment has now moved into .env files.

But one that can't just live in .env is the environment-dependent loading of service providers.

On a project we're working on, we want to register our error handlers in service providers, and we want to register a different error handler depending on the environment. We have two: ProductionErrorHandler and VerboseErrorHandler, the second of which is for development environments.

Loading service providers normally

In case you're not familiar, defining normal (non-environment-specific) Service Providers happens in /config/app.php. There's a providers array there that looks a bit like this:

    'providers' => [

        /*
         * Laravel Framework Service Providers...
         */
        'Illuminate\Foundation\Providers\ArtisanServiceProvider',
        'Illuminate\Auth\AuthServiceProvider',
        'Illuminate\Bus\BusServiceProvider',
        ...
    ]

So, if your service provider should be loaded in every environment, just toss it into that array and you're good to go.

Loading service providers conditionally

However, if you want to make it conditional, you'll need to head over to /app/Providers/AppServiceProvider.php. This file is the general place you're going to want to be booting and registering anything that's not handled in another service provider, so this is a place you can go to conditionally register your service providers.

Here's what it looks like right now:

<?php namespace app\Providers;

use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }

    /**
     * Register any application services.
     *
     * This service provider is a great spot to register your various container
     * bindings with the application. As you can see, we are registering our
     * "Registrar" implementation here. You can add your own bindings too!
     *
     * @return void
     */
    public function register()
    {
        $this->app->bind(
            'Illuminate\Contracts\Auth\Registrar',
            'App\Services\Registrar'
        );
    }
}

So, let's do our switch.

    // AppServiceProvider.php

    public function register()
    {
        $this->app->bind(
            'Illuminate\Contracts\Auth\Registrar',
            'App\Services\Registrar'
        );

        if ($this->app->environment('production')) {
            $this->app->register('App\Providers\ProductionErrorHandlerServiceProvider');
        } else {
            $this->app->register('App\Providers\VerboseErrorHandlerServiceProvider');
        }
    }

$this->app->register() will set up the service provider just like adding it to config/app.php will, so its register() and boot() methods will get called at the appropriate times.

You could also use switch instead of if, or you could do your work based on other environment variables, or whatever else--but this is your current best bet to conditionally load service providers. Hope this helps!


Comments? I'm @stauffermatt on Twitter


Tags: laravel  •  laravel 5