Come posso unire due tabelle in una terza relazione n..n (hasAndBelongsToMany) in CakePHP?
-
02-07-2019 - |
Domanda
Ho una struttura n ... n
per due tabelle, ma
e modelli
. Finora nessun problema.
In una terza tabella ( prodotti
) come:
id
make_id
model_id
...
Il mio problema è la creazione di una vista per prodotti di una specifica ma
all'interno del mio ProductsController
contenente solo i modelli di marca:
Ho pensato che potesse funzionare:
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
Quindi, se voglio usare list
per passare alla mia vista per creare pulsanti di opzione, dovrò fare un foreach ()
nel mio < code> make array per trovare tutti i titoli dei modelli e creare un nuovo array e inviarlo alla vista tramite $ this- > set ()
.
$makeArray = $this->Make->find();
foreach ($makeArray['Model'] as $model) {
$modelList[] = $model['title'];
}
$this->set('models', $models)
Esiste un modo più semplice per ottenere tale elenco senza stressare l'array make
. Sarà un compito comune sviluppare tali scenari nelle mie applicazioni.
Grazie in anticipo per qualsiasi suggerimento!
Soluzione 5
La soluzione può essere raggiunta con l'uso dell'operazione with
nella matrice habtm sul modello.
Usando con
puoi definire " middle " tabella come:
$habtm = " ...
'with' => 'MakeModel',
... ";
E internamente, nel Modello o nel Controller, è possibile emettere condizioni per il metodo find
.
Altri suggerimenti
Ecco il mio suggerimento: prova a scrivere la tua query in SQL normale prima di provare a ricostruire usando la libreria Cake. In sostanza stai facendo un sacco di lavoro extra che il DB può fare per te. Il tuo approccio (solo per show - SQL non buono):
SELECT * FROM makes, models, products WHERE make_id = 5
Non stai prendendo in considerazione le relazioni (a meno che Cake non capisca automaticamente le relazioni delle tabelle)
Probabilmente stai cercando qualcosa che unisca queste cose:
SELECT models.title FROM models
INNER JOIN products
ON products.model_id = models.model_id
AND products.make_id = 5
Speriamo che questa sia una spinta nella giusta direzione?
A giudicare dal tuo commento, ciò che stai chiedendo è come ottenere risultati da un determinato modello, in cui la condizione è in un modello correlato a HABTM. Cioè qualcosa che faresti normalmente con un'istruzione JOIN in SQL raw.
Attualmente è uno dei pochi punti deboli di Cake. Esistono diverse strategie per affrontarlo.
-
Chiedi al modello B correlato di restituire tutti gli ID dei possibili candidati per il modello A, quindi esegui una seconda query sul modello A. I.e .:
$this->ModelB->find('first', array('conditions' => array('field' => $condition))); array( ['ModelB'] => array( ... ), ['ModelA'] => array( [0] => array( 'id' => 1 ) )
Ora hai un array di tutti gli ID di ModelA che appartengono a ModelB che corrispondono alle tue condizioni, che puoi estrarre facilmente usando Set :: extract (). Fondamentalmente l'equivalente di
SELECT model_a.id FROM model_b JOIN model_a DOVE model_b.field = xxx
. Quindi cerchi ModelA:$this->ModelA->find('all', array('conditions' => array('id' => $model_a_ids)));
Questo produrrà
SELEZIONA model_a. * FROM model_a WHERE id IN (1, 2, 3)
, che è un modo rotonda di fare l'istruzione JOIN. Se sono necessarie condizioni su più di un modello correlato, ripetere fino a quando non si hanno tutti gli ID per ModelA, SQL utilizzerà l'intersezione di tutti gli ID (WHERE id IN (1, 2, 3) E id IN (3, 4 , 5)
). -
Se hai bisogno di una sola condizione su ModelB ma vuoi recuperare ModelA, cerca ModelB. Cake recupererà automaticamente i ModelAs correlati per te (vedi sopra). Potrebbe essere necessario Set :: extract () di nuovo, ma potrebbe essere già sufficiente.
-
Puoi usare il metodo sopra e combinarlo con il Comportamento contenitore per avere un maggiore controllo sui risultati.
-
Se tutto il resto fallisce o i metodi sopra descritti producono semplicemente un sovraccarico eccessivo, puoi comunque scrivere il tuo SQL grezzo con
$ this- > Model- > query ()
. Se ti attieni agli standard Cake SQL (denominando correttamente le tabelle conFROM model_as AS ModelA
) Cake continuerà comunque a elaborare correttamente i risultati.
Spero che questo ti mandi nella giusta direzione.
Tutte le tue diverse chiamate Make- > find () e Model- > find () sono completamente indipendenti l'una dall'altra. Anche Make- > Model- > find () è lo stesso di Model- > find (), Cake non ricorda in alcun modo o tiene conto di ciò che hai già trovato in altri modelli. Quello che stai cercando è qualcosa di simile:
$this->Product->find('all', array('conditions' => array('make_id' => 5)));
Dai un'occhiata al metodo Set :: extract () per ottenere un elenco di titoli dei modelli dai risultati di $ this- > Make- > find ()