2014-01-30 3 views
0

У меня есть две ситуации, когда выполняются два похожих запроса, и в одной ситуации код для виртуального поля связанной модели не генерируется в sql запрос запроса и, следовательно, не найден.Виртуальное поле ассоциированной модели в похожих запросах, но иногда не встраивается в sql-запрос

В базе данных: * Два мастер-таблица (hospitals и hotels) * Один ссылочной таблица contacts * Мастер таблица имеет различные поля, указывающие на контактной таблицу. Для больниц, например. a director_contact_id и a janitor_contact_id. Для гостиниц a director_contact_id и concierge_contact_id.

В CakePHP * The Hospital модели имеет два belongsTo отношения DirectorContact и JanitorContact * The Hotel модель имеет два belongsTo отношение DirectorContact и ConciergeContact * контакты имеют виртуальное поле full_name, нечто вроде CONCAT(…)

В HospitalController , когда мне нужна одна из данных контакта, привязанных к данным больницы, я могу сделать:

$contain = array(); 
… 
$contain['DirectorContact'] = array('fields' => array('id','full_name')); 
… 
$this->Hospital->find('all', array(
    … 
    'contain' => $contain, 
    … 
)); 

сгенерированный код SQL содержит

CONCAT(…) AS DirectorContact__full_name 

Однако, тот же не работает в HotelController. Там я также делаю:

$contain['DirectorContact'] = array('fields' => array('id','full_name')); 

И если я

debug($this->Hotel->DirectorContact->virtualFields); 

Я получаю

array(
    'full_name' => 'CONCAT(…)' 
) 

Но когда я запускаю действие я получаю сообщение об ошибке SQL произнося поле full_name неизвестно. И я вижу, что в запросе sql, который сгенерирован, отсутствует CONCAT(…) AS DirectorContact__full_name.

В обоих случаях контактная таблица ссылается более одного раза, по меньшей мере, существуют ассоциации с различными псевдонимами. Поэтому я не уверен, почему CakePHP генерирует правильный запрос в одном случае, но не в другом.

Конечно, фразы поиска более сложны, больше содержит, объединяет и поля, чем я указал здесь.

Вопрос 1: Кто-нибудь знает, что может заставить CakePHP отказаться от генерации кода для виртуального поля связанной модели?

Я читал, что сдерживаемое поведение немного деликатно и что в некоторых ситуациях лучше использовать объединения.

Так что в том случае, когда виртуальное поле не работало, я использовал объединения вместо того, чтобы содержать.Тем не менее, виртуальное поле не генерируется, так что я сделал это явно для обоих assiciations:

$fields[] = 'DirectorContact.id'; 
$fields[] = 'CONCAT(…) AS `DirectorContact__name_or_company`'; 
$fields[] = 'ConciergeContact.id'; 
$fields[] = 'CONCAT(…) AS `ConciergeContact__name_or_company`'; 

Если я отлаживать результат запроса:

array(
    'Hotel' => array(
     'id' => '123', 
    ), 
    'DirectorContact' => array(
     'id' => '456', 
     'name_or_company' => 'Some name' 
    ), 
    (int) 0 => array(
     'ConciergeContact__name_or_company' => 'Some other name', 
    ), 
    'ConciergeContact' => array(
     'id' => '789' 
    ), 
) 

Таким образом, для первой ассоциации с Automagic работы и CakePHP напишите содержимое виртуального поля DirectorContact__name_or_company в часть ассоциативного массива DirectorContact, но другой get помещается в «общую» часть для вычисленных полей, на которые указывает ключ 0.

Но что еще больше в teresting: если я поменять порядок ссылок модели в определении поля для

$fields[] = 'ConciergeContact.id'; 
$fields[] = 'CONCAT(…) AS `ConciergeContact__name_or_company`'; 
$fields[] = 'DirectorContact.id'; 
$fields[] = 'CONCAT(…) AS `DirectorContact__name_or_company`'; 

результат

array(
    'Hotel' => array(
     'id' => '123', 
    ), 
    'ConciergeContact' => array(
     'id' => '789' 
    ), 
    (int) 0 => array(
     'ConciergeContact__name_or_company' => 'Some other name', 
     'DirectorContact__name_or_company' => 'Some name', 
    ), 
    'DirectorContact' => array(
     'id' => '456', 
    ), 
) 

Так что теперь Automagic больше не работает на всех, и как виртуальные поля wqritten в общая часть.

Вопрос 2: Кто-нибудь знает причину этого и как заставить автомат CakePHP работать во всех случаях?

(с использованием версии 2.4.3)

ответ

1

После копания в коде CakePHP, я нашел причину.

Если вы определяете опцию полей для запроса, то virtualFields не будут созданы (даже если вы добавите их в опцию полей).

В блоке DboSource.php есть функция read(Model $model, $queryData = array(), $recursive = null).

Фрагмент кода этой функции:

if (!empty($queryData['fields'])) { 
    $bypass = true; 
    … 
} else { 
    … 
} 
$_associations = $model->associations(); 
… 
foreach ($_associations as $type) { 
    foreach ($model->{$type} as $assoc => $assocData) { 
     … 
     if ($model->useDbConfig === $linkModel->useDbConfig) { 
      if ($bypass) { 
       $assocData['fields'] = false; 
      } 
      if ($this->generateAssociationQuery($model, $linkModel, $type, $assoc, $assocData, $queryData, $external, $null) === true) { 
       … 
      } 
     } 
    } 
} 

SO, когда параметр поля определяется тогда переменная $bypass устанавливается истина. Далее вниз, где построен код запроса для всех связанных моделей, когда $bypass истинно, определения полей связанных моделей установлены в false. Это, видимо, также удаляет виртуальные поля.

И тогда, когда вы включите это поле в поле поля запроса, оно не будет найдено.

Скорее логично ...