CakePHP の 3 番目の n..n (hasAndBelongsToMany) リレーションシップで 2 つのテーブルを結合するにはどうすればよいですか?
-
02-07-2019 - |
質問
私は持っています n...n
2 つのテーブルの構造、 makes
そして models
. 。これまでのところ問題はありません。
3 番目のテーブル (products
) のように:
id
make_id
model_id
...
私の問題は、特定の製品のビューを作成することです make
私の中で ProductsController
これだけが含まれているのはモデルの作成だけです:
これはうまくいくかもしれないと思いました:
var $uses = array('Make', 'Model');
$this->Make->id = 5; // My Make
$this->Make->find(); // Returns only the make I want with it's Models (HABTM)
$this->Model->find('list'); // Returns ALL models
$this->Make->Model->find('list'); // Returns ALL models
それで、私が使用したい場合は、 list
ラジオボタンを作成するためにビューに渡すには、次のことを行う必要があります foreach()
私の中で make
配列を使用してすべてのモデルのタイトルを検索し、新しい配列を作成してビューに送信します。 $this->set()
.
$makeArray = $this->Make->find();
foreach ($makeArray['Model'] as $model) {
$modelList[] = $model['title'];
}
$this->set('models', $models)
ストレスを与えずにそのリストを取得する簡単な方法はありますか? make
配列。私のアプリケーションでそのようなシナリオを開発するのは一般的なタスクになります。
何かヒントがあればよろしくお願いします!
解決 5
この解決策は、 with
モデル上の habtm 配列での操作。
使用する with
「中間」テーブルは次のように定義できます。
$habtm = " ...
'with' => 'MakeModel',
... ";
そして内部的には、モデルまたはコントローラーで、条件を find
方法。
他のヒント
私のヒントは次のとおりです。Cake ライブラリを使用して再構築する前に、クエリを通常の SQL で作成してみてください。本質的には、DB が代わりに実行できる多くの追加作業を行っていることになります。あなたのアプローチ(ショーのためだけ - 良いSQLではありません):
SELECT * FROM makes, models, products WHERE make_id = 5
リレーションシップを考慮していません (Cake が自動的にテーブルのリレーションシップを魔法のように理解しない限り)
あなたはおそらく、次のものを結合するものを探しているでしょう。
SELECT models.title FROM models
INNER JOIN products
ON products.model_id = models.model_id
AND products.make_id = 5
これが正しい方向へのナッジであることを願っていますか?
コメントから判断すると、あなたが求めているのは、条件が HABTM 関連モデルにある特定のモデルから結果を取得する方法です。つまり、これは通常、生の SQL で JOIN ステートメントを使用して実行するものです。
現時点では、それが Cake の数少ない弱点の 1 つです。それに対処するにはさまざまな戦略があります。
関連モデル B にモデル A の考えられる候補のすべての ID を返させてから、モデル A に対して 2 番目のクエリを実行します。つまり:
$this->ModelB->find('first', array('conditions' => array('field' => $condition))); array( ['ModelB'] => array( ... ), ['ModelA'] => array( [0] => array( 'id' => 1 ) )
これで、条件に一致する ModelB に属する ModelA のすべての ID の配列が得られ、Set::extract() を使用して簡単に抽出できます。基本的には以下と同等です
SELECT model_a.id FROM model_b JOIN model_a WHERE model_b.field = xxx
. 。次に ModelA を探します。$this->ModelA->find('all', array('conditions' => array('id' => $model_a_ids)));
それが生み出すのは
SELECT model_a.* FROM model_a WHERE id IN (1, 2, 3)
, 、これは JOIN ステートメントを実行する回りくどい方法です。複数の関連モデルの条件が必要な場合は、ModelA のすべての ID が得られるまで繰り返します。SQL ではすべての ID の共通部分が使用されます (WHERE id IN (1, 2, 3) AND id IN (3, 4, 5)
).ModelB の条件が 1 つだけ必要で、ModelA を取得したい場合は、ModelB を検索するだけです。Cake は、関連する ModelAs を自動的に取得します (上記を参照)。再度 Set::extract() する必要があるかもしれませんが、それだけで十分かもしれません。
上記の方法を使用して、 抑制可能な動作 結果をより詳細に制御できるようになります。
他のすべてが失敗する場合、または上記の方法で単にオーバーヘッドが多すぎる場合でも、次のコマンドを使用して独自の生の SQL を作成できます。
$this->Model->query()
. 。Cake SQL 標準に従う場合 (テーブルに正しい名前を付ける場合)FROM model_as AS ModelA
) Cake は引き続き結果を正しく後処理します。
これがあなたを正しい方向に導いてくれることを願っています。
さまざまな Make->find() 呼び出しと Model->find() 呼び出しはすべて、互いに完全に独立しています。Make->Model->find() は Model->find() と同じであり、Cake は他のモデルですでに見つけたものをまったく記憶したり考慮したりしません。探しているものは次のようなものです:
$this->Product->find('all', array('conditions' => array('make_id' => 5)));
$this->Make->find() の結果からモデル タイトルのリストを取得する Set::extract() メソッドを確認してください。