CakePHPには利用するデータベース定義を複数定義しておける機能がありますが、その使い分けに関するアイデアです。

よくある解決策

よく開発環境と本番環境で自動的にデータベース接続を切り替えられるように、以下のようにDATABASE_CONFIGクラスのコンストラクタを改良したり、AppModelクラスのコンストラクタに現在の環境を判別できるような設定を書いたりするアイデア多く見かけられます。

DATABASE_CONFIGクラスの改良

class DATABASE_CONFIG
{
	public $default = array();

	// 公開用
	public $production = array(
		'driver' => 'mysql',
		'persistent' => false,
		'host' => 'production.mysql.server',
		'login' => 'admin',
		'password' => '****',
		'database' => 'production_database',
		'prefix' => 'prefix_',
		'encoding' => 'utf8'
	);

	// 開発用
	public $development = array(
		'driver' => 'mysql',
		'persistent' => false,
		'host' => 'localhost',
		'login' => 'test',
		'password' => '****',
		'database' => 'development_database',
		'prefix' => 'prefix_',
		'encoding' => 'utf8'
	);

	public function __construct()
	{
		if (env('SERVER_ADDR') !== '127.0.0.1') {
			$this->default = $this->production;

		} else {
			$this->default = $this->development;
		}
	}
}

AppModelの改良

function __construct()
{
	if (env('SERVER_ADDR') == '127.0.0.1') {
		$this->useDbConfig = 'development';
	}  else {
		$this->useDbConfig = 'production';
	}
}

よくある解決策の問題点

よくある解決策では、httpから利用する場合には非常に便利で良いのですが、コンソールから利用する場合、この設定では不都合が発生します。

たとえばschemaコマンドを利用する場合です。
コンソールではREMOTE_ADDRやSERVER_ADDRなどの環境変数が利用できません。
そのため、コンソールで利用する場合はリモートで利用しているのかローカルで利用しているのかを環境変数から判別することができません。

であれば、schemaコマンドを実行する際に -connectionオプションで利用する接続を選択してやれば良いと考えてしまうのですが、CakePHPのコンソールから起動するschemaコマンドは、-connectionオプションで指定されたデータベース接続(指定されなければdefault)とModelのデータベース接続(Model::$useDbConfig)が一致しない場合、そのModelのスキーマを読み込んでくれません。

実行しているファイルのパスを見て判別するような荒技もありますが、実行ファイルのパスが被らない保証も無いので、こちらも確実とはいえません。

シンプルな解決策

ではどうすれば良いか、というと、Configureクラスを利用する方法が一番わかりやすくてベターです。
config/core.php もしくは config/bootstrap.php に下記のように設定します。

Configure::write('database', 'production');

そして、config/database.php のDATABASE_CONFIGクラスを下記のように記述します。

class DATABASE_CONFIG
{
	public $default = array();

	// 公開用
	public $production = array(
		'driver' => 'mysql',
		'persistent' => false,
		'host' => 'production.mysql.server',
		'login' => 'admin',
		'password' => '****',
		'database' => 'production_database',
		'prefix' => 'prefix_',
		'encoding' => 'utf8'
	);

	// 開発用
	public $development = array(
		'driver' => 'mysql',
		'persistent' => false,
		'host' => 'localhost',
		'login' => 'test',
		'password' => '****',
		'database' => 'development_database',
		'prefix' => 'prefix_',
		'encoding' => 'utf8'
	);

	public function __construct()
	{
		$connection = Configure::read('database');
		
		if (!empty($this->{$connection})) {
			$this->default = $this->{$connection};
		}
	}
}

この方法であれば、データベースを切り替えたいときはデバッグモードの切り替えのように設定値を変更するだけで済みますし、ローカルに依存するコードを記述する必要もなくなります。

さらに今後新しいデータベース接続を追加した場合にも、設定値を変更するだけで対応可能なので、今後の拡張性の面でも安心できます。

CakePHPのMediaプラグインは非常に多機能なプラグインで、バージョン管理という非常に便利な機能が備わっており、本画像に手を加えずにいくつものサムネイル画像を生成する事ができます。

ただ、その便利な機能であるバージョン管理機能が少々複雑で、馴れないと使いづらい印象を受けてしまいます。

たとえば画像をアップロードする際、モデルごとに違ったサイズのサムネイルを生成したい、などという場合などが特に悩むポイントかと思います。

基本的にMediaプラグインは、あらかじめアップロードするファイルごとに生成するファイルを「バージョン」として定義しているため、Mediaプラグインを通してアップロードしたファイルは、全て定義した数のバージョンファイルが生成されてしまいます。

そこで、下記のように工夫することで、モデルごとに生成するバージョンファイル取捨選択するアイデアです。

Attachmentモデルをコピーして改良

App::import('Lib', 'Media.Media');

