115
CakePHPをさらにDRYにする ドライケーキレシピ 2007.12.7 akiyan.com 秋田真宏

CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

Embed Size (px)

DESCRIPTION

http://www.akiyan.com/

Citation preview

Page 1: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

CakePHPをさらにDRYにするドライケーキレシピ

2007.12.7akiyan.com 秋田真宏

Page 2: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

かなりピンポイントな話をします

Page 3: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

コードがたくさん出てきます

Page 4: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

自己紹介

Page 5: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

秋田真宏

Page 6: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

あきやん

Page 7: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

青い人

Page 8: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

石川県出身(県庁所在地:金沢)

Page 9: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

何やってる人?

Page 10: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

会社員

Page 11: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

自社開発系

Page 12: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

プログラマー

Page 13: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

SE

Page 14: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

Cake歴 約1年

Page 15: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

akiyan.com 管理人

Page 16: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

Webサービスいろいろ

Page 17: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

gihyo.jpでCakePHPの連載を執筆しています

Page 18: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

自己紹介おわり

Page 19: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

本編ここから

Page 20: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

Conditionsとarray_mergeでDRYになる!

Page 21: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

Conditionsとは?

Page 22: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

Cakeのモデルのfind系メソッドに渡す検索条件

Page 23: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

配列か文字列を渡せる

Page 24: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

配列の例

Page 25: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

$this->User->findAll(array(‘status’ => ‘active’,‘confirmed_email’ => ‘yes’,

))

Page 26: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

文字列の例

Page 27: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

$this->User->findAll(” status = ‘active’ AND confirmed_email = ‘YES’ ”

)

Page 28: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

今回は配列に注目します

Page 29: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

で、

Page 30: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

毎回Conditionsを書くのは面倒だし、

条件が多いと書き忘れがち

Page 31: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

findをDRYにしたい!

Page 32: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

その前に、「DRY」って何?

Page 33: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

DRYとは

Page 34: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

Don’tRepeatYourselfの略

Page 35: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

意味は

「繰り返して書くな」

Page 36: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

というわけで

Page 37: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

さっきのfindをDRYにしてみる

Page 38: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

ありがちな実装

Page 39: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

モデルに専用メソッドを定義する

Page 40: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

Class User extends AppModel {var $name = ‘User’;function getActiveUser() {return $this->User->findAll(array(‘status’ => ‘active’,‘confirmed_email’ => ‘yes’,

));}

}

$this->User->getActiveUser();

Page 41: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

これでもいいっちゃいいけど

Page 42: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

LimitとOffset(page)とか指定したくなったら?

Page 43: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

解決例:メソッドを拡張する

Page 44: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

Class User extends AppModel {var $name = ‘User’;function getActiveUser($limit = null, $page = null) {return $this->User->findAll(array(‘status’ => ‘active’,‘confirmed_email’ => ‘yes’,

), null, null, $limit, $page);}

}

Page 45: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

さらにソート条件も指定したくなったら?

Page 46: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

やっぱりメソッドを拡張する

Page 47: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

Class User extends AppModel {var $name = ‘User’;function getActiveUser($order = null, $limit = null,

$page = null) {return $this->User->findAll(array(‘status’ => ‘active’,‘confirmed_email’ => ‘yes’,

), null, $order, $limit, $page);}

}

Page 48: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

さらにさらに取得フィールドも指定…

Page 49: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

…って、やってらんない

Page 50: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

機能を増やせば増やすほどどんどん元のfindAllメソッドに

近づいていく

Page 51: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

専用メソッドを作るたびにfindAllに似たようなものを

作るのは、そもそもDRYじゃない

Page 52: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

そこで

Page 53: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

案 1

Page 54: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

よく使うConditionsをモデルのメンバ変数に

定義しておく

Page 55: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

Class User extends AppModel {var $name = ‘User’;var $cond_activeuser = array(‘status’ => ‘active’,‘confirmed_email’ => ‘yes’,

};}

$this->User->findAll($this->User->cond_activeuser);

Page 56: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

案1のメリット

Page 57: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

find(all)の機能がそのまま使える

Page 58: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

メソッドを選ばない

(find, findAll, generateListなど)

Page 59: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

お手軽

(メンバ変数に定義するだけ)

Page 60: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

Conditionsのカスタマイズもそこそこ柔軟

Page 61: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

例えば、性別条件を追加するとき

Page 62: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

サンプル

Page 63: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

// 性別条件を追加$this->User->findAll(am($this->User->cond_activeuser,array(‘sex’ => ‘male’)

));

Page 64: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

解説

Page 65: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

// 性別条件を追加$this->User->findAll(am($this->User->cond_activeuser,array(‘sex’ => ‘male’)

));

am = cake/basics.phpで定義された、array_mergeへのエイリアス

