以下は、ケーキ1.3で試験した。
class Post extends AppModel {
var $hasAndBelongsToMany = 'Tag';
}
class Tag extends AppModel {
var $hasAndBelongsToMany = 'Post';
}
をケーキの独自のドキュメントによると::
がしたい、またはすでに実行し、これが正常に適用される他のすべての状況のためのモデルで定義されたHABTM関係を持っている、おそらくあなたを開始するには、[
1]
いくつかの団体(belongsToのとhasOneのは)自動実行CakePHPでは
あなたは、関連する1のデータに基づいてモデル を取得するためにクエリを発行することができますので、データを取得するために結合します。
ただし、これはhasManyとhasAndBelongsToManyの関連付けでは当てはまりません。ここに があります。ここで強制的にジョインするのがレスキューです。必要な結合を定義するだけで、テーブルを結合してクエリに望ましい結果を得るのに、 が必要です。
空のHABTM結果を除外するのは、これらの時間のうちの1つです。ケーキブックのこの同じセクションでは、これを達成する方法について説明していますが、結果が得られたテキストを読んであまりにも明白ではありませんでした。 Cake Bookの例では、タグ - >投稿タグ - >投稿の代わりに、ブック - >ブックタグ - >タグの\ joinパスを使用しています。この例では、TagControllerから次のように設定します。
$options['joins'] = array(
array(
'table' => 'posts_tags',
'alias' => 'PostsTag',
'type' => 'INNER',
'foreignKey' => false,
'conditions' => 'PostsTag.tag_id = Tag.id'
),
array(
'table' => 'posts',
'alias' => 'Post',
'type' => 'INNER',
'foreignKey' => false,
'conditions' => 'Post.id = PostsTag.post_id'
)
);
$tagsWithPosts = $this->Tag->find('all', $options);
foreignKeyをfalseに設定してください。これはCakeに、結合条件を把握せず、代わりに指定した条件だけを使用するようにすべきであることを伝えます。
これは、ジョインの性質上、重複した行を戻すのが一般的です。返されるSQLを減らすには、必要に応じてフィールドにDISTINCTを使用します。すべてのフィールドが通常find( 'all')によって返されるようにする場合は、各列をハードコードするために必要な複雑さが加わります。 (あなたのテーブル構造はそれを頻繁に変えるべきではありませんが、それが起こる可能性があります。プログラムですべての列をつかむために、findメソッド呼び出しの前に、以下を追加します。
$options['fields'] = array('DISTINCT Tag.'
. implode(', Tag.', array_keys($this->Tag->_schema)));
// **See note
HABTM関係が AFTER主な選択を実行していることに注意することが重要です。本質的に、Cakeは適格なタグのリストを取得し、関連するPostを得るためにSELECTステートメントの別のラウンドを実行します。これはSQLのダンプから見ることができます。手動で設定した「結合」は最初の選択に適用され、希望するタグのセットが与えられます。その後、組み込みのHABTMが再び実行され、関連するすべてのPostがそれらのタグに与えられます。私たちは目標である投稿を持たないタグは持っていませんが、追加された場合、私たちは当初の条件の一部ではないタグに関連付けられた投稿を得ることができます。
$options['conditions'] = 'Post.id = 1';
は、次のような結果が得られます:以下の条件の追加例えば
、問題のサンプルデータに基づいて
Array (
[0] => Array (
[Tag] => Array (
[id] => 1
[name] => 'Tag1')
[Post] => Array (
[0] => Array (
[id] => 1
[title] => 'Post1')
[1] => Array (
[id] => 4
[title] => 'Post4'))
)
)
は、唯一のタグ1は、当社の「条件」と関連していましたステートメント。したがって、これは '結合'によって返された唯一の結果でした。しかし、HABTMはこの後に実行されたので、Tag1に関連付けられたすべての投稿(Post1とPost4)を取得しました。
明示的な結合を使用して目的の初期データセットを取得するこの方法も、Quick Tip - Doing Ad-hoc Joins in Model::find()で説明しています。また、このテクニックを一般化して、それをAppModelに追加する方法を示します(find()を拡張)。
私たちは本当にだけで、我々は 'を含む' [2]オプション句を追加する必要があり、同様POST1を見たい場合は、次の結果を与える
$this->Tag->Behaviors->attach('Containable');
$options['contain'] = 'Post.id = 1';
:
Array (
[0] => Array (
[Tag] => Array (
[id] => 1
[name] => 'Tag1')
[Post] => Array (
[0] => Array (
[id] => 1
[title] => 'Post1'))
)
)
代わりのをContainableを使用すると、bindModelを使用して、find()のこのインスタンスでHABTM関係を再定義できます。私は初心者がケーキのオートマジック能力の周りに頭をラップしようとしているため、明示的なジョイン作ることは(私はそれがあった知って見ると理解しやすいと感じる
$this->Tag->bindModel(array(
'hasAndBelongsToMany' => array(
'Post' => array('conditions' => 'Post.id = 1'))
)
);
:bindModelでは、目的のポストの条件を追加します私のために)。これを行うもう1つの有効かつ間違いなくもっと 'Cake'の方法は、unbindModelとbindModelを排他的に使用することです。 http://nuts-and-bolts-of-cakephp.comのTeknoidには、これを行う方法に関する良い書き方があります:http://nuts-and-bolts-of-cakephp.com/2008/07/17/forcing-an-sql-join-in-cakephp/。さらに、teknoidはこれをgithubから得ることができる行動にしました:http://nuts-and-bolts-of-cakephp.com/2009/09/26/habtamable-behavior/
**これは、データベースで定義された順序で列を引き出します。したがって、主キーが最初に定義されていない場合は、DISTINCTが期待どおりに適用されないことがあります。 array_diff_keyを使用して$ this-> Model-> primaryKeyのプライマリキーを除外するには、これを変更する必要があります。
[この投稿](http://www.volved.com/index.php/2009/03/26/cakephp-12-group-by-with-having-count-habtm-associations-limit-the-関連するデータベースのクエリ)はこの問題に対処しているようです。しかし、1.3。 – Ross