Como faço para participar de duas tabelas em um relacionamento terceiro n..n (hasAndBelongsToMany) em CakePHP?
-
02-07-2019 - |
Pergunta
Eu tenho uma estrutura n...n
para duas tabelas, makes
e models
. Até agora não há problema.
Em uma terceira tabela ( products
) como:
id
make_id
model_id
...
Meu problema é a criação de uma exibição para produtos de uma específi make
dentro da minha ProductsController
contendo apenas isso de fazer modelos:
Eu pensei que isso poderia funcionar:
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
Então, se eu quiser usar o list
para passar para meu ponto de vista para criar botões de rádio que vou ter que fazer uma foreach()
na minha make
array para encontrar todos os modelos títulos e criar uma nova matriz e enviar para a view via $this->set()
.
$makeArray = $this->Make->find();
foreach ($makeArray['Model'] as $model) {
$modelList[] = $model['title'];
}
$this->set('models', $models)
Existe alguma maneira mais fácil de obter essa lista sem forçar o make
Matriz. Será uma tarefa comum a desenvolve tais cenários na minha candidatura (s).
Agradecemos antecipadamente por qualquer dica!
Solução 5
A solução pode ser conseguido com a utilização da operação with
na matriz habtm no modelo.
Usando with
você pode definir a tabela "meio" como:
$habtm = " ...
'with' => 'MakeModel',
... ";
E internamente, no modelo ou Controller, você pode emitir condições para o método find
.
Outras dicas
Aqui está a minha dica: Tente obter sua consulta escrito em SQL normal antes de tentar reconstruir usando a biblioteca bolo. Em essência, você está fazendo um monte de trabalho extra que a DB pode fazer por você. Sua abordagem (apenas para mostrar - não é bom SQL):
SELECT * FROM makes, models, products WHERE make_id = 5
Você não está levando em consideração as relações (a menos bolo entende auto-magicamente as relações das tabelas)
Você provavelmente está procurando por algo que une essas coisas juntas:
SELECT models.title FROM models
INNER JOIN products
ON products.model_id = models.model_id
AND products.make_id = 5
Esperamos que este é um empurrão na direção certa?
A julgar pelo seu comentário, o que você está pedindo é como obter resultados de um determinado modelo, onde a condição é em um modelo relacionado HABTM. Ou seja, algo que você normalmente faria com um JOIN em SQL cru.
Atualmente é um dos poucos pontos fracos do bolo. Existem diferentes estratégias para lidar com isso.
-
Ter o modelo relacionado B devolver todos os ids de possíveis candidatos para o Modelo A, em seguida, fazer uma segunda consulta no Modelo A. ou seja:.
$this->ModelB->find('first', array('conditions' => array('field' => $condition))); array( ['ModelB'] => array( ... ), ['ModelA'] => array( [0] => array( 'id' => 1 ) )
Agora você tem uma matriz de todos ids de ModelA que pertencem a ModelB que corresponda às suas condições, que você pode facilmente extrair usando Set :: extract (). Basicamente, o equivalente de
SELECT model_a.id FROM model_b JOIN model_a WHERE model_b.field = xxx
. Em seguida, você procurar ModelA:$this->ModelA->find('all', array('conditions' => array('id' => $model_a_ids)));
Isso
SELECT model_a.* FROM model_a WHERE id IN (1, 2, 3)
irá produzir, que é uma forma indireta de fazer o JOIN. Se você precisa de condições em mais de um modelo relacionado, repita até que você tenha todos os ids para ModelA, SQL usará a intersecção de todos os ids (WHERE id IN (1, 2, 3) AND id IN (3, 4, 5)
). -
Se você só precisa de uma condição em ModelB mas deseja recuperar ModelA, basta procurar por ModelB. Bolo irá recuperar automaticamente ModelAs relacionados para você (veja acima). Você pode precisar Set :: extract () novamente, mas isso já pode ser suficiente.
-
Você pode usar o método acima e combiná-lo com a comportamento Containable para obter mais controle sobre os resultados.
-
Se tudo mais falhar ou os métodos acima simplesmente produzir muito em cima, você ainda pode escrever seu próprio SQL crua com
$this->Model->query()
. Se você ficar com as normas bolo SQL (nomear tabelas corretamente comFROM model_as AS ModelA
) Bolo vai ainda pós-processar os resultados corretamente.
Espero que isso envia-lo na direção certa.
Toda a sua diferente make> find () e Model-> find () são completamente independentes um do outro. Mesmo make> Model-> find () é o mesmo que Model-> find (), o bolo não de qualquer maneira lembrar ou ter em conta o que já encontradas em outros modelos. O que você está procurando algo como:
$this->Product->find('all', array('conditions' => array('make_id' => 5)));
Confira o método Set :: extract () para obter uma lista de títulos modelo a partir dos resultados de $ this-> make> find ()