【发布时间】:2020-04-06 16:27:12
【问题描述】:
问题
我有一个与如何最好地在表上实施业务规则有关的问题,该表应该适用于在彼此了解的情况下创建的实体。从我目前的研究来看,我怀疑这与 CakePHP 的内部工作原理背道而驰,而且我可能错过了框架的另一个特性,它允许这样做。
相关实体具有hasMany 关联,通过该关联保存数据。例如,UsersTable 和 Questionnaires 通过 UsersQuestionnairesTable 关联。因此,我注意到UsersQuestionnairesTable 的buildRules 方法运行n 次,其中n 是正在创建的关联实体的数量。
目标
我的目标是应用一个构建规则,确保请求数据中的一个(并且只有一个)UsersQuestionnaire 行被标记为default: true,如果用户不存在其他UsersQuestionnairesTable 记录。
目前的结果实际上是,通过在UsersQuestionnairesTable::buildRules 中应用这个,在尝试通过UsersQuestionnairesTable 创建一个带有一些Questionnaires 的User 时,它只会通过验证,如果第一个数据行的它编组到实体中的有效负载具有default: true。因此,它不适用于创建多个实体,因为第二行将失败为default: false,因此不会创建User。
我理解/尝试过的
据我了解,Table 类的buildRules 方法是执行应用于实体的应用程序逻辑规则的有用地方。例如,电子邮件在数据库中是唯一的。
来自CakePHP 3.x Cookbook > Validating Data > Applying Application Rules
在验证确保数据的形式或语法正确的情况下,规则侧重于将数据与应用程序和/或网络的现有状态进行比较。
这些类型的规则通常被称为“域规则”或“应用程序规则”。 CakePHP 通过在实体持久化之前应用的“RulesCheckers”公开了这个概念。一些示例域规则是:
- 确保电子邮件的唯一性
- 状态转换或工作流程步骤(例如,更新发票的状态)。
- 防止修改软删除项。
- 实施使用/速率限制上限。
我想在创建过程中对实体应用类似的规则,但了解请求数据中的其他实体,以便我可以访问所有正在创建的 UsersQuestionnairesTable 实体以检查它们的 deafult 值,如果没有发现是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中的数据,但我理解这种方法更适合 在持久性之前进行数据操作,因此可能不合适 满足我的需要。 - 在许多可能负责创建
UsersQuestionnaires记录的控制器中具有此功能,无论是直接还是通过关联都感觉不那么 DRY 和 SRP,因为它需要Users::create(例如)知道并采取行动UsersQuestionnaires有效负载数据中的一行是否包含default: true,无论它是否由某种可重用的助手包装。
问题
我在应用buildRules 时是否遗漏了一些东西,这将允许检查将或已经作为此请求的一部分编组的所有实体,这样验证只会在创建所有实体后失败或通过?
也许是一种用更多请求上下文覆盖/重载buildRules 的方法?还是这种业务逻辑更适合在其他位置使用或使用框架的不同功能?
【问题讨论】:
标签: cakephp cakephp-3.0