CakePHP 3.x:将应用程序规则应用于多个实体
CakePHP 3.x: Applying application rules to multiple entities
问题
我有一个关于如何最好地在 table 上实施业务规则的问题,这些规则应该适用于在相互了解的情况下创建的实体。根据我迄今为止的研究,我怀疑这违背了 CakePHP 的内部工作原理,并且我可能错过了允许这样做的框架的另一个功能。
相关实体有一个 hasMany
关联,通过该关联保存数据。例如,UsersTable
和 Questionnaires
通过 UsersQuestionnairesTable
关联。因此,我注意到 UsersQuestionnairesTable
的 buildRules
方法是 运行 n
次,其中 n
是正在创建的关联实体的数量。
目标
我的目标是应用一个构建规则,确保请求数据中 UsersQuestionnaire
行中的一个(并且只有一个)被标记为 default: true
应该没有其他 UsersQuestionnairesTable
用户存在记录。
目前的结果实际上是,通过在 UsersQuestionnairesTable::buildRules
中应用它,在尝试创建一个 User
并通过 UsersQuestionnairesTable
与之关联的一些 Questionnaires
时,它将仅当它编组到实体中的有效负载的第一个数据行具有 default: true
时才通过验证。因此,它不适用于创建多个实体,因为它会在第二行失败,如 default: false
,因此不会创建 User
.
我understand/have试过的
据我了解,Table
class 的 buildRules
方法是强制执行适用于实体的应用程序逻辑规则的有用位置。例如,电子邮件在数据库中是唯一的。
来自CakePHP 3.x Cookbook > Validating Data > Applying Application Rules
Where validation ensures the form or syntax of your data is correct, rules focus on comparing data against the existing state of your application and/or network.
These types of rules are often referred to as ‘domain rules’ or ‘application rules’. CakePHP exposes this concept through ‘RulesCheckers’ which are applied before entities are persisted. Some example domain rules are:
- Ensuring email uniqueness
- State transitions or workflow steps (e.g., updating an invoice’s status).
- Preventing the modification of soft deleted items.
- Enforcing usage/rate limit caps.
我想在创建期间对实体应用类似的规则,但了解请求数据中的其他实体,这样我就可以访问正在创建的所有 UsersQuestionnairesTable
个实体来检查它们的 deafult
值,如果发现 none 为 true
,则函数失败并且所有实体都不会被创建。
目前,在创建过程中但在保存之前(尽管不正确)应用于每个实体的此条件规则应该说明所需的最终目标。
用户问卷表:
public function buildRules(RulesChecker $rules)
{
$enforceFirstAsDefault = function ($entity) {
$count = $this->find('all')
->where(['UserQuestionnaires.user_id' => $entity->user_id])
->andWhere(['Questionnaires.type_id' => 1])
->contain(['Questionnaires'])->count();
if ($count == 0 && !$this->containsDefault($entity)) {
return false;
}
return true;
};
$rules->add($enforceFirstAsDefault, [
'errorField' => 'no_default_identified',
'message' => 'A default questionnaire is required')
]);
}
...
private function containsDefault($entities): bool
{
foreach ($entities as $entity) {
if ($entity->is_default) {
return true;
}
}
return false;
}
由于希望在创建之前失败,buildRules
在一个模型上感觉最合适的位置定位此逻辑仅适用于此模型,如:
- 行为更适合模型之间的共同行为
- 虽然你可以用
$event->getData()
访问beforeMarshal
中的数据,但我知道这种方法更适合
在持久化之前进行数据操作,因此很可能是 unsuitable
为了我的需要。
- 在许多可能负责创建
UsersQuestionnaires
记录的控制器中拥有此功能,无论是直接还是通过关联,感觉不那么枯燥
和 SRP,因为它需要 Users::create
(例如)了解并基于
根据 UsersQuestionnaires
有效负载数据中的一行是否包含 default: true
,无论它是否被某种可重用的助手包装。
问题
我在应用 buildRules
时是否遗漏了一些东西,这将允许检查将要或已经作为此请求的一部分编组的所有实体,这样验证只会失败或通过一次已创建所有实体?
也许是 override/overload 具有更多请求上下文的 buildRules
的方法?或者这种业务逻辑是否更适合在另一个位置或使用框架的不同功能?
您的规则函数可以采用第二个参数,该参数接收传递给 save
函数的选项。所以在你的控制器中,
$this->UsersQuestionnaires->saveMany($entities, ['entities' => $entities]);
然后在你的 table:
$enforceFirstAsDefault = function ($entity, $options) {
// Use $options['entities'] here to access the set of entities being saved
}
问题
我有一个关于如何最好地在 table 上实施业务规则的问题,这些规则应该适用于在相互了解的情况下创建的实体。根据我迄今为止的研究,我怀疑这违背了 CakePHP 的内部工作原理,并且我可能错过了允许这样做的框架的另一个功能。
相关实体有一个 hasMany
关联,通过该关联保存数据。例如,UsersTable
和 Questionnaires
通过 UsersQuestionnairesTable
关联。因此,我注意到 UsersQuestionnairesTable
的 buildRules
方法是 运行 n
次,其中 n
是正在创建的关联实体的数量。
目标
我的目标是应用一个构建规则,确保请求数据中 UsersQuestionnaire
行中的一个(并且只有一个)被标记为 default: true
应该没有其他 UsersQuestionnairesTable
用户存在记录。
目前的结果实际上是,通过在 UsersQuestionnairesTable::buildRules
中应用它,在尝试创建一个 User
并通过 UsersQuestionnairesTable
与之关联的一些 Questionnaires
时,它将仅当它编组到实体中的有效负载的第一个数据行具有 default: true
时才通过验证。因此,它不适用于创建多个实体,因为它会在第二行失败,如 default: false
,因此不会创建 User
.
我understand/have试过的
据我了解,Table
class 的 buildRules
方法是强制执行适用于实体的应用程序逻辑规则的有用位置。例如,电子邮件在数据库中是唯一的。
来自CakePHP 3.x Cookbook > Validating Data > Applying Application Rules
Where validation ensures the form or syntax of your data is correct, rules focus on comparing data against the existing state of your application and/or network.
These types of rules are often referred to as ‘domain rules’ or ‘application rules’. CakePHP exposes this concept through ‘RulesCheckers’ which are applied before entities are persisted. Some example domain rules are:
- Ensuring email uniqueness
- State transitions or workflow steps (e.g., updating an invoice’s status).
- Preventing the modification of soft deleted items.
- Enforcing usage/rate limit caps.
我想在创建期间对实体应用类似的规则,但了解请求数据中的其他实体,这样我就可以访问正在创建的所有 UsersQuestionnairesTable
个实体来检查它们的 deafult
值,如果发现 none 为 true
,则函数失败并且所有实体都不会被创建。
目前,在创建过程中但在保存之前(尽管不正确)应用于每个实体的此条件规则应该说明所需的最终目标。
用户问卷表:
public function buildRules(RulesChecker $rules)
{
$enforceFirstAsDefault = function ($entity) {
$count = $this->find('all')
->where(['UserQuestionnaires.user_id' => $entity->user_id])
->andWhere(['Questionnaires.type_id' => 1])
->contain(['Questionnaires'])->count();
if ($count == 0 && !$this->containsDefault($entity)) {
return false;
}
return true;
};
$rules->add($enforceFirstAsDefault, [
'errorField' => 'no_default_identified',
'message' => 'A default questionnaire is required')
]);
}
...
private function containsDefault($entities): bool
{
foreach ($entities as $entity) {
if ($entity->is_default) {
return true;
}
}
return false;
}
由于希望在创建之前失败,buildRules
在一个模型上感觉最合适的位置定位此逻辑仅适用于此模型,如:
- 行为更适合模型之间的共同行为
- 虽然你可以用
$event->getData()
访问beforeMarshal
中的数据,但我知道这种方法更适合 在持久化之前进行数据操作,因此很可能是 unsuitable 为了我的需要。 - 在许多可能负责创建
UsersQuestionnaires
记录的控制器中拥有此功能,无论是直接还是通过关联,感觉不那么枯燥 和 SRP,因为它需要Users::create
(例如)了解并基于 根据UsersQuestionnaires
有效负载数据中的一行是否包含default: true
,无论它是否被某种可重用的助手包装。
问题
我在应用 buildRules
时是否遗漏了一些东西,这将允许检查将要或已经作为此请求的一部分编组的所有实体,这样验证只会失败或通过一次已创建所有实体?
也许是 override/overload 具有更多请求上下文的 buildRules
的方法?或者这种业务逻辑是否更适合在另一个位置或使用框架的不同功能?
您的规则函数可以采用第二个参数,该参数接收传递给 save
函数的选项。所以在你的控制器中,
$this->UsersQuestionnaires->saveMany($entities, ['entities' => $entities]);
然后在你的 table:
$enforceFirstAsDefault = function ($entity, $options) {
// Use $options['entities'] here to access the set of entities being saved
}