目次
CakePHP3 version 3.0.9 で環境ごとに設定ファイルを分ける方法について書きます。 FuelPHP だと app/config/development
などの中に 上書きする設定ファイルを記述しますね。
CakePHP3 で環境ごとに設定ファイルを作る場合にも config/development
というディレクトリを作って対処するのがいいと思います。 でも、既存のコードではできないので少し手を加えます。
ファイルを書き換えて環境ごとの設定を読み込むようにする方法
環境変数を利用し、且つ環境設定用のファイルを作成します。
bin/cake.php
が -e
オプションを受け付けるように変更します。 -e
が設定されている場合に、その値を環境変数に設定するためのスクリプトファイル(env.php
)を作成します。
ハイライトされている部分のコードを bin/cake.php
に追加します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
$minVersion = '5.4.16'; if (file_exists('composer.json')) { $composer = json_decode(file_get_contents('composer.json')); if (isset($composer->require->php)) { $minVersion = preg_replace('/([^0-9\.])/', '', $composer->require->php); } } if (version_compare(phpversion(), $minVersion, '<')) { fwrite(STDERR, sprintf("Minimum PHP version: %s. You are using: %s.\n", $minVersion, phpversion())); exit(-1); } $envPath = dirname(__FILE__).'/../config/env.php'; if ($index = array_search('-e', $argv)) { $_SERVER['CAKE_ENV'] = $argv[$index + 1]; file_put_contents( $envPath, "<?php\n\$_SERVER['CAKE_ENV'] = '".$_SERVER['CAKE_ENV']."';"); unset($argv[$index]); unset($argv[$index + 1]); array_splice($argv, count($argv)); } else { if (file_exists($envPath)) { unlink($envPath); } unset($_SERVER['CAKE_ENV']); } include dirname(__DIR__) . '/config/bootstrap.php'; exit(Cake\Console\ShellDispatcher::run($argv)); |
次に、 config/bootstrap.php
の最初で env.php
を読み込み、環境変数を設定します。
1 2 3 4 5 |
<?php $envPath = dirname(__FILE__).'/env.php'; if (file_exists($envPath)) { require $envPath; } |
そして config/bootstrap.php
に Configure::load
を追加します。
1 2 3 4 5 6 7 8 9 |
try { Configure::config('default', new PhpConfig()); Configure::load('app', 'default', false); if (isset($_SERVER['CAKE_ENV'])) { Configure::load($_SERVER['CAKE_ENV'].'/app', 'default', true); } } catch (\Exception $e) { die($e->getMessage() . "\n"); } |
env.php
は .gitignore
に入れておくのがいいと思います。
こうすることで、bin/cake xxx -e development
などとした場合には、 development
環境の設定ファイルを読み込むようになります。 また、 bin/cake server -e development
とすれば開発環境用の設定でビルトインサーバが起動します。 サーバ(Apacheなど)で環境変数 CAKE_ENV
を設定すればそれが使えます。
なぜこんなに回りくどいことをするのか
-e
オプションをつけるだけではなく、 ファイルを作成してファイルを読み込むということをやっています。 それには理由があります。
cake.php
で環境変数を設定してしまうと、 bin/cake server -e development
とサーバを起動したとき、 起動時には cake.php
が実行されるので環境変数を設定できるのですが、 http リクエスト を受けた場合はcake.php
が実行されないため環境に応じた設定ファイルを読み込むことができません。 (参考: CakePHP 3 コントローラ実行までのプロセスを追う) そこで、 cake.php
で環境変数を設定するスクリプトを作り、 リクエストを受けた際にも実行される bootstrap.php
で、 作ったスクリプト(env.php
)を実行することにしました。
解説
Configure がなにをやっているのか
設定ファイルを読み込むのは bootstrap.php
を見ると、 Configure::config
, Configure::load
が関係していそうだというのがわかります。 これらの関数をまず見てみます。
Configure
クラス は vendor/cakephp/cakephp/src/Core/Configure.php
で定義されています。
Configure::config
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
/** * Add a new engine to Configure. Engines allow you to read configuration * files in various formats/storage locations. CakePHP comes with two built-in engines * PhpConfig and IniConfig. You can also implement your own engine classes in your application. * * To add a new engine to Configure: * * ``` * Configure::config('ini', new IniConfig()); * ``` * * @param string $name The name of the engine being configured. This alias is used later to * read values from a specific engine. * @param ConfigEngineInterface $engine The engine to append. * @return void */ public static function config($name, ConfigEngineInterface $engine) { static::$_engines[$name] = $engine; } |
コメントから、エンジンを追加するメソッドだとわかります。 パラメータはひとつめが識別するためのキーとなるもの、 ふたつめがエンジンのインスタンスですね。 また、このメソッドを使って同じ名前のエンジンを2回設定すると、後に設定されたもので上書きされることもわかります。
bootstrap.php
では、 Configure::config('default', new PhpConfig());
とありましたので、 デフォルトのエンジンとして new PhpConfig()
を追加していることになります。
Configure::load
Configure::config
で設定されたエンジンを使って設定値をロードするメソッドです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
/** * Loads stored configuration information from a resource. You can add * config file resource engines with `Configure::config()`. * * Loaded configuration information will be merged with the current * runtime configuration. You can load configuration files from plugins * by preceding the filename with the plugin name. * * `Configure::load('Users.user', 'default')` * * Would load the 'user' config file using the default config engine. You can load * app config files by giving the name of the resource you want loaded. * * ``` * Configure::load('setup', 'default'); * ``` * * If using `default` config and no engine has been configured for it yet, * one will be automatically created using PhpConfig * * @param string $key name of configuration resource to load. * @param string $config Name of the configured engine to use to read the resource identified by $key. * @param bool $merge if config files should be merged instead of simply overridden * @return mixed false if file not found, void if load successful. * @link http://book.cakephp.org/3.0/en/development/configuration.html#reading-and-writing-configuration-files */ public static function load($key, $config = 'default', $merge = true) { $engine = static::_getEngine($config); if (!$engine) { return false; } $values = $engine->read($key); if ($merge) { $values = Hash::merge(static::$_values, $values); } return static::write($values); } |
ひとつめのパラメータでロードするファイルを指定します。 スラッシュで区切ればディレクトリの階層も表現できます。
ふたつめのパラメータで Configure::config
で設定したエンジンを指定してロードします。 エンジンのキーが格納される引数は、Configure::config
では $name
でしたが、 ここでは $config
です。 もしエンジンが設定されていなければ false
を返して終了です。
みっつめのパラメータで マージするか完全に上書きするかが決まります。 全環境で共通のものは1箇所に書きたいので、 追加設定を読み込む際は true
にしましょう。
以上より、 Configure::load(filepath, 'default', true)
で設定ファイルをマージできることがわかりましたね。 細かいところはすっとばして説明しているので、厳密にいうと Hash::merge
なども調べないといけませんが。
もし存在しないファイルをロードしたらどうなるか
やってみればわかるわけですが、どんな処理をやっているか見てみましょう。 bootstrap.php
と Configure::load
を合わせて見るとわかりますが、 設定ファイルは PhpConfig
のメソッド read
で読み込んでいます。 PhpConfig
は vendor/cakephp/cakephp/src/Core/Configure.php
にあります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
/** * Read a config file and return its contents. * * Files with `.` in the name will be treated as values in plugins. Instead of * reading from the initialized path, plugin keys will be located using Plugin::path(). * * Setting a `$config` variable is deprecated. Use `return` instead. * * @param string $key The identifier to read from. If the key has a . it will be treated * as a plugin prefix. * @return array Parsed configuration values. * @throws \Cake\Core\Exception\Exception when files don't exist or they don't contain `$config`. * Or when files contain '..' as this could lead to abusive reads. */ public function read($key) { $file = $this->_getFilePath($key, true); $return = include $file; if (is_array($return)) { return $return; } if (!isset($config)) { throw new Exception(sprintf('Config file "%s" did not return an array', $key . '.php')); } return $config; } |
エラーがでることがわかりますね。 $config
はコメントにもあるように過去の遺物と思われます。