CakePHP Advent Calendar 2012の15日目の記事です。
昨日は@lifegoodさんの「Phing を利用して CakePHP を継続的インテグレーション」でした。
僕も最近Jenkinsでテストの自動化をしたんですけども、設定ファイルで結構苦労したんで、早速参考にしたいと思います。

最近はCakePHPをガシガシ触っているわけではないので、新しいネタがなかなか無いのですが、普段自分がCakePHPをセットアップしている時にやっているもろもろのことをまとめてみたいと思います。

CakePHPの管理はGitで

Composerでインストール作法が今後メインになっていく様な流れを感じますが、会社で普段からGitを使っているのもあり、Gitで管理してます。
基本的にCakePHPのコア部分はgit-submoduleで管理してます。

まずはgit-cloneしてソースを持ってくる

git clone git://github.com/cakephp/cakephp.git project

不要なディレクトリの削除&gitディレクトリの作り直し

cd project
rm -r .git
rm -r lib
git init

cakephpをsubmoduleで追加

git submodule add git://github.com/cakephp/cakephp.git
git submodule update --init

CAKE_CORE_INCLUDE_PATHを編集する

vi app/webroot/index.php

  //define('CAKE_CORE_INCLUDE_PATH', ROOT . DS . 'lib');
+ define('CAKE_CORE_INCLUDE_PATH', ROOT . DS . 'cakephp' . DS . 'lib');

vi app/webroot/test.php

  //define('CAKE_CORE_INCLUDE_PATH', ROOT . DS . 'lib');
+ define('CAKE_CORE_INCLUDE_PATH', ROOT . DS . 'cakephp' . DS . 'lib');

app/Console/cake.phpを編集

app/Consoleからcakeのシェルコマンドを叩けるように変更する。
appディレクトリ以下なので、思いっきり修正出来るのが良い!

vi app/Console/cake.php
...

$ds = DIRECTORY_SEPARATOR;
$dispatcher = 'Cake' . $ds . 'Console' . $ds . 'ShellDispatcher.php';

  if (function_exists('ini_set')) {
      $root = dirname(dirname(dirname(__FILE__)));
+     //  for managing cakephp's core-code by git-submodule
-     ini_set('include_path', $root . $ds. 'lib' . PATH_SEPARATOR . ini_get('include_path'));
+     ini_set('include_path', $root . $ds . 'cakephp' . $ds . 'lib' . PATH_SEPARATOR . ini_get('include_path'));
  }

...

+ // for managing cakephp's core-code by git-submodule
+ $idx = array_search('-app', $argv);
+ if ($idx === false) {
+     $argv[] = '-app';
+     $argv[] =  $root . $ds . 'app';
+ }

unset($paths, $path, $dispatcher, $root, $ds);

return ShellDispatcher::run($argv);

tmpディレクトリ以下に.gitignoreファイルをセットする

emptyってファイルを管理下に置くのはなんだか気が引けるので。

echo '*' > app/tmp/.gitignore
echo '*' > app/tmp/cache/.gitignore
echo '*' > app/tmp/cache/models/.gitignore
echo '*' > app/tmp/cache/persistest/.gitignore
echo '*' > app/tmp/cache/views/.gitignore
echo '*' > app/tmp/logs/.gitignore
echo '*' > app/tmp/sessions/.gitignore
echo '*' > app/tmp/tests/.gitignore
git add -f app/tmp/.gitignore app/tmp/cache/.gitignore git add -f app/tmp/cache/models/.gitignore app/tmp/cache/persistest/.gitignore app/tmp/cache/views/.gitignore app/tmp/logs/.gitignore app/tmp/sessions/.gitignore app/tmp/tests/.gitignore

Config以下のファイルを環境ごとに用意する

bootstrap.phpで上書きするというやり方もありますが、キャッシュ周りで変な動きをすることが多いので、僕はシンプルにファイルごと分けちゃってます。
環境は環境変数を見て切り替えるようにします。

Bootstrapの場合。

mkdir app/Config/Bootstrap

mv app/Config/bootstrap.php app/Config/Bootstrap/production.php
cp app/Config/Bootstrap/production.php app/Config/Bootstrap/test.php
cp app/Config/Bootstrap/production.php app/Config/Bootstrap/development.php

vi app/Config/bootstrap.php

<?php
if (env('CAKE_ENV') === null) {
  config('Bootstrap/production');
} else {
  config('Bootstrap/' . env('CAKE_ENV'));
}

Coreの場合。

mkdir app/Config/Core

mv app/Config/core.php app/Config/Core/production.php
cp app/Config/Core/production.php app/Config/Core/test.php
cp app/Config/Core/production.php app/Config/Core/development.php

vi app/Config/core.php

<?php
if (env('CAKE_ENV') === null) {
  config('Core/production');
} else {
  config('Core/' . env('CAKE_ENV'));
}

Databaseの場合。

mkdir app/Config/Database


mv app/Config/Database/database.php app/Config/Database/production.php
cp app/Config/Database/production.php app/Config/Database/test.php
cp app/Config/Database/production.php app/Config/Database/development.php

vi app/Config/database.php

<?php
if (env('CAKE_ENV') === null) {
  config('Database/production');
} else {
  config('Database/' . env('CAKE_ENV'));
}

全環境共通の処理や設定は、app/Config/bootstrap.phpやapp/Config/core.phpとかに書いちゃっても良いと思います。

あとは環境毎に環境変数を設定して、読み込む設定ファイルの種類を変えてやればOKです。

具体的にはWebサーバとかでApacheなら

SetEnv CAKE_ENV test

とかやっとけば動くと思いますし、
bakeする時もbash使っているなら$HOME/.bashrcとかで

export CAKE_ENV=development

みたいに設定しておくと楽出来ると思います。

Security.saltとSecurity.cipherSeedのセット

意外にこいつの設定が面倒なので、こんなPHPプログラムを走らせて自動生成してます。

vi cakephp.php

<?php
echo 'please input string: ';
$stdin = fgets(STDIN,4096);

// salt
$salt = sha1($stdin);

// seed
$seed = '';
for ($i = 0; $i < 30; $i++) {
    $seed .= mt_rand(0, 9);
};

echo "**************************************\n";
echo sprintf("Security.salt:       %s\n", $salt);
echo sprintf("Security.cipherSeed: %s\n", $seed);
echo "**************************************";

んで、こいつをローカルで

php cakephp.php

とかやると文字列を聞いてくるので、プロジェクト名とか適当に入れると、勝手にSecurity.saltとSecurity.cipherSeedを表示してくれます。 まあ、あまりセキュリアかと言われるとアレですが・・・。

キャッシュエンジンでFileを利用する際の注意

個人的に開発環境ではキャッシュエンジンをFileにすることが多いのですが、CakeのコマンドとWEBサーバを介しての表示を交互にやっていたりすると、キャッシュファイルに書き込めないとかエラーが出ることが結構あるので、下記のように設定してます。

vi app/Config/Core/development.php

  /**
   * Configure the cache used for general framework caching.  Path information,
   * object listings, and translation cache files are stored with this configuration.
   */
  Cache::config('_cake_core_', array(
    'engine' => $engine,
    'prefix' => $prefix . 'cake_core_',
    'path' => CACHE . 'persistent' . DS,
    'serialize' => ($engine === 'File'),
    'duration' => $duration,
+   'mask' => 0666
  ));

  /**
   * Configure the cache for model and datasource caches.  This cache configuration
   * is used to store schema descriptions, and table listings in connections.
   */
  Cache::config('_cake_model_', array(
    'engine' => $engine,
    'prefix' => $prefix . 'cake_model_',
    'path' => CACHE . 'models' . DS,
    'serialize' => ($engine === 'File'),
    'duration' => $duration,
+   'mask' => 0666
  ));

よく使うプラグインの設定

以下のプラグインは大体どのプロジェクトでも使うので、最初にざーっと入れちゃってます。

最後に

いざ書きだしてみると、細かいことを色々やっているなーと思ったりしました。
まだ、思い出せてないことも結構有りそうですけど、思い出したら追記していきたいなと思います。

あと、個人的にAdvent Calendarというのは読む専門だったんですが、今年初めて参加できて嬉しかったです。
CakePHPにはお世話になりっぱなしなので、少しでもコミュニティに還元出来れば嬉しいなあーって思います(自己満)。

明日は@yujiodさんの「CakePHPでジョブキューするプラグイン」です!