Page 66: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

// 性別条件を追加$this->User->findAll(am($this->User->cond_activeuser,array(‘sex’ => ‘male’)

));

cond_activeuserの配列に‘sex’ キーで ‘male’ の値をマージ。

Page 67: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

// 結果

Array([status] => active[confirmed_email] => yes[sex] => male

)

Page 68: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

とりあえずは案 1で結構いける

Page 69: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

Page 70: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

Conditionsが複雑になるとちょっと非力

Page 71: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

例えば複数条件(or)があるような

Conditionsとか

Page 72: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

Page 73: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

Class User extends AppModel {var $name = ‘User’;var $cond_activeuser = array(‘or’ => array(array(‘status’ => ‘active’,‘confirmed_email’ => ‘yes’,

),array(‘status’ => ‘active’,‘confirmed_phone’ => ‘yes’,

),),

);}

Page 74: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

わかりにくいのでprint_rした形で

Page 75: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

Array([or] => Array([0] => Array([status] => active[confirmed_email] => yes

)[1] => Array([status] => active[confirmed_phone] => yes

))

)

Page 76: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

このConditionsに適切に性別条件を追加するには?

Page 77: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

array_mergeでは、まず無理

Page 78: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

array_merge_recursiveも試してみたけどできなかった

Page 79: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

失敗例

Page 80: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

array_merge_recursive($this->User->cond_activeuser,array('or' => array(array('sex' => 'male'),

))

)

Page 81: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

結果

Page 82: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

Array([or] => Array(

[0] => Array(

[status] => active[confirmed_email] => yes

)[1] => Array

([status] => active[confirmed_phone] => yes

)[2] => Array

([sex] => male

))

)

Page 83: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

惜しい orz

Page 84: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

お寒い成功例

Page 85: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

$cond = $this->User->cond_activeuser;$cond[‘or’][0][‘sex’] = ‘male’;$cond[‘or’][1][‘sex’] = ‘male’;

Page 86: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

元のConditionsによって条件を追加する方法が変わってしまう

Page 87: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

そもそも中間変数を必要としてしまっている

Page 88: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

ありえない

Page 89: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

そこで、

Page 90: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

案 2

Page 91: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

Conditionsを返す関数を用意する

Page 92: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

引数に追加条件を渡すとよしなにマージしてくれる

機能つき

Page 93: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

実装例 1

Page 94: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

Class User extends AppModel {var $name = ‘User’;function getActiveCond($merger) {

return am(array(‘status’ => ‘active’,‘confirmed_email’ => ‘yes’,

), $merger);}

}

Page 95: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

$this->User->getActiveCond(array(‘sex’ => ‘male’));

Array([status] => active[confirmed_email] => yes[sex] => male

)

Page 96: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

この例はメンバ変数版との差はほとんど無い

(array_mergeでも普通にできちゃうから)

Page 97: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

複数条件のあるConditionsで真価を発揮

Page 98: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

実装例 2複数条件

Page 99: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

Class User extends AppModel {var $name = ‘User’;function getActiveCond($merger) {return array(‘or’ => array(am(array(‘status’ => ‘active’,‘confirmed_email’ => ‘yes’,

), $merger),am(array(‘status’ => ‘active’,‘confirmed_phone’ => ‘yes’,

), $merger),),

);}

}

Page 100: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

使ってみる

Page 101: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

$this->User->getActiveCond(array(‘sex’ => ‘male’));

Array([or] => Array(

[0] => Array(

[status] => active[confirmed_email] => yes[sex] => male

)[1] => Array

([status] => active[confirmed_phone] => yes[sex] => male

))

)

Page 102: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

できた!

Page 103: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

案2のメリット

Page 104: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

メソッドを選ばない

(案1と同じく)

Page 105: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

複雑な条件でも、追加条件を渡すだけで

Conditionsをカスタム可能

Page 106: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

元の条件が変化してもコントローラー側のコードは変更しなくてもよい

Page 107: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

それって超DRY!

Page 108: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

ドライケーキ一つ焼き上がり!

←銀座洋菓子舗ウエストにDry cake というケーキがあるらしいhttp://www.ginza-west.co.jp/

Page 109: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

いろいろやってみて気づいたこと

Page 110: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

レコード検索の条件指定が連想配列だと

とても加工しやすい

Page 111: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

SQLをsprintfとかで組み上げていた頃からは考えられない柔軟性

(prepareもしかり)

Page 112: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

SQLをコードで組み立てるのは、別の言語のコードを

コードによって組み立てるような非常に煩雑な作業なのでは…?

Page 113: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

Conditions万歳(^o^)

Page 114: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

以上、Conditionsとarray_merge

でDRYになる!でした

Page 115: CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏

ご静聴ありがとうございました