CakePHP multipla nidificato entra a far parte
-
22-09-2019 - |
Domanda
Ho un app in cui molti dei modelli sono collegate da Associazioni / belongsTo hasMany. Così, per esempio, A hasMany B, B hasMany C, C hasMany D, e D hasMany E. Inoltre, E appartiene a D, D appartiene a C, C appartiene a B e B appartiene ad A. Utilizzando il comportamento contenibile è stata grande per controllare la quantità di informazioni torna con ogni query, ma mi sembra di avere un problema quando si cerca di ottenere i dati dalla tabella a durante l'utilizzo di una condizione che coinvolge tabella D. per esempio, ecco un esempio della mia 'a' modello:
class A extends AppModel {
var $name = 'A';
var $hasMany = array(
'B' => array('dependent' => true)
);
function findDependentOnE($condition) {
return $this->find('all', array(
'contain' => array(
'B' => array(
'C' => array(
'D' => array(
'E' => array(
'conditions' => array(
'E.myfield' => $some_value
)
)
)
)
)
)
));
}
}
Questo mi dà ancora indietro tutti i record in 'A', e se è legato 'E' record non soddisfano la condizione, allora ottengo solo questo:
Array(
[0] => array(
[A] => array(
[field1] => // stuff
[field2] => // more stuff
// ...etc
),
[B] => array(
[field1] => // stuff
[field2] => // more stuff
// ...etc
),
[C] => array(
[field1] => // stuff
[field2] => // more stuff
// ...etc
),
[D] => array(
[field1] => // stuff
[field2] => // more stuff
// ...etc
),
[E] => array(
// empty if 'E.myfield' != $some_value'
)
),
[1] => array( // ...etc )
)
Quando Se 'E.myfield'! = $ Some_value, non voglio il record restituito a tutti.
Spero che questo esprime il mio problema in modo sufficientemente chiaro ...
In sostanza, voglio la seguente query, ma in un database agnostico / CakePHP-y tipo di strada:
SELECT *
FROM A INNER JOIN
(B INNER JOIN
(C INNER JOIN
(D INNER JOIN
E ON D.id=E.d_id)
ON C.id=D.c_id)
ON B.id=C.b_id)
ON A.id=B.a_id
WHERE E.myfield = $some_value
Soluzione
Il tuo problema è un equivoco di ciò che il comportamento contenibile fa e ciò che l'opzione contain
fa in Model::find
. La chiamata Model::find
nel primo codice di esempio-si tradurrebbe grosso modo:
Trova tutti A; poi trovare tutti i B associato ad ogni A; poi trovare tutti i C associata a ciascun B; poi trovare tutte D associata a ciascun C; infine, trovare tutte e associata a ciascun D dove un campo in E corrisponde a un valore specificato.
La dichiarazione condizione filtra solo i risultati di D, non all'altezza della catena a C, poi B, poi R. Se si esegue la scansione del registro di SQL, si vedrà un numero enorme di query tirando fuori ogni livello della catena di contain
.
Al fine di ottenere CakePHP per restituire i risultati come si desidera, direttamente dalla banca dati, che avrebbe dovuto configurare un'associazione hasOne
tra A e E. Con una lunga catena, come lei descrive, questo potrebbe essere abbastanza ingombrante. Sarebbe sembrare qualcosa di simile (leggi: non testata):
$this->bindModel(array('hasOne'=>array(
'B'=>array(
'foreignKey' => false,
'conditions' => array('A.id = B.a_id')
),
'C'=>array(
'foreignKey' => false,
'conditions' => array('B.id = C.b_id')
),
'D'=>array(
'foreignKey' => false,
'conditions' => array('C.id = D.c_id')
),
'E'=>array(
'foreignKey' => false,
'conditions' => array('D.id = E.d_id')
)
)));
$this->find('all', array(
'conditions' => array( 'E.my_field' => $some_value )
));
Un'alternativa è di eliminare la condizione E.my_value
interamente dalla chiamata Model::find
, e invece eseguire un Set::extract
abbastanza complesso alla fine:
$results = $this->find('all', array(
'contain' => array(
'B' => array(
'C' => array(
'D' => array(
'E' => array()
)
)
)
)
));
return Set::extract("/A/B/C/D/E[my_field={$some_value}]/../../../../", $results);
Performance sarebbe un vero problema con un Set::extract
profondo, però, soprattutto se si stesse operando su un sacco di righe.
Modifica : voglio solo sottolineare quanto sia terribile l'idea l'opzione Set::extract
è se questa operazione ha bisogno di scala. Si sposta il intero onere di filtraggio dal motore di database sulle funzioni di array di PHP.