Concrete CMS で環境ごとに別の設定ファイルを読み込む方法


Concrete CMS で本番環境、テスト環境、ローカル環境など様々な別のサーバーで管理しているときがあります。

- 本番環境ではキャッシュをオンにしているけれど、テスト環境・ローカル環境ではキャッシュをオフにしたい。
- 開発環境からのメールは、きちっと開発環境のドメインから送るようにしたい。
- 本番・開発・テストと MySQL (database.php) の設定ファイルをプライベート git の中に保存しておきたい。

そういった時、Concrete CMS では環境変数 Environment を設定できます。

Environment を設定し、/application/config/ 内の config ファイル全てにその環境変数を頭文字にして保存すると、その環境は独自に作られた設定ファイルが読み込まれるようになります。

# 設定ファイルの作り方

後述の方法で Concrete CMS に環境変数を設定する際、別々にしたい config 設定ファイルを環境変数の接頭語付きで作成します。

例えば `develop` という環境変数がついていれば。/application/config フォルダ内で

```
app.php
concrete.php
database.php
site.php
```

設定ファイルを下記のように環境変数の接頭語を加えて保存できます。

```
develop.app.php
develop.concrete.php
develop.database.php
develop.site.php
```



# 環境変数の付与の方法

環境変数の設定は、`/application/bootstrap/start.php` で行います。

## アクセスされたドメイン名で変数を設定する

例: develop.example.com のドメインでアクセスした場合は、`develop` という環境変数を与える。staging.example.com のドメインの場合は `staging`という環境変数。その他は `default`、つまり接頭語なし。

```/application/bootstrap/start.php
<?php
use Concrete\Core\Application\Application;
// /application/bootstrap/start.php
/* 
 * ----------------------------------------------------------------------------
 * Instantiate Concrete CMS
 * ----------------------------------------------------------------------------
 */
$app = new Application();
/*
 * ----------------------------------------------------------------------------
 * Detect the environment based on the hostname of the server
 * ----------------------------------------------------------------------------
 */
$app->detectEnvironment(function() {
    if (!Application::isRunThroughCommandLineInterface()) {
        $request = \Concrete\Core\Http\Request::getInstance();
        switch ($request->getHost()) {
            case 'develop.example.com':
                return 'develop';
                break;
            case 'staging.example.com':
                return 'staging';
                break;
            default:
                return;
        }
    }
});
return $app;
```

## ロードバランサー経由などで X-Forwarded-For な属性で判断したい

下記は Header 情報で判断するためのサンプルです。`x-forwaded-server` の Header 情報に `loadbalancer.example.com` は含まれて (contain) されていたら、default の環境変数。それではなかったら `direct` という環境変数を付与している例です。

Symfony の HTTP Request のライブラリを使っています。他にも、IP アドレスなどで判断するなどいろいろ抽出方法があります。

```/application/bootstrap/start.php
<?php
use Concrete\Core\Application\Application;

/*
 * ----------------------------------------------------------------------------
 * Instantiate concrete5
 * ----------------------------------------------------------------------------
 */
$app = new Application();

/*
 * ----------------------------------------------------------------------------
 * Detect the environment based on the hostname of the server
 * ----------------------------------------------------------------------------
 */
$app->detectEnvironment(function() {
    if (!Application::isRunThroughCommandLineInterface()) {
        /** @var $request \Symfony\Component\HttpFoundation\Request */
        $request = \Concrete\Core\Http\Request::getInstance();
        if ($request->headers->contains('x-forwarded-host', 'loadbalancer.example.com')) {
            return 'default';
        } else {
            return 'direct';
        }
    }
});

return $app;
```

## サーバーの Hostname で設定する

サーバーの Hostname で判断する。
array 配列なので、複数のHostnameを設定できます。

サーバーの Hostname は、SSH などでログインして

```
$ hostaname
```

コマンドを叩くことで hostname を確認することができます。
**サーバーの Hostname とドメイン名とは別**なので、気をつけてください。


```/application/bootstrap/start.php
<?php

use Concrete\Core\Application\Application;

/*
 * ----------------------------------------------------------------------------
 * Instantiate Concrete CMS
 * ----------------------------------------------------------------------------
 */
$app = new Application();

/*
 * ----------------------------------------------------------------------------
 * Detect the environment based on the hostname of the server
 * ----------------------------------------------------------------------------
 */
$app->detectEnvironment(
    [
        'staging' => [
            'staging.localhost',
        ],
        'production' => [
            'production.localhost'
        ],
        'test' => [
            'test.localhost',
            'localhost'
        ]
    ]);

return $app;
```



## おまけ: Mac のローカル環境 Valet は環境変数 `valet` が自動的につく

PHP Laravel フレームワークのチームが開発している Valet という Mac 専用のローカル環境があります。

Valet は Concrete CMS に対応しており、Concrete CMS は自動的に `valet` という環境変数を理解します。

# Config ファイルの読み込まれる優先順位

各 Config の値は以下の優先順位で読み込まれます。

1. 特定 Environment 名の `/application/config` 以下の Config ファイルが存在していたらそれが読み込まれる
2. 環境名無しの`/application/config` 以下の各設定ファイルが読み込まれる。
3. 環境名無しの`/application/config/generated_overrides` 以下の各設定ファイルが読み込まれる。これは管理画面を通じて設定され自動生成された config ファイル


## おまけ: Webサーバーのホスト名と、サーバーホスト名を組み合わせて判断したい場合

Symfony の HTTP Request と Concrete CMS の gethostname を組み合わせて条件分岐したい場合。

```
$app->detectEnvironment(function () {
    if (!Application::isRunThroughCommandLineInterface()) {
        $request = \Concrete\Core\Http\Request::getInstance();
        if ($request->headers->get('host') == 'example.com') {
            return 'production';
        }
    } elseif (in_array(
        gethostname(),
        [
            'dev-hostname',
            'ip-xxx-xxx-xxx-xxx.ap-northeast-1.compute.internal',
            'devserverhostname.example.com'
        ], true)
    ) {
        return 'develop';
    }
});
```