Ваша проблема - неправильное представление о том, что делает поведение Containable и что опция contain
делает в Model::find
. Вызов Model::find
в вашем первом примере кода будет примерно равен:
Найти все А; затем найдите все B, связанные с каждым A; затем найдите все C, связанные с каждым B; затем найдите все D, связанные с каждым C; наконец, найдите все E, связанные с каждым D, где одно поле в E соответствует указанному значению.
Оператор условия фильтрует только результаты D, не вверх по цепочке до C, затем B, затем A. Если вы просканируете журнал SQL, вы увидите огромное количество запросов, вытягивающих каждый уровень вашего contain
цепь.
Чтобы CakePHP мог возвращать результаты по вашему желанию, прямо из базы данных, вам нужно настроить hasOne
связь между A и E. С длинной цепочкой, как вы описываете, это может быть довольно громоздкий. Это будет выглядеть примерно так (читай: не проверено):
$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 )
));
Альтернативой является полное удаление условия E.my_value
из вызова Model::find
и вместо этого выполнение довольно сложного Set::extract
в конце:
$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);
Производительность была бы реальной проблемой с глубоким Set::extract
, особенно если вы работали с большим количеством строк.
РЕДАКТИРОВАТЬ : Я просто хочу подчеркнуть, насколько ужасна идея Set::extract
, если эту операцию нужно масштабировать. Он переносит всю нагрузку фильтрации с ядра базы данных на функции массива PHP.