
【CakePHP2】HABTMモデルの練習 その2
2015/03/18
前回はとりあえずHABTMモデルを作っただけでしたので、もう少しだけ踏み込んで拡張してみたいと思います。
テーブルの拡張と検索用フォームの作成
テーブル拡張
voiceactorsテーブルに五十音で検索できるようになどを考えて氏名カナ、性別を追加。
レコードは適宜作成。
[default]
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;
[/default]
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。
[php]
// 検索オプション
$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);
[/php]
画面のAnimeを「アニメ三銃士」とした場合の画面と、作成されるSQLは以下の感じ。
画面
Voiceactorの抽出部
[sql]
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
[/sql]
これで、
ID:2 / 神谷 明 氏
ID:3 / 千葉 繁 氏
ID:4 / 平野 文 氏
が抽出され、
Animeの抽出部
[sql]
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
)
[/sql]
これで、
神谷 明 氏 / うる星やつら, シティハンター, アニメ三銃士, バビル2世
千葉 繁 氏 / うる星やつら, ハイスクール!奇面組, アニメ三銃士
平野 文 氏 / うる星やつら, アニメ三銃士
が抽出されます。
うーむ、奥深い。