CakePHP わかりずらい+2点

独特のモデルの性質と、コントロールの規約から解放されたい。余計なルールはムシして、わかりやすいように使っちゃうことにしました。規約を捨てたほうが使いやすくなる、という場合もある。

ブログチュートリアルの一節

サンプルコード
<?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はステートフルだとはっきり分かる。いたって普通です。


コメント

コメントしてください
お名前:
入力しなければ「匿名さん」。20字以内。

メール:
入力しても表示しません

URL:
入力すればリンクが貼れます


コメント: