Если вам нужны экземпляры построителя запросов, то здесь в значительной степени есть два варианта, которые являются более или менее простыми, то есть либо использовать связи с пользовательскими условиями, либо ручные объединения.
Пользовательские условия ассоциации
Со связями вы, вероятно, будете делать что-то вроде самоассоциирования с MaintenanceTypes
с отключенным внешним ключом и пользовательскими условиями, как в вашем MaintenanceTypesTable
классе:
$this
->hasMany('MaintenanceTypesInc')
->setClassName('MaintenanceTypes')
->setForeignKey(false)
->setConditions(function (
\Cake\Database\Expression\QueryExpression $exp,
\Cake\ORM\Query $query
) {
return $exp->lte(
$query->identifier('MaintenanceTypesInc.periodicity'),
$query->identifier('MaintenanceTypes.periodicity')
);
});
Отключение внешнего ключа не позволит ORM создать условие A.fk = B.fk
по умолчанию при присоединении к ассоциации. Следует отметить, что вы не можете содержать hasMany
связь с отключенным внешним ключом, вы можете только присоединиться к ней! Вместо этого вы могли бы использовать hasOne
или даже belongsTo
связь, но это было бы вроде ie, поскольку у вас нет здесь отношения 1: 1 (по крайней мере, насколько я понимаю).
Также обратите внимание, что вам необязательно использовать обратный вызов со всеми выражениями для условий, вы можете передать условия как массив key => value
с созданным вручную выражением идентификатора или даже в виде простой строки (последняя однако не будет распознаваться при использовании автоматического c цитирования идентификатора):
->setConditions([
'MaintenanceTypesInc.periodicity <=' =>
new \Cake\Database\Expression\IdentifierExpression('MaintenanceTypes.periodicity');
]);
->setConditions('MaintenanceTypesInc.periodicity <= MaintenanceTypes.periodicity');
Если у вас также есть ассоциация для Operations
в вашем классе MaintenanceTypesTable
, вы сможете присоединиться как в новой, так и в ассоциации Operations
с помощью методов построения запросов *JoinWith()
, например:
$query = $maintenanceTypesTable
->find()
->select([
'MaintenanceTypes.id', 'MaintenanceTypes.name', 'MaintenanceTypes.periodicity',
'MaintenanceTypesInc.name', 'MaintenanceTypesInc.periodicity',
'Operations.name',
])
->leftJoinWith('MaintenanceTypesInc.Operations');
В результате данные ассоциации будут помещены под ключ _matchingData
, ie вы можете получить его как $entity->_matchingData->MaintenanceTypesInc
и $entity->_matchingData->Operations
. Если вы не хотите этого, вам нужно использовать псевдонимы для полей ассоциаций, например:
->select([
'MaintenanceTypes.id', 'MaintenanceTypes.name', 'MaintenanceTypes.periodicity',
'mt_inc_name' => 'MaintenanceTypesInc.name', 'mt_inc_periodicity' => 'MaintenanceTypesInc.periodicity',
'op_name' => 'Operations.name',
])
Если вы не хотите выбирать все поля каждый раз, используйте пользовательский искатель как в приведенном ниже примере ручных объединений.
ручные объединения
Использование ручных объединений дает вам полную свободу, с помощью методов построения запросов *Join()
вы можете создавать любые объединения, которые вам нравятся, а вам нет необходимо использовать возможные обходные пути с ассоциациями.
Вы можете добавить их в пользовательском искателе для правильного повторного использования, это может выглядеть примерно так в вашем MaintenanceTypesTable
классе:
public function findWithIncludedMaintenanceTypes(\Cake\ORM\Query $query, array $options)
{
return $query
->select(/* ... */)
->leftJoin(
['MaintenanceTypesInc' => 'maintenance_types'],
function (
\Cake\Database\Expression\QueryExpression $exp,
\Cake\ORM\Query $query
) {
return $exp->lte(
$query->identifier('MaintenanceTypesInc.periodicity'),
$query->identifier('MaintenanceTypes.periodicity')
);
}
)
->leftJoin(
['Operations' => 'operations'],
function (
\Cake\Database\Expression\QueryExpression $exp,
\Cake\ORM\Query $query
) {
return $exp->equalFields(
'Operations.maintenance_type_id ',
'MaintenanceTypesInc.id'
);
}
);
}
Тогда вы просто используйте искатель везде, где вам это нужно, например:
$query = $maintenanceTypesTable
->find('withIncludedMaintenanceTypes');
Обратите внимание, что, как и в примере ассоциаций, вы можете использовать условия строки или массива для пользовательских объединений.
См. также