[英]CakePHP 2.5.7 - Authentication failure on login with non-standard user
[英]CakePHP ORM : Query with a join on the same table with a non-standard association
我有一個非常特殊的用例,我找不到 ORM 的干凈解決方案。 我搜索了很多,也許我的數據庫 model 不正確,我不確定。
我使用 CakePHP 3.8.11。
所以,我有一個表“MaintenanceTypes”,其中包含 3 個重要字段:id、名稱和周期性。 周期性(以天為單位)表示“此維護將每(例如)30 天進行一次”。
周期性如 7(周)、30(月)、90(三個月)等。
我還有一個“Operations”表,它們是屬於“MaintenanceType”的小單元測試(字段是 id、name、maintenance_type_id)。
在這種情況下,特殊之處在於,作為業務規則,屬於具有 7 天周期的維護類型的操作被“包含”在具有更大周期的每個維護類型中; 這意味着每個三個月,您都應該執行與三個月直接相關的每個操作,還應該執行與月、周等相關的每個操作。
在原始 SQL 中,這是微不足道的:slight_smile:
mt_ref是參考維護類型, mt_inc是包含的維護類型(具有較小的周期性),最后,每個操作都屬於找到的任何維護類型。
SELECT mt_ref.id, mt_ref.name, mt_ref.periodicity,
mt_inc.name, mt_inc.periodicity, o.name
FROM maintenance_types mt_ref
LEFT JOIN maintenance_types mt_inc
ON (mt_inc.periodicity <= mt_ref.periodicity)
LEFT JOIN operations o ON (o.maintenance_type_id = mt_inc.id)
WHERE mt_ref.id = 3
我試圖聲明MaintenanceTypes之間的關聯,但我找不到一種方法來聲明關聯是在周期性字段上完成的,而且,額外的點,不是在相等上而是在“小於或等於”上。
To add extra difficulties, I use this query for a (very good) JQuery Datatables CakePHP plugin ( https://github.com/allanmcarvalho/cakephp-datatables ), so I can't simply pass the raw SQL, and I must use ORM...
我希望這很清楚,並且有人可以幫助我解決這個問題!
非常感謝 !
如果您需要查詢構建器實例,那么這里幾乎有兩個或多或少簡單的選項,即使用具有自定義條件的關聯或手動連接。
有了關聯,您可能會使用禁用的外鍵和自定義條件與MaintenanceTypes
進行自我關聯,就像在MaintenanceTypesTable
class 中一樣:
$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
關聯,但這有點謊言,因為您在這里沒有 1:1 的關系(至少據我所知)。
另請注意,您不必對條件的所有表達式使用回調,您可以將條件作為key => value
數組與手動實例化的標識符表達式或什至作為簡單字符串傳遞(但后者不會使用自動標識符引用時被識別):
->setConditions([
'MaintenanceTypesInc.periodicity <=' =>
new \Cake\Database\Expression\IdentifierExpression('MaintenanceTypes.periodicity');
]);
->setConditions('MaintenanceTypesInc.periodicity <= MaintenanceTypes.periodicity');
假設您在MaintenanceTypesTable
class 中也有Operations
關聯,您應該能夠通過查詢構建器*JoinWith()
方法加入新關聯和Operations
關聯,如下所示:
$query = $maintenanceTypesTable
->find()
->select([
'MaintenanceTypes.id', 'MaintenanceTypes.name', 'MaintenanceTypes.periodicity',
'MaintenanceTypesInc.name', 'MaintenanceTypesInc.periodicity',
'Operations.name',
])
->leftJoinWith('MaintenanceTypesInc.Operations');
在結果中,關聯數據將放在_matchingData
鍵下,即您可以像$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',
])
如果您不想每次都 select 所有字段,請使用自定義查找器,如下面的手動連接示例中所示。
使用手動連接為您提供了完全的自由,使用查詢構建器*Join()
方法,您可以創建您喜歡的任何連接,並且您不必使用關聯的可能解決方法。
您可以將它們添加到自定義查找器中以獲得適當的可重用性,它在您的MaintenanceTypesTable
class 中可能如下所示:
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');
請注意,就像在關聯示例中一樣,您也可以將字符串或數組條件用於自定義連接。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.