CakePHP

【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も表示するようにしています。

HABTM_va_list_2_1

上の方に、(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は以下の感じ。

画面

HABTM_va_list_2_2

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世
千葉 繁 氏 / うる星やつら, ハイスクール!奇面組, アニメ三銃士
平野 文 氏 / うる星やつら, アニメ三銃士

が抽出されます。

うーむ、奥深い。

-CakePHP
-,