【Laravel】composer require-devの開発、本番での切り分け

### 環境
* Laravel 5.1LTS
* Composer 1.4

### 概要
Laravelを使用していて、require-devオプションに開発用パッケージを導入する事があるかと思います。
私の環境ですと`require-dev`には以下のパッケージを記載しています

```composer.json
"require-dev": {
    "barryvdh/laravel-ide-helper": "@stable",
    "barryvdh/laravel-debugbar": "^2.3",
    "fzaninotto/faker": "~1.4",
    "mockery/mockery": "0.9.*",
    "phpunit/phpunit": "^5.3",
    "phpspec/phpspec": "~2.1"
},
```

開発用パッケージは本番環境では不要ですので、`--no-dev`オプションを付けcomposerコマンドを実行します

```
$ composer install --no-dev
```

そうするとrequire-devオプションに記載されているライブラリ自体はvendorへインストールされませんが、
ServiceProvider登録が必要なライブラリを`config/app.php`に記載している場合、Laravelの起動時にエラーとなります。

```config/app.php
'providers' => [
    Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::class,
    Barryvdh\Debugbar\ServiceProvider::class,
],
'aliases' => [
    'Debugbar'  => 'Barryvdh\Debugbar\Facade',
],
```

IdeHelperServiceProviderに関しては`composer.json`のpost-xxxx-cmdオプションで、`php artisan ide-helper`を実行するよう設計されているため、`composer install --no-dev`を実行した際にクラスが見つからずこちらもエラーになります。

```composer.json
"scripts": {
    "post-install-cmd": [
        "Illuminate\\Foundation\\ComposerScripts::postInstall",
        "php artisan ide-helper:generate",
        "php artisan ide-helper:meta",
        "php artisan optimize"
    ]

```

このような問題を解決するため以下のように対応します。

* config/app.phpに記載していたproviders, aliasesを別ファイルに分けます。  
   ※ ファイル名やディレクトリは好きに変更してください

```config/dev/app.php
'providers' => [
    'Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider',
    'Barryvdh\Debugbar\ServiceProvider',
],
'aliases' => [
    'Debugbar'  => 'Barryvdh\Debugbar\Facade',
],
```


* .envに環境変数を追加します
 
```sample.env
REQUIRE_DEV=true
```

* AppServiceProviderに以下を追記します

```app/Providers/AppServiceProvider.php
public function register()
{
    if (!env('REQUIRE_DEV', false)) {
        return;
    }

    $providers = config('dev.app.providers', []);
    foreach ($providers as $provider) {
        if (class_exists($provider)) {
            $this->app->register($provider);
        }
    }

    $aliases = config('dev.app.aliases', []);
    foreach ($aliases as $alias => $facade) {
        if (class_exists($facade)) {
            $this->app->alias($alias, $facade );
        }
    }
}
```

これでrequire-devに定義されてるパッケージは、`REQUIRE_DEV=true`の時のみロードされるようになります。
しかし、composer.jsonの"post-install-cmd"に記載した`php artisan ide-helper:generate`が実行されてしまうため、こちらも対応を行う必要があります。

artisanコマンドとして実行できるクラスを作成します。

```ComposerPostScripts.php
<?php namespace App\Console\Commands;

use Illuminate\Console\Command;

class ComposerPostScripts extends Command
{
    protected $name = 'app:update';

    protected $description = 'Command description.';

    public function handle()
    {
        if (env('REQUIRE_DEV', false)) {
            $this->call('ide-helper:generate');
            $this->call('ide-helper:meta');
        }
    }

}
```

作成したCommandクラスを`composer.json`に登録します。

```composer.json
"post-install-cmd": [
    "Illuminate\\Foundation\\ComposerScripts::postInstall",
    "php artisan app:update",
    "php artisan optimize"
],
"post-update-cmd": [
    "Illuminate\\Foundation\\ComposerScripts::postUpdate",
    "php artisan app:update",
    "php artisan optimize"
]
```

これで`composer install (update) --no-dev`を実行した時には、ide-helperのCommandは制御されます。

その他利用するrequire-devパッケージにartisanコマンド依存のものがあっても、上記の`function handle()`に追加する事で対応するができますね。

このテクニックは[Laracats](https://laracasts.com/discuss/channels/general-discussion/how-to-add-serviceproviders-and-facades-to-only-development-configuration?page=1)を参考にしました。

※ .envへ新たにキー登録をしていますが、APP_ENVがstaging, productionなどの値を使用した判定でも問題ありません。