ブログチュートリアルの一節
サンプルコード<?php
class PostsController extends AppController{
var $name = 'Posts';
function index() {
$this->set('posts', $this->Post->findAll());
}
function view($id = null) {
$this->Post->id = $id;
$this->set('post', $this->Post->read());
}
function add() {
if (!empty($this->data)) {
if ($this->Post->save($this->data)) {
$this->flash('保存しました','/posts');
}
}
}
}
?>
えーと、このコード、普通のコーダーなら、普通のコードには見えないと思います。そこにCakeナリのマジックがあるのかもしれないけれど、私にはまともに読めないし、おいおい大丈夫か?と不安になる。
こう書くとどうだろう?
<?php
loadModel("Post");
class PostsController extends AppController{
var $uses = null; //呪縛解放 その1
function index() {
$dao = new Post();
$this->set('posts', $dao->findAll());
}
function view($id = null) {
$dao = new Post();
$this->set('post', $dao->findById($id));
}
function add() {
$this->log( $this->params, LOG_DEBUG ); //呪縛解放 その2
$data = $this->params['data'];
if (!empty($data)) {
$entity1 = new Post();
$entity1->save( $data );
$entity2 = new Post(); //呪縛解放 その3
$entity2->set('title','xxxxxxxx');
$entity2->set('body' ,'xxxxxxxx');
$entity2->save();
}
}
}
?>
その1
コントロール名とモデル名を関連させない。これは前に書きました
その2
$this->Post->save($this->data)
この一行、わかりずらい(マニュアルにもほとんど記述がない)。
結局Webアプリでは、我々プログラマがほしい情報は、CGIパラメータをどうやって取得できるかってこと。
そこで $this->params を見る。logの出力結果は、こんな風。
Array(
[controller] => posts
[action] => add
[data] => Array(
[Post] => Array(
[title] => きょうの記事 ) )
)
このハッシュから、使いたいものを抜き出して、モデルに突っ込めば良い。
$this->data ってのは、$this->params['data']への(ただの)ショートカットです。※レンダーするフェーズでは違う意味を持ちますが、また別の話。
その3
class PostsController {
$name = "Post"
//または $uses = array( "Post" )
で生成される $this->Post は、Cakeが自動的にnewしてくれるインスタンス変数なんだけど、これが異常なほどわかりづらい。
実はコレに縛られる必要はなくて、自分が欲しいタイミングで、ローカル変数にnewすればいいです。
以上、3つのルールを無視したら、Cakeが最高に使いやすい道具になりました。
ステートフルかステートレスか
さらにその3を説明すると長くなる・・
$this->Post->id = $id;
$post = $this->Post->read();
print_r( $post['title'] );
私の違和感は、この↑不自然なコードに集約されている。
$this->Postがナニモノなのか、わからなくない?ステートレスなDAOなのか?ステートフルなentityなのか?
$this->Post->id = $id; //entityかと思いきや、
$title = $this->Post->title; //コレはエラー。つまりentityではない。
$posts = Post::findAll(); //出来そうでデキナイ。
ずいぶん悩みましたよ。で、$this->Postがナニモノかといえば、
エンティティのidだけを持っているステートフルDAO
タチわる~いw だから、こんな不自然なコードが成立するわけだ。
書き方に慣れたとしても、そのうち行き詰る。例えば、
$this->Post->save( array('Post' => array('title'=>'aa')) );
$this->Post->save( array('Post' => array('title'=>'bb')) );
こう書いても、データが2件挿入されるわけではない。
なぜなら、$this-Postがidを持っちゃってるから、2行目は上書き更新になる。
そのクセにだ!
$name = "Post"; //つまり、これが
$uses = array("Post"); //諸悪の根源!
とかルールにしちゃうもんだから、$this->Post 1エンティティしか使えない(ように縛ってる(ように見せてかけている))。
こんなのに縛られずに、自分でバンバン new してしまおう。
※もちろん、$uses はCakeマジックを仕込むための施策と思われるので、それ自体がダメだといってるわけではない。ただ、今使うには、わかりづらいのです。
ちなみにRailsだと・・
class PostsController < ApplicationController
def index
@posts = Post.find(:all)
end
def view
@post = Post.find(params[:id])
end
def add
@post = Post.new(params[:post])
if ! @post.save
flash[:notice] = 'xxxxxxx'
redirect_to :controller=>:posts
end
end
end
Postはステートレスで、@postはステートフルだとはっきり分かる。いたって普通です。