このコピペチェックツール【CopyContentDetector】もCakePHPで実装しています。そこで学んできたCakePHPで実装するときに気をつけることを3つ紹介します。
■モデルはなるべくloadModelで都度呼び出す
マニュアルなどでは、コントローラーのuses配列の要素としてモデル名を書くように。という風に書いてあります。ですが読み込むモデルが多くなってくると、コントローラー実行時のオーバーヘッドが大きくなってきます。モデル読み込み時にDBにアクセスに行くので、モデルの数だけデータベースにアクセスして、存在の確認とかをおこなっているようですね。
そのアクションで利用しないモデルの内容までチェックするので、結果ページの表示が遅くなったりします。そこで、モデルの類はコントローラー上で直前に以下のように記述して都度読み込むようにしています。もちろん、利用頻度の高いモデルに関しては、usesに書いても問題ありません。
$this->loadModel('【モデル名】');
■DB接続しないモデルを作成して、コントローラーを綺麗に保つ
最近はこんな感じの構成で使っています。ロジック専用モデルを作成することで、メンテナンス性も良くなります。また、テストコードを書きやすくなるというよい副作用もあります。データベースにアクセスしないモデルの作成方法はこちらです。
・コントローラー
ロジック専用モデルをどんどん呼び出していく。文字通りコントローラー。
・ロジック専用モデル
DBにアクセスしないモデルを作成、そこに必要なロジックを書いていく
このロジック専用モデルがどんどん拡張されていく感じ
・データアクセス用モデル
データベースにアクセスするモデル。ドキュメントに書かれている普通のモデルの使い方
■バリデーションの内容をPOSTされた内容によって変更する方法
公式のドキュメントなどには、モデルのメンバ変数へ直接記述しておく、というのが多いです。これだと、動的にバリデーションの内容を変更しづらいです。渡されてくるPOSTの結果などによって、バリデーションの内容を変えたりする方法を紹介します。
コントローラーに以下のように記述しています。
$this->【モデル名】->setValidation($this->request->data);
$this->【モデル名】->set($this->request->data);
if (!$this->【モデル名】->validates()) {
バリデーションに失敗した時の処理を書く
}
対象モデルのsetValidationでバリデーションの内容を変更し、setで検査対象のデータをセットして、validatesメソッドでバリデーション実行という流れです。
モデルのsetValidationには以下のように記述しています。
$this->validate = array(
バリデーションの内容
);
メンバ変数のvalidateを関数内で変更、定義してあげる感じになります。あんまりモデルのメンバ変数定義するところにバリデーション内容をつらつら書くと、どこで使っているバリデーションなのかわからなくなるので、こっちのほうがいいと思いました。
■ページネーションをElementにして共通化する
paginateを使って、ページングの処理を行うときの、よくある<< 1 2 3 >>みたいなやつを共通化します。ここでは、件数が0件の時にはページングの部分を表示しないという実装になっています。
また、このままコピペすれば、Twitter Bootstrapに最適化された状態で利用することができます。大体どんな箇所でも利用することが可能です。
<?php if ($this->params['paging'][$model]['pageCount'] > 1) { ?>
<div class="row">
<div class="col-md-12">
<ul class="pagination">
<?php echo $this->Paginator->prev(__('<<'), array('tag' => 'li'), null, array('tag' => 'li','class' => 'disabled','disabledTag' => 'a')); ?>
<?php echo $this->Paginator->numbers(array('separator' => '','currentTag' => 'a', 'currentClass' => 'active','tag' => 'li','first' => 1, 'ellipsis' => '<li class="disabled"><a>...</a></li>')); ?>
<?php echo $this->Paginator->next(__('>>'), array('tag' => 'li','currentClass' => 'disabled'), null, array('tag' => 'li','class' => 'disabled','disabledTag' => 'a')); ?>
</ul>
</div>
</div>
<?php } ?>
<?php echo $this->Paginator->counter(array('format' => __('全{:count}件中 {:page}/{:pages}ページを表示'))); ?>
呼び出し元は以下のように記述しておきます。こうすることによって、ページネーションするモデルが変わっても、共通のエレメントで、【件数が0件の時にはページングの部分を表示しない】という処理が実現できます。
<?php echo $this->element('paginate', array('model' => '【モデル名】'));?>
というかんじで、いままでCakePHPを使ってシステム実装してきたときに感じたことを書いてみました。参考にしてみてください。