【CakePHP2】HABTMモデルの練習 その2
2015/03/18
前回はとりあえずHABTMモデルを作っただけでしたので、もう少しだけ踏み込んで拡張してみたいと思います。
テーブルの拡張と検索用フォームの作成
テーブル拡張
voiceactorsテーブルに五十音で検索できるようになどを考えて氏名カナ、性別を追加。
レコードは適宜作成。
1 2 3 4 5 6 7 8 9 10 11 |
CREATE TABLE `atn_voiceactors` ( `id` INT UNSIGNED AUTO_INCREMENT, -- `created` DATETIME DEFAULT NULL, -- `modified` DATETIME DEFAULT NULL, -- `delete_flg` TINYINT NOT NULL default '0', -- 削除フラグ `publish_flg` TINYINT NOT NULL default '1', -- 公開フラグ `name` VARCHAR(255), -- 氏名 `name_kana` VARCHAR(255), -- 氏名カナ `gender_flg` TINYINT default 3, -- 性別フラグ(1:男 / 2:女 / 3:不明) PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
Voiceactor一覧画面からAnime別で検索
現在のレコードは以下の感じ。
なお、一覧でVoiceactorが参加したAnimeも表示するようにしています。
上の方に、(Gender)性別、Ainimeをオプションとして検索できるように、フォームを追加。
このフォームを稼働させることが今回の目的です。
HABTMでの検索
テーブル結合
では本題。
画面にもありますが、Voiceactor一覧画面に、参加しているAnimeの一覧は取得できるのですが、このままでは Voiceactor一覧画面から Animeを条件として検索しようとしても、テーブルを連結していないため抽出することは出来ません。
なので、テーブルを連結して find すれば良いということですね。
ということで、find 部分に手を加えます。
マニュアル参照
アソシエーション: モデル同士を繋ぐ - CakePHP Cookbook 2.x ドキュメント
http://book.cakephp.org/2.0/ja/models/associations-linking-models-together.html#id6
ほぼ、マニュアルそのまんまでOK。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
// 検索オプション $options = array( 'joins' => array( array( 'table' => 'animes_voiceactors', // joinするテーブル名 'alias' => 'AnimesVoiceactor', // テーブルの別名。テーブルのモデルの名前と同じにするのが良いです 'type' => 'INNER', // oin種別。inner、left、rightのいずれか 'conditions' => array( 'Voiceactor.id = AnimesVoiceactor.voiceactor_id' // joinの時の条件を指定 ) ), array( 'table' => 'animes', 'alias' => 'Anime', 'type' => 'INNER', 'conditions' => array( 'AnimesVoiceactor.anime_id = Anime.id' ) ), ), 'conditions' => $conditions, 'fields' => null, 'order' => array('Voiceactor.id' => 'ASC'), 'recursive' => 1, 'group' => 'Voiceactor.id' ); // Voiceactor一覧取得 $voiceactor_data = $this->Voiceactor->find('all', $options); |
画面のAnimeを「アニメ三銃士」とした場合の画面と、作成されるSQLは以下の感じ。
画面
Voiceactorの抽出部
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
SELECT `Voiceactor`.`id`, `Voiceactor`.`created`, `Voiceactor`.`modified`, `Voiceactor`.`delete_flg`, `Voiceactor`.`publish_flg`, `Voiceactor`.`name`, `Voiceactor`.`name_kana`, `Voiceactor`.`gender_flg` FROM `antenna`.`atn_voiceactors` AS `Voiceactor` INNER JOIN `antenna`.`atn_animes_voiceactors` AS `AnimesVoiceactor` ON (`Voiceactor`.`id` = `AnimesVoiceactor`.`voiceactor_id`) INNER JOIN `antenna`.`atn_animes` AS `Anime` ON (`AnimesVoiceactor`.`anime_id` = `Anime`.`id`) WHERE `Voiceactor`.`publish_flg` = 1 AND `AnimesVoiceactor`.`anime_id` = (6) GROUP BY `Voiceactor`.`id` ORDER BY `Voiceactor`.`id` ASC |
これで、
ID:2 / 神谷 明 氏
ID:3 / 千葉 繁 氏
ID:4 / 平野 文 氏
が抽出され、
Animeの抽出部
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
SELECT `Anime`.`id`, `Anime`.`created`, `Anime`.`modified`, `Anime`.`delete_flg`, `Anime`.`publish_flg`, `Anime`.`title`, `AnimesVoiceactor`.`id`, `AnimesVoiceactor`.`created`, `AnimesVoiceactor`.`modified`, `AnimesVoiceactor`.`delete_flg`, `AnimesVoiceactor`.`publish_flg`, `AnimesVoiceactor`.`voiceactor_id`, `AnimesVoiceactor`.`anime_id` FROM `antenna`.`atn_animes` AS `Anime` JOIN `antenna`.`atn_animes_voiceactors` AS `AnimesVoiceactor` ON (`AnimesVoiceactor`.`voiceactor_id` IN (2, 3, 4) AND `AnimesVoiceactor`.`anime_id` = `Anime`.`id`) |
これで、
神谷 明 氏 / うる星やつら, シティハンター, アニメ三銃士, バビル2世
千葉 繁 氏 / うる星やつら, ハイスクール!奇面組, アニメ三銃士
平野 文 氏 / うる星やつら, アニメ三銃士
が抽出されます。
うーむ、奥深い。