class Attachment extends AppModel
{
    public $name = 'Attachment';
    public $useTable = 'attachments';
    public $useVersions = array();

    public $actsAs = array(
        'Media.Transfer' => array(
            'trustClient' => false,
            'transferDirectory' => MEDIA_TRANSFER,
            'createDirectory' => true,
            'alternativeFile' => 100
        ),
        'Media.Generator' => array(
            'baseDirectory' => MEDIA,
            'filterDirectory' => MEDIA_FILTER,
            'createDirectory' => true,
        ),
        'Media.Polymorphic',
        'Media.Coupler' => array(
            'baseDirectory' => MEDIA
        ),
        'Media.Meta' => array(
            'level' => 2
        )
    );

    public $validate = array(
        'file' => array(
            'resource'   => array('rule' => 'checkResource'),
            'access'     => array('rule' => 'checkAccess'),
            'location'   => array('rule' => array('checkLocation', array(
                MEDIA_TRANSFER, '/tmp/'
            ))),
            'permission' => array('rule' => array('checkPermission', '*')),
            'size'       => array('rule' => array('checkSize', '5M')),
            'pixels'     => array('rule' => array('checkPixels', '1600x1600')),
            'extension'  => array('rule' => array('checkExtension', false, array(
                'jpg', 'jpeg', 'png', 'tif', 'tiff', 'gif', 'pdf', 'tmp'
            ))),
            'mimeType'   => array('rule' => array('checkMimeType', false, array(
                'image/jpeg', 'image/png', 'image/tiff', 'image/gif', 'application/pdf'
        )))),
        'alternative' => array(
            'rule'       => 'checkRepresent',
            'on'         => 'create',
            'required'   => false,
            'allowEmpty' => true,
        )
    );

    public function makeVersion($file, $process)
    {
        if (!is_array($this->useVersions) && !empty($this->useVersions)) {
            $this->useVersions = array($this->useVersions);
        }

        if ($this->useVersions === false || !empty($this->useVersions) && !in_array($process['version'], $this->useVersions)) {
            return true;
        }

        return $this->Behaviors->Generator->makeVersion($this, $file, $process);
    }
}

モデルごとに生成するバージョンファイルを切り替える

先ほどのモデルを継承したモデルを生成し、メンバー変数 $useVersions に利用したいバージョンファイル名を配列で列挙します。

App::import('Model', 'Attachment');

class UserImage extends Attachment
{
    public $name = 'UserImage';
    public $useVersions = array('main', 'sub');

    public $validate = array(
        'file' => array(
            'resource'   => array('rule' => 'checkResource'),
            'access'     => array('rule' => 'checkAccess'),
            'location'   => array('rule' => array('checkLocation', array(
                MEDIA_TRANSFER, '/tmp/', 'C:\xampp\tmp',
            ))),
            'permission' => array('rule' => array('checkPermission', '*')),
            'size'       => array('rule' => array('checkSize', '1M')),
            'extension'  => array('rule' => array('checkExtension', false, array(
                'jpg', 'jpeg', 'png', 'gif', 'tmp',
            ))),
            'mimeType'   => array('rule' => array('checkMimeType', false, array(
                'image/jpeg', 'image/png', 'image/gif',
            ))),
        ),
    );
}

$useVersions が空の場合は全てのバージョンファイルが生成されます。
これにより、モデルごとに生成するバージョンファイルを切り替えることが可能になります。

必要に追われて、MovableTypeのパーマリンクを正規表現でカスタマイズするプラグインを書いたので、需要があるかどうかはわかりませんが公開します。

利用方法はいろいろあると思うんですが、自分の場合はCakePHPのコンテンツ部分を管理するのにMovableTypeを利用する場合に使用しています。
※CakePHPのコンテンツ管理にMovableTypeを利用する、を参照。

CakePHPを設置する場合、Cakeのディレクトリやアプリケーションのディレクトリは公開ディレクトリ以外の部分に設置することが多いため、MovableTypeのテンプレートの生成先をアプリケーションのviewsディレクトリ以下に設定した場合、MovableTypeの生成するパーマリンクや、管理画面上からの記事へのリンク(プレビューなども含めて)が正しく動作しなくなります。

その場合、正規表現でパーマリンクのURLを書き換えることで、正しいURLが生成されるようにできます。

ダウンロード

http://inspire-tech.jp/wp-content/uploads/2010/08/CustomPermalink.zip

動作要件

MovableType 5.0以上

使用方法

  1. MovableTypeのPluginsディレクトリにアップロード後、利用したいウェブサイトまたはブログのプラグイン管理画面から、有効のチェックを入れます。
  2. その後、同画面のAdd new pairリンクをクリックするとダイアログが表示されるので、そこに検索する文字列と置換する文字列を設定します。このペアは、複数登録することが可能です。

※検索と置換の処理は表示されてるペアの上から順番に実行されていきますので、並び順には注意してください。