http://book.cakephp.org/2.0/ja/models/model-attributes.html
recursiveは恐ろしい。怖い人はAppModelに、public $recursive = -1;と書いておけばデフォルトで-1になるようだ。 これをしない場合、デフォルト値は1になる。
- recursive -1 は、JOINしない。自分だけとってくる。
- recursive 0 は、自分と自分がbelongsToしているモデルだけとってくる。
- recursive 1 は、自分とbelongsToとHasManyをとってくる。
- recursive 2 は、自分とbelongsToとHasManyと、BelongsToとHasMany先が関連しているモデルを一階層分とってくる。
みたいな感じになっているようだ。0は自分だけという意味ではないってことである。それにしても0と1と2はいまいち明確な違いが分からない。
ブログみたいなシステムを考えて、UserがPostを投稿し、PostにCommentがつき、PostにはTagも設定できるようにしてみる。この場合、UserはPostをHasManyしていて、PostはUserにbelongsToしている。PostはCommentをHasManyしていて、CommentはPostにbelongsToしている。また、CommentはUserにもbelongsToしている。また、PostとTagはHABTMになっている(PostはPostsTagをHasManyしている)。
Postをrecursive0でfindすると、PostとUserが得られる。Commentは得られない。なのでやはりbelongsToは得られるが、HasManyは得られないのだ。
Postをrecursive1でfindすると、PostとUserとCommentとTagが得られる。Tagの中にPostsTagが入っている。こういうことを自動的にやってくれているらしい。確かに1の場合はHasManyもとってくるのだ。ただし、HABTMの場合は、中間テーブルを取ってくるのではなく気を利かせてHABTM先のモデルを取ってきてくれるらしい。
recursive2でfindすると、Userの中にPostが入っている。Commentの中にはUserとPostが入っている。なので下手にrecursiveをあげるとすごいことになる。
recursive -1 , 0 までは1クエリで、recursive1で、3クエリ。でもrecursive2で、32クエリ。3で、113クエリ。4で、309クエリ。5で865クエリ。6で2228クエリ。recursive2以上を使う場合は、bindModel()とunbindModel()を使って都度アソシエーションを限定的にする必要がある。
http://d.hatena.ne.jp/takuya15/20071219/1198035692 これは、都度動的にアソシエーションを設定することを簡単にする方法が書いてある。これは結構いいかもと思った。
$this->Post->recursive = 2; $this->User->unbindModel(array('hasMany' => array('Post', 'Comment', 'Item'))); $this->Comment->unbindModel(array('belongsTo' => array('Post'))); $posts = $this->Post->find('all');
こうやって動的にunbindModelを使うと、Commentした人の名前だけ4クエリで取得できるからrecursive2以上を使うときはこういうことをしないといけない。
全部モデルにアソシエーションは書いておいて、AppModelでrecursiveのデフォルト値を-1に設定しておいて、基本recursiveを使わないようにしつつ、どうしても必要なときだけ、unbindModelを使うっていう感じでいいかのう。
と思ったらなんかおかしい。commentの件数分、個別にUserをクエリで取得しているようだ。なんだこれは。100件コメントがあったら100クエリするつもりのようだ。CommentにUserをJoinすればいいだけの気がするが。
http://d.hatena.ne.jp/hetima/20070225/1172409266にも同じようなことが書いてある。でもこれは、そもそもrecursive0でよかったのに2にしていただけともいえると思った。 それにしてもやっぱりこわい。HasManyされているやつが、何かにbelongsToしていて、その何かがrecursive2以上に該当する場合は注意が必要だということであります。
まあ要するに効率的にやろうとすると、cakePHPも都度色々コードをしっかり書かないといけないってことかのう。