CakePHPで高速Webアプリ開発
第2回 CakePHPのフレームワークとしての機能
連載第1回目ではCakePHPを抽象的に紹介しました。今回はCakePHPのフレームワークとしての機能を具体的に紹介いたします。なお,紹介する機能は安定版の1.1系をもとにしています。
MVCモデル
CakePHPの構造はWebアプリケーション開発で実績のあるMVCモデルを採用しています。MVCについての解説は少々長くなるのでここでは省略させていただきますが,非常にシンプルな構造なのですぐに理解できます。MVCモデルの採用はそれほど手間をかけずに可読性と再利用性が上がり,デザイナーとの分業もしやすくなります。
Cool URI
CakePHPの初期状態のURI規則は「Cool URI」と言える綺麗な構造です。
http://example.com/コントローラー名/アクション(メソッド)名/パラメータ1/パラメータ2…
たとえば「ユーザの情報を編集するURI」であれば,Usersコントローラーのeditメソッドをアクションとし,パラメータとしてユーザーIdを渡すことにすると,できあがるURIは以下のようになります。
http://example.com/users/edit/128
「アクション名がメソッド名だと,外から直接呼ばれたくないメソッドはコントローラには定義しちゃいけないの?」と疑問を持たれるかもしれませんが,もちろんそこは大丈夫です。コントローラに定義するメソッド名の頭に「_(アンダースコア)」をつけることで,URIからの呼び出しができないメソッドになります。
このURI規則は「Routes(app/config/routes.php)」という機構で柔軟に定義することができます。たとえば「/(ルート)」にアクセスしたときだけ,特別に指定したコントローラのアクションを呼び出すといったことも可能です。場合によってはmod_rewriteを活用しても良いでしょう。
ActiveRecord
第1回でも紹介しましたが,ActiveRecordパターンのO/Rマッパは,CakePHPによる高速開発の要です。具体的なサンプルコードを示したほうがイメージを掴み易いかと思いますので,以下にいくつか例を用意しました。
// すべてのユーザーの情報を取得
$users = $this->User->findAll();
// ユーザーIdを指定して1つの情報を取得
$user = $this->User->findById($user_id)
// ステータスがactiveのユーザーの情報を取得 方法1
$active_users = $this->User->findAll(array('status' => 'active'));
// ステータスがactiveのユーザーの情報を取得 方法2
$active_users = $this->User->findAllByStatus('active');
// ユーザー情報を追加
$this->User->save($new_user);
// ユーザー情報を変更
$this->User->id = $user_id;
$this->User->save($new_info);
// ユーザー情報を削除
$this->User->del($user_id);
モデルのバリデーション機能
モデルに保存できるデータの形式をあらかじめ定義しておくことで,不正なデータが保存されることを未然に防ぐ機能があります。バリデーション機能はデータの保存時に自動的に呼ばれるだけでなく,コントローラから利用することもできます。
バリデーションの規則はCakePHPが用意した中から選ぶか,正規表現で記述します。形式がCakePHPが用意したものか正規表現だけなので,複雑な条件を加えたい場合は後で紹介するモデルのフィルタチェインを利用して実装したり,コントローラで処理する必要はあります。
なお,現在開発中の1.2系ではモデルのバリデーション機能が拡張され,複雑なロジックを組み込めるようになるようです。
ビューで便利なヘルパー群
CakePHPの標準のビューはピュアPHPで,ビュー内で使えるヘルパーオブジェクトが便利です。よくある処理としてselect要素とoptions要素の繰り返しや,javascriptの値のエスケープ処理などは以下のように記述します。
<!--$job_optionsはoption要素用の連想配列で,$user['User']['job'] は selected にしたい値-->
<?php echo $html->selectTag('User/job', $job_options, $user['User']['job']) ?>
<script type="text/javascript">
// JavaScript用に適切にエスケープする
var username = "<?php echo $javascript->escapeString($user['User']['name']) ?>";
</script>
ビューキャッシュ
CakePHPのビューキャッシュは非常に強力でシンプルなキャッシュ機構です。表示結果のHTMLをすべてキャッシュしてファイルに保存し,キャッシュヒットした場合はそのまま出力するので通常に比べてほとんど負荷がかかりません。うまく使えばサーバの負荷を劇的に下げることができるでしょう。
ビューキャッシュは初期状態では無効になっていますので,設定が必要です。app/config/core.phpのCACHE_CHECK定数をtrueにし,キャッシュさせたいコントローラークラス内で,キャッシュさせたいアクション名(必要であればパラメータ)と生存時間(秒)を定義することで動作します。
フィルタチェイン
CakePHPの各種フィルタは厳密にはフィルタチェインとはいえないかもしれませんが,同等の便利さを備えています。例として,コントローラのbeforeFilterメソッドではすべてのアクションの前に共通処理を定義できます。モデルのafterFindメソッドでは,コントローラに値を返す前に値を加工する処理を定義できます。
少々富豪的な例になりますが,モデルで有効期限とステータスがあるレコードを扱うとき,afterFindを使って有効期限内かつステータスが有効かどうかを判別するフラグを返り値にセットしておくと,コントローラでフラグを見るだけで判別できたりします。
アクションチェイン
アクションとして定義したメソッドを外部から呼びたくなることがあります。そんなときは以下のように書くことで,通常はURIから呼び出されるアクションを内部から呼び出すことができます。
$usersDetail = $this->requestAction('/users/detail/' . $user_id, array('return' => true));
ネイティブ関数の短縮表記
フレームワークとしての機能とは言い難いですが,よく使われるネイティブ関数を短い関数名で定義しています。たとえば以下のような関数があります。
- array(配列) => a
- array(連想配列) => aa // array assocの略
- array_merge => am
- htmlspecialchars => h
- str_replace => r
- print_r => pr
短縮表記を使うことでタイプ量が減って画面内に表示できる情報量が増えるので,開発効率を上げることができます。
自分で用意してもよい手法ですが,CakePHPの関数として定義されていることに意味があります。CakePHPで再開発するときに定義し直す必要はありませんし,グループ開発時には「CakePHPで定義されているから」という理由で導入しやすくなるかもしれないからです。
まとめ
いかがでしたでしょうか。筆者の個人的には,CakePHPのフレームワークの機能は「よくあるWebアプリケーション開発のために」「必要十分で」「極力シンプルに」作られているようで,さじ加減がちょうど良いと感じます。
開発中の1.2系ではバリデータの拡張の他に,キャッシュにapcやmemcachedなどが使えるようになり,この他にも新機能や多くの改良が施されています。安定版のリリースが待ち遠しいですね。

