CodeIgniter4 メモ。
CodeIgniter4 User Guide を参考にしながら、必要に応じてソースを読み解き、挙動を追って理解を深めようと思います。
Attention
2017/09/23 現在 開発版の CodeIgniter4 についての記事です。リリースまでに変更される可能性があることをご承知おきの上、お読み下さい。
使用している commit: 8eba1da1f194e5124d87cc4d3b5c75e68af1ad44
TL;DR
.env
にCI_ENVIRONMENT
を設定しない。- 環境に依存する Config 以下の設定は
.env
に設定する
環境 (Environment)
User Guide: Handling Multiple Environments
環境を CodeIgniter に伝えるには、次の二つがあります。
-
.env
ファイルに記述 - Webサーバーに環境変数を設定
- Apache であれば
SetEnv CI_ENVIRONMENT development
- nginx であれば
fastcgi_param CI_ENVIRONMENT development
- Apache であれば
この CI_ENVIRONMENT
は、下記で 定数 ENVIRONMENT
に設定されます。
protected function detectEnvironment()
{
// running under Continuous Integration server?
if (getenv('CI') !== false)
{
define('ENVIRONMENT', 'testing');
}
else
{
define('ENVIRONMENT', $_SERVER['CI_ENVIRONMENT'] ?? 'production');
}
}
CI_ENVIRONMENT
が設定されていなければ、production
として動作します。
ちなみに、getenv('CI')
の CI とは、CodeIgniter ではなく、Continuous Integration の意味ですね。framework/.travis.yml
に設定されていました。
.env
と Web サーバー、どちらが優先される?
Apache/nginx 等の Web サーバーに設定された環境変数は、PHP では $_SERVER
に格納され、使用できますが、.env
にも CI_ENVIRONMENT
を設定していた場合、どちらが優先されるのでしょう?
実際に環境変数をセットしているのは、下記の箇所です。
protected function setVariable(string $name, string $value = '')
{
list($name, $value) = $this->normaliseVariable($name, $value);
if ( ! getenv($name, true))
putenv("$name=$value");
if (empty($_ENV[$name]))
$_ENV[$name] = $value;
if (empty($_SERVER[$name]))
$_SERVER[$name] = $value;
}
$_ENV
, $_SERVER
それぞれ、その環境変数名が空だったら、値をセットするようになっています。なので、 Web サーバーの設定値が優先されます。
「.env
に書いてあるのに、環境が切り替わらない〜」 とハマらないためにも、どこで設定するかのルールを決めた方がよいでしょう。
追記
User Guide に書いてありましたね。
If the variable exists in the environment already, it will NOT be overwritten.
意訳
すでに環境変数が設定されていたら、変数は上書きしません。
追記ここまで
どの方法で CI_ENVIRONMENT
を設定するか?
ここでは、本番・ステージング・ローカル開発の3つを切り替えたいと思います。
今や仮想化、コンテナ、Infrastructure as Code があるため、本番とステージングの構成に差異は無いという前提にします。
本番 (production
)
$_SERVER['CI_ENVIRONMENT']
が設定されていなければ、production
として扱うため、何も設定しません。
本番環境は、「しなくていいことは極力しない」ほうが良いと考えています。
ステージング (staging
)
前述のとおり、本番と差はありません。ですが、後述のローカル開発環境との兼ね合いで、.env
には書きたくありません。
なので、ここは Web サーバーに任せようと思います。
.htaccess
に書くのも手ではありますが、nginx になると使えません。なので、もうサーバーの設定ファイルに書くことにします。
SetEnv CI_ENVIRONMENT development
fastcgi_param CI_ENVIRONMENT "development";
専用のサーバーを設置していると思うので、グローバルなスコープで定義してしまいます。
これらのファイルをサーバー構築時に設置するだけでよいので、最もお手軽かと。
ローカル開発 (development
)
CodeIgniter4 にはローカル開発環境のための serve
スクリプトが付属しています。
php serve
と実行すると、ビルトインサーバーを使って http://localhost:8080/ で動作します。
この時、ルータースクリプトとして、rewrite.php
を指定されており、その中で
$_SERVER['CI_ENVIRONMENT'] = 'development';
と、 CI_ENVIRONMENT が設定されています。.env
に書きたくない、というのはココにあります。
前述の
$_ENV
,$_SERVER
それぞれ、その環境変数名が空だったら、値をセットするようになっています。なので、 Web サーバーの設定値が優先されます。
を思い出して下さい。そうです、$_SERVER['CI_ENVIRONMENT']
には値がセットされているので、.env
に CI_ENVIRONMENT
を設定しても、development
となります。
仮に、.env
に CI_ENVIRONMENT = "hoge"
として serve
から起動した場合、
var_dump($_SERVER['CI_ENVIRONMENT']); // "development"
var_dump($_ENV['CI_ENVIRONMENT'] // "hoge"
という、チグハグな状態になります。作りとしては、これら二値は同じ値であることが前提と思われるので、この運用はよろしくない。
いずれの環境においても、.env
に CI_ENVIRONMENT
を設定しない
とするのが正のように思います。
設定 (Config)
User Guide: Working With Configuration Files
User Guide に従い、データベースの設定を読み出してみます
$db_config = new \Config\Database();
var_dump($db_config);
object(Config\Database)[40]
public 'filesPath' => string '/XXX/XXX/XXX/application/Database/' (length=47)
public 'defaultGroup' => string 'default' (length=7)
public 'default' =>
array (size=19)
'DSN' => string '' (length=0)
'hostname' => string 'localhost' (length=9)
'username' => string '' (length=0)
'password' => string '' (length=0)
'database' => string '' (length=0)
'DBDriver' => string 'MySQLi' (length=6)
'DBPrefix' => string '' (length=0)
'pConnect' => boolean false
'DBDebug' => boolean true
'cacheOn' => boolean false
'cacheDir' => string '' (length=0)
'charset' => string 'utf8' (length=4)
'DBCollat' => string 'utf8_general_ci' (length=15)
'swapPre' => string '' (length=0)
'encrypt' => boolean false
'compress' => boolean false
'strictOn' => boolean false
'failover' =>
array (size=0)
empty
'port' => int 3306
public 'tests' =>
array (size=19)
'DSN' => string '' (length=0)
'hostname' => string '127.0.0.1' (length=9)
'username' => string '' (length=0)
'password' => string '' (length=0)
'database' => string '' (length=0)
'DBDriver' => string '' (length=0)
'DBPrefix' => string 'db_' (length=3)
'pConnect' => boolean false
'DBDebug' => boolean true
'cacheOn' => boolean false
'cacheDir' => string '' (length=0)
'charset' => string 'utf8' (length=4)
'DBCollat' => string 'utf8_general_ci' (length=15)
'swapPre' => string '' (length=0)
'encrypt' => boolean false
'compress' => boolean false
'strictOn' => boolean false
'failover' =>
array (size=0)
empty
'port' => int 3306
protected 'registrars' => null
application/Config/Database.php
の値が取得できています。というか、クラスまんまですね。
User Guide によれば、自作の設定ファイルを作ることができるそうです。以下 User Guide から引用。
<?php namespace Config;
class App extends \CodeIgniter\Config\BaseConfig {
public $siteName = 'My Great Site';
public $siteEmail = 'webmaster@example.com';
}
ただし、 application/Config/App.php
, \Config\App
はデフォルトで用意されていて、コアで使われているので別の名前にする必要があります。(User Guide も違う例文にしたほうが良いと思う…)
さらに、特に影響のない範囲ですが、デフォルトの Config では use CodeIgniter\Config\BaseConfig;
しています。できれば前へ倣えしたほうがいいかと。
環境ごとの設定
どの環境でも同じ設定値で済むものについては、application/Config/
以下に設定していけばよいですが、先述のデータベースなどは、本番と開発で接続先が異なることがほとんどです。
その取り回しについては、前項 環境 (Environment) で言及している .env
が使えます。
CI_ENVIRONMENT
は .env
に設定しないことを決めましたが、他方、設定値についてはとても有用です。
単純な使い方として、
HOGE_VAR=hoge
$hoge_var = getenv('HOGE_VAR');
$hoge_var = $_SERVER['HOGE_VAR'];
$hoge_var = $_ENV['HOGE_VAR'];
というふうに使えるよう、環境変数にセットされます。
ここで紹介したい、便利な使い方は、.env
から Config に値を設定する方法です。(もちろん、User Guide に書いてありますが)
データベースの接続設定を例にします。
# Database
database.default.hostname = "localhost"
database.default.port = "3306"
database.default.username = "mysql_user"
database.default.password = "mysql_pass"
database.default.database = "app_db"
database.default.DBDriver = "MySQLi"
application/Config/Database.php
についてはデフォルトのまま変更せず、先ほどと同じように設定値を var_dump
してみます。 (長いので $db_config->default
のみ抜粋)
array (size=19)
'DSN' => string '' (length=0)
'hostname' => string 'localhost' (length=9)
'username' => string 'mysql_user' (length=10)
'password' => string 'mysql_pass' (length=10)
'database' => string 'app_db' (length=6)
'DBDriver' => string 'MySQLi' (length=6)
'DBPrefix' => string '' (length=0)
'pConnect' => boolean false
'DBDebug' => boolean true
'cacheOn' => boolean false
'cacheDir' => string '' (length=0)
'charset' => string 'utf8' (length=4)
'DBCollat' => string 'utf8_general_ci' (length=15)
'swapPre' => string '' (length=0)
'encrypt' => boolean false
'compress' => boolean false
'strictOn' => boolean false
'failover' =>
array (size=0)
empty
'port' => string '3306' (length=4)
ご覧の通り、値が変わりました。.
でつなげてネストすることで、配列の値が設定されます。
あとは、本番、開発などの環境ごとに .env
が変わればよいわけですね。
環境変数に値を設定することもできるし、CodeIgniter の Config の値を設定することもできるので、たとえば AWS などのサービスで使う 取扱いに注意しなければならないキーやパスワードを .env
ひとつにまとめることができます。
当然のことながら、この .env
は バージョン管理に含めてはならない運用が必要です。
application/Config/*.php
を編集する必要
.env
で設定を管理するにしても、デフォルトで用意されていない値の場合、そのクラスのプロパティは宣言しておくとよいでしょう。たとえば、App
に hoge
という設定を作るとします。
app.hoge = "HogeHoge"
.env
はこれでいいとして、\Config\App
にも hoge
を追加しましょう。
<?php namespace Config;
use CodeIgniter\Config\BaseConfig;
class App extends BaseConfig
{
// ...略...
public $hoge = 'default';
// ...略...
}
確実に .env
に設定する ことが保証されるなら、問題はありません。しかし、前述のとおりバージョン管理に含めないので、プロパティを追加することで 「どんな設定値を追加したか」 のログができます。
デフォルト値も設定しておけば、フェイルセーフとして機能するかもしれません。
また、IDEがプロパティがあることを認識するので、補完が効くようになります。
まとめ
以上、CodeIgniter4 での環境切替/設定の取り回しについてまとめてみました。
先日 参加させていただいた CodeIgniter Night (第4回) で聞いた、「User Guide に書かれていることがすべて」 のとおりで、この記事は結局 User Guide の焼き直しみたいなものでした。
しかし、CodeIgniter はだいぶ自由度が高い印象を受けます。なので、自分が考える 「きれいな」 とか 「安全な」 開発運用のため、必要と思ったのでまとめた次第です。
これから CodeIgniter を使う誰かの一助にでもなれば。