最近、趣味で作成しているWEBアプリでCodeIgniter 2を使っており、コア部分のソースを眺めていると環境別設定を切り分ける機構が導入されていたので少しソースを追ってみました。
結論から言えば、末端のindex.php内に定義されているENVIRONMENT定数の値をdevelopment,testing,productionのいずれかに変更するだけで、
application/configに関して、下記のような構造で環境別に管理できるようになります。development,testing,productionに関しては、任意の値に変更可能ですが、その際はディレクトリ名も一緒に変更する必要があるので注意してください。
./ `-- application `-- config |-- config.php # ENVIRONMENTに指定されたディレクトリ内に見つからなかった場合に読み込まれる。 |-- development | `-- config.php # ENVIRONMENT=developmentの時、読み込まれる。 |-- testing | `-- config.php # ENVIRONMENT=testingの時、読み込まれる。 `-- production `-- config.php # ENVIRONMENT=productionの時、読み込まれる。 |
環境別設定は別ファイルで完全に分離しておいた方がリリース毎のミスなども少なくなり良いですよね。ていうか、CodeIgniter 1を使ってた時は自前で環境設定を切り替えるshellを書いちゃってました・・・。もしかしたら1系の時からこの機構って提供されてたんでしょうか?もしかしたら1系にも同様の機構があるかも。と思い、軽くソースを追ってみたんですが、それらしいコードを見つけることができませんでした。もし、1系でもデフォルトで可能であればそれを使うようにしたいところです。
追記:2011.03.24
Change Log : CodeIgniter User Guideに2.0.1からという記載がありました。
環境を識別する定数
/index.phpの以下がまさにそれに当たります。
ENVIRONMENT定数の値をdevelopment,testing, productionに書き換えれることにより環境別の設定が反映される仕組みのようです。
/* *--------------------------------------------------------------- * APPLICATION ENVIRONMENT *--------------------------------------------------------------- * * You can load different configurations depending on your * current environment. Setting the environment also influences * things like logging and error reporting. * * This can be set to anything, but default usage is: * * development * testing * production * * NOTE: If you change these, also change the error_reporting() code below * */ define('ENVIRONMENT', 'development'); |
ENVIRONMENT定数を利用している箇所
ソースを追う前のメモとしてENVIRONMENTという文字が含まれる箇所を出しました。
この中から気になった部分について見ていきます。
find ./|xargs grep -n 'ENVIRONMENT' ./index.php:5: * APPLICATION ENVIRONMENT ./index.php:21: define('ENVIRONMENT', 'development'); ./index.php:31: switch (ENVIRONMENT) ./system/core/Config.php:88: $file_path = $path.'config/'.ENVIRONMENT.'/'.$file.EXT; ./system/core/Config.php:98: log_message('debug', 'Config for '.ENVIRONMENT.' environment is not found. Trying global config.'); ./system/core/Config.php:147: show_error('The configuration file '.ENVIRONMENT.'/'.$file.EXT.' and '.$file.EXT.' do not exist.'); ./system/core/Loader.php:885: if (file_exists($path .'config/'.ENVIRONMENT.'/'.strtolower($class).EXT)) ./system/core/Loader.php:887: include_once($path .'config/'.ENVIRONMENT.'/'.strtolower($class).EXT); ./system/core/Loader.php:890: elseif (file_exists($path .'config/'.ENVIRONMENT.'/'.ucfirst(strtolower($class)).EXT)) ./system/core/Loader.php:892: include_once($path .'config/'.ENVIRONMENT.'/'.ucfirst(strtolower($class)).EXT); ./system/core/Common.php:211: $file_path = APPPATH.'config/'.ENVIRONMENT.'/config'.EXT; ./system/database/DB.php:31: $file_path = APPPATH.'config/'.ENVIRONMENT.'/database'.EXT; ./system/database/DB.php:35: log_message('debug', 'Database config for '.ENVIRONMENT.' environment is not found. Trying global config.'); |
エラー出力の切り分け
/* *--------------------------------------------------------------- * ERROR REPORTING *--------------------------------------------------------------- * * Different environments will require different levels of error reporting. * By default development will show errors but testing and live will hide them. */ switch (ENVIRONMENT) { case 'development': error_reporting(E_ALL); break; case 'testing': case 'production': error_reporting(0); break; default: exit('The application environment is not set correctly.'); } |
環境別設定ファイルの読込
下記は、system/core/Config.phpの抜粋です。
/** * Load Config File * * @access public * @param string the config file name * @param boolean if configuration values should be loaded into their own section * @param boolean true if errors should just return false, false if an error message should be displayed * @return boolean if the file was loaded correctly */ function load($file = '', $use_sections = FALSE, $fail_gracefully = FALSE) { $file = ($file == '') ? 'config' : str_replace(EXT, '', $file); $loaded = FALSE; foreach ($this->_config_paths as $path) { $file_path = $path.'config/'.ENVIRONMENT.'/'.$file.EXT; if (in_array($file_path, $this->is_loaded, TRUE)) { $loaded = TRUE; continue; } if ( ! file_exists($file_path)) { log_message('debug', 'Config for '.ENVIRONMENT.' environment is not found. Trying global config.'); $file_path = $path.'config/'.$file.EXT; if ( ! file_exists($file_path)) { continue; } } include($file_path); |
$this->load->configなどで通常はapplication/config配下のファイルを読み込みますが、application/config/[ENVIRONMENT]/に読込対象の設定ファイルが存在すれば、読み込み、存在しなければ、通常のディレクトリである、application/config/から読み込むようになっています。これは、database.phpやconfig.phpなど予めCodeIgniterに含まれる設定ファイルでなくても、独自に定義した設定ファイルについても環境別ディレクトリ配下に配置すればそれを読み込むように出来ます。
下記は、config.phpを読み込む際の
./ `-- application |-- cache `-- config |-- config.php # ENVIRONMENTに指定されたディレクトリ内に見つからなかった場合に読み込まれる。 |-- development | `-- config.php # ENVIRONMENT=developmentの時、読み込まれる。 |-- testing | `-- config.php # ENVIRONMENT=testingの時、読み込まれる。 `-- production `-- config.php # ENVIRONMENT=productionの時、読み込まれる。 |
ライブラリ初期化パラメータの環境別切り分け
$this->load->libraryで読み込む際に第二引数に指定した値をライブラリの初期化時のパラメータを渡す事ができますが、何も指定しなかった場合、application/config配下に配置されているライブラリと同名のphpファイル内に定義された$config変数を初期化時のパラメータとして渡す事ができます。コレについてもconfigを読み込む際の条件が適用され、環境別の設定内容をライブラリの初期化時のパラメータとして渡す事ができます。
下記が、system/core/Loader.phpの該当部分のコードになります。CodeIgniter 2.0.1の時点では、Loader#_ci_init_classはLoader#libraryメソッド経由でのみ呼ばれているようです。
/** * Instantiates a class * * @access private * @param string * @param string * @param string an optional object name * @return null */ function _ ci_init_class($class, $prefix = '', $config = FALSE, $object_name = NULL) { // Is there an associated config file for this class? Note: these should always be lowercase if ($config === NULL) { // Fetch the config paths containing any package paths $config_component = $this->_ci_get_component('config'); if (is_array($config_component->_config_paths)) { // Break on the first found file, thus package files // are not overridden by default paths foreach ($config_component->_config_paths as $path) { // We test for both uppercase and lowercase, for servers that // are case-sensitive with regard to file names. Check for environment // first, global next if (file_exists($path .'config/'.ENVIRONMENT.'/'.strtolower($class).EXT)) { include_once($path .'config/'.ENVIRONMENT.'/'.strtolower($class).EXT); break; } elseif (file_exists($path .'config/'.ENVIRONMENT.'/'.ucfirst(strtolower($class)).EXT)) { include_once($path .'config/'.ENVIRONMENT.'/'.ucfirst(strtolower($class)).EXT); break; } elseif (file_exists($path .'config/'.strtolower($class).EXT)) { include_once($path .'config/'.strtolower($class).EXT); break; } elseif (file_exists($path .'config/'.ucfirst(strtolower($class)).EXT)) { include_once($path .'config/'.ucfirst(strtolower($class)).EXT); break; } } } } |
ユーザガイドを読んでいないだけかもしれませんが、CodeIgniterのソースはさほど大きくなく、読むのに苦労しないので興味のある方は是非一度読んでみてはいかがでしょうか。