Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

polarcubs's avatar

How to add ServiceProviders and Facades to only development configuration

How to add ServiceProviders and Facades to only development configuration?

Currently I only add them to app.php together.

0 likes
15 replies
rodrigo.pedra's avatar

Note that your config/app.php file practically has only a return [ ... ]; statement. Modify this file as the following:

<?php
    // instead of returning, cache the configuration in a variable
    $results = [

        /*
        |--------------------------------------------------------------------------
        | Application Debug Mode
        |--------------------------------------------------------------------------
    ... keep all the the same inside here */
    
    ];

    // Add this check for the conditional providers and other configurations
    if ( env( 'APP_ENV' ) === 'local' )
    {
        $results['providers'][] = 'Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider';
    }

    // return it
    return $results;
2 likes
polarcubs's avatar

Ah thank you jonathan. Now a side question.

My local/config/app.php now looks like this:

<?php

return array(

    /*
    |--------------------------------------------------------------------------
    | Application Debug Mode
    |--------------------------------------------------------------------------
    |
    | When your application is in debug mode, detailed error messages with
    | stack traces will be shown on every error that occurs within your
    | application. If disabled, a simple generic error page is shown.
    |
    */

    'debug' => true,

    'providers' => append_config(array(
        'Way\Generators\GeneratorsServiceProvider',
        'Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider',
        'Barryvdh\Debugbar\ServiceProvider',
    ))

);

And my composer.json require-dev looks like this

    "require-dev": {
        "way/generators": "~2.0",
        "barryvdh/laravel-ide-helper": "~1.11",
        "barryvdh/laravel-debugbar": "~1.8",
        "phpunit/phpunit": "4.5.*",
        "laracasts/testdummy": "~2.0"
    },

However when I run composer update, everything still get installed on the production server including those on require-dev. How do I only install those on require? Thank you.

1 like
adamwathan's avatar

@polarcubs: You can skip dev dependencies by using composer update --no-dev or composer install --no-dev.

1 like
polarcubs's avatar

Hi @adamwathan . Thank you I just pushed the new code to my production site. However I'm seeing this error

remote:   - Installing bugsnag/bugsnag-laravel (v1.4.2)
remote:     Downloading: 100%
remote: 
remote: Writing lock file
remote: Generating autoload files
remote: 
remote: 
remote:                                                                 
remote:   [InvalidArgumentException]                                    
remote:   There are no commands defined in the "ide-helper" namespace.  
remote:                                                                 
remote: 
remote: 
remote: Script php artisan ide-helper:generate handling the post-update-cmd event returned with an error
remote: 
remote: 
remote:                                                                     
remote:   [RuntimeException]                                                
remote:   Error Output:                                                     
remote:                                                                     
remote:     [InvalidArgumentException]                                      
remote:     There are no commands defined in the "ide-helper" namespace.   

This confuses me as I have shifted ide-helper to require-dev in composer and it's service provider to config/local/app.php

Any tips on resolving this?

dberry's avatar

@adamwathan, you moved the service provider to only load when in development, but.... you've added php artisan ide-helper:generate to your composer.json file. So it's trying to run the command, but the package isn't there.

I personally never run composer update on a production server. composer install only. running composer update can lead you to some mixed results.

polarcubs's avatar

Hi @dberry, just curious is there a hook for post-update only for dev or without dev?

dberry's avatar

@polarcubs to my knowledge, no there is no way to to do that using the composer hooks.

What you could do and something I've done in the past, is create an artisan command that runs during the update hook in composer. This command checks the env, if it's development, then it runs the scripts. So instead of adding php artisan ide-helper:generate to the composer.json file, I'd add it to the artisan update script that I create.

if (app()->environment('local')) {
   // run commands
   $this->call('php artisan ide-helper:generate')
}

That is only an example and I'm not even sure if those method names are correct.

dberry's avatar

So something as simple as this

<?php namespace App\Console\Commands;

use Illuminate\Console\Command;

class ComposerUpdateScripts extends Command {

    /**
     * The console command name.
     *
     * @var string
     */
    protected $name = 'app:update';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Command description.';

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function fire()
    {
        if ($this->laravel->environment('local')) {
            $this->call('php artisan ide-helper:generate');
            $this->call('php artisan ide-helper:meta');
        }
    }

}

Then in your composer.json

"post-update-cmd": [
    "php artisan clear-compiled",
    "php artisan app:update",
    "php artisan optimize"
],
progmars's avatar

Alternative to creating custom Artisan command would be to skip the "scripts" altogether when building production builds (or any build without dev dependencies). Your customized build script should do everything required instead of relying on those "script" commands. So, your custom build script would look like:

... some preparation code...
 composer install --no-dev --no-scripts
... notice - "install" and not "update", update is dangerous because it will bring in new versions of packages which you haven't tested to work fine in your app...
... some other commands, maybe the ones from composer.json "scripts" section - pick what you need...
... some cleanup - delete .git folders, test folders etc. - everything you would want to get rid of before deploying the build to your server...
derekmcwhinnie's avatar

Add this to AppServiceProvider....

public function register ()
    {
        //register the service providers for local environment
   
        //Update 2016-04-13
        // FIXME if ( $this->app->isLocal() ) // Bug in isLocal(), method call is case sensitive
        // 'local'=true, 'Local', 'Local', 'LOCAL' = false.
        if (strtoupper($this->app->environment()) == 'LOCAL')
        {
            if ( ! empty( $providers = config( 'app.dev_providers' ) ) )
            {
                foreach ( $providers as $provider )
                {
                    $this->app->register( $provider );
                }
            }

            if ( ! empty( $aliases = config( 'app.dev_aliases' ) ) )
            {
                foreach ( $aliases as $alias => $facade )
                {
                    $this->app->alias( $alias, $facade );
                }
            }
        }
}

Add this to config.app

  'dev_providers' => [
        /*
         * Application Service Providers for development only...
         */
        Somedev\SomePackage\SomePackageServiceProvider::class,
    ],
  'dev_aliases' => [
        /*
         * Aliases to be loaded in development only...
         */
        'DevAlias'      => SomePackage\Facades\AliasClass::class,
    ],

We can define service providers in config.app as usual but know they will only be registered/loaded when the environment is development/local. So when you do a "composer update --no-dev" to clear out dev packages then your code won't fail thereafter when trying to load a service provider that is no longer there (unless you forget to change the environment).

I've looked at alot of solutions to this problem and the above is a mixture of then all. Some great ideas out there and all I've done is brought them together to keep it all Laravesque.

Hope it helps someone.

6 likes
eblanshey's avatar

For anyone else bashing their heads trying to get Facades registered using $this->app->alias( $alias, $facade );, for Laravel 5.3 you have to use AliasLoader::getInstance()->alias($alias, $facade); instead.

Please or to participate in this conversation.