Quantcast
Channel: まとめーたー
Viewing all articles
Browse latest Browse all 454

cakephp hasAndBelongsToMany ビヘイビア作ってみました

$
0
0
photoBy: http://www.shellbarbakery.com/wp-content/uploads/… hasAndBelongsToManyをできるだけ簡単に hasAndBelongsToMany ビヘイビアを作ってみた cakephpで一番便利だけど、一番難しいのが hasandbelongstomany。 ビヘイビアもネットでいくつかあるけどうまく動かない。 今回は以下の条件で作ってみました。 関連タグ を保存。ただし、すでにあるタグの場合は作成しない。 指定タグがいくつの記事を持っているか を countercacheを利用し、 Tagモデルに保存 できるだけ、簡単に。 Habtmビヘイビアを保存しよう /app/Model/Behavior/HabtmBehavior.php class HabtmBehavior extends ModelBehavior {         public function afterSave(Model $Model, $created) {                if (count($Model->hasAndBelongsToMany) > 0) {                        $Model->data = $Model->find('first',array('conditions' => array($Model->name . '.id' => $Model->getLastInsertID())));                        reset($Model->hasAndBelongsToMany);            $alias=key($Model->hasAndBelongsToMany);                    $HabtmModel = ClassRegistry::init($Model->hasAndBelongsToMany[$alias]['with']);                    $tag_ids = Set::combine($Model->data,'/'.$alias.'/./id','/'.$alias.'/./id');                        foreach($tag_ids as $v){                $HabtmModel->updateCounterCache(array($HabtmModel->belongsTo[$alias]['foreignKey'] => $v));            }                                }                return true;    }                function beforeDelete(Model $Model)    {        //hasAndBelongsToManyが設定されていれば         if (count($Model->hasAndBelongsToMany) > 0) {            $Model->data = $Model->find('first', array(                'conditions' => array($Model->name . '.id' => $Model->id)            ));            }                return true;    }            function afterDelete(Model $Model)    {         //関連モデルのカウンターキャッシュを更新          foreach ($Model->data as $alias => $modelData) {                        if (!empty($this->hasAndBelongsToMany[$alias])) {                $HabtmModel = ClassRegistry::init($Model->hasAndBelongsToMany[$alias]['with']);                            $tag_ids = Set::combine($Model->data,'/'.$alias.'/./id','/'.$alias.'/./id');                                foreach($tag_ids as $v){                    $HabtmModel->updateCounterCache(array($HabtmModel->belongsTo[$alias]['foreignKey'] => $v));                }                            }                }                        return true;    } } Appモデルに読み込ませる /Model/AppModel.php class AppModel extends Model {         public $actsAs = array(        'Habtm'    );         } ・appモデルに追記 /*         保存時にタグをカウントして保存     */    function saveAssociated($data = null, $options = array()) {                        foreach ($data as $alias => $AsModelData) {                                    if (!empty($this->hasAndBelongsToMany[$alias])) {                    $habtm = array();                    $AsModel = ClassRegistry::init($this->hasAndBelongsToMany[$alias]['className']);                     foreach ($AsModelData as $AsModelDatum) {                                                $AsModel->create();                                $id = $AsModel->find('first',array('conditions' => $AsModelDatum , 'fields' => array('id')));                                                                        if($id){                            //すでにデータが有る場合                             $habtm[] = $id[$AsModel->name]['id'];                                                        } else {                            //データがない場合 (タグ登録)                             $AsModel->save($AsModelDatum);                            $habtm[] = $AsModel->getLastInsertID();                        }                                            }                        $data[$alias] = array($alias => $habtm);            }        }        return parent::saveAssociated($data, $options);                    } ここまでで behaviorの準備完了。 DBとモデルの準備 今回はそれぞれ以下のphpと以下のテーブルフィールドを作る meigen.php (名言集)  tag.php (タグ)  habtmstag.php (名言とタグのリレーション) を作る。 hasAndBelongsToManyは、理解するまで難しいので、とにかく以下のコードを作ってみること。 テーブル作成 yourprefix を変更してテーブル作成 CREATE TABLE IF NOT EXISTS `yourprefix_habtms_tags` ( `id` int(11) NOT NULL AUTO_INCREMENT, `tag_id` int(11) NOT NULL, `meigen_id` int(11) NOT NULL COMMENT 'meigens テーブルの中間キー', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=ujis AUTO_INCREMENT=783 ; CREATE TABLE IF NOT EXISTS `yourprefix_meigens` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` text NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=243 ; CREATE TABLE IF NOT EXISTS `yourprefix_tags` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` text NOT NULL, `meigen_count` int(11) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=33 ; モデルを作成 Meigen.php <?php App::uses('Model', 'Model'); class Meigen extends AppModel {         var $hasAndBelongsToMany = array(        'Tag' => array(            'with' => 'HabtmsTag',            'foreignKey' => 'meigen_id',            'associationForeignKey' => 'tag_id'        ),    );     } Tag.php <?php    App::uses('AppModel', 'Model');    class Tag extends AppModel {                        var $validate = array(            'name' => array(                'rule' => 'isUnique'            )        );                var $hasMany = array(            'HabtmsTag' => array(                'foreignKey' => 'tag_id',            )        );    } HabtmsTag.php <?php App::uses('AppModel', 'Model');    class HabtmsTag extends AppModel {                var $belongsTo = array(            'Tag' => array(                'className' => 'Tag',                'foreignKey' => 'tag_id',                'conditions' => '',                'fields' => '',                'order' => '',                'counterCache' => array(                    'meigen_count' => array(                                ),                )            )        );                } いざ実践! MeigensController.php class MeigensController extends AppController {         function index()    {        $data = array(            'Meigen'=>array(                'name'=>'美味しい果物',            ),            'Tag'=>array(                0 => array(                    'name'=>'うどん'                ),                1 => array(                    'name'=>'スープ'                ),                2 => array(                    'name'=>'チゲなべ'                )                            )        );                if($this->Meigen->saveAssociated($data)){                    }                $this->autoRender = false;                    } } これで /meigens/index/ にアクセスすれば、 美味しい果物 という名言テーブルに うどん、スープ、チゲなべ というTagが登録、関連付されさらに Tag.meigen_count に、そのタグがいくつの名言を持っているか が保存されます。 deleteにも対応 deleteした時も Tag.meigen_count を計算しなおすので、便利です。

Viewing all articles
Browse latest Browse all 454