CakePHP 3.x:将应用程序规则应用于多个实体 问题

CakePHP 3.x:将应用程序规则应用于多个实体 问题,cakephp,cakephp-3.0,Cakephp,Cakephp 3.0,我有一个关于如何最好地在一个表上实现业务规则的问题,该表应该应用于在相互了解的情况下创建的实体。从我到目前为止的研究来看,我怀疑这与CakePHP的内部工作方式相违背,并且我很可能错过了框架的另一个特性,允许这样做 所涉及的实体有一个关联,通过它可以保存数据。例如,UsersTable和调查问卷通过UsersQuestionnairesTable关联。因此,我注意到UsersQuestionnairesTable的buildRules方法运行n次,其中n是正在创建的关联实体的数量 目标 我的目标

我有一个关于如何最好地在一个表上实现业务规则的问题,该表应该应用于在相互了解的情况下创建的实体。从我到目前为止的研究来看,我怀疑这与CakePHP的内部工作方式相违背,并且我很可能错过了框架的另一个特性,允许这样做

所涉及的实体有一个
关联,通过它可以保存数据。例如,
UsersTable
调查问卷
通过
UsersQuestionnairesTable
关联。因此,我注意到
UsersQuestionnairesTable
buildRules
方法运行
n
次,其中
n
是正在创建的关联实体的数量

目标 我的目标是应用一个构建规则,确保请求数据中的
UsersQuestionnaire
行中的一行(并且只有一行)被标记为
default:true
如果用户不存在其他
UsersQuestionnairesTable
记录

目前的结果实际上是,通过在
UsersQuestionnairesTable::buildRules
中应用此方法,在尝试创建一个
用户
时,通过
UsersQuestionnairesTable
与一些
问卷
关联,只有当它封送到实体中的有效负载的第一个数据行具有
default:true
时,它才会通过验证。因此,它不适用于多实体创建,因为它将在第二行失败,因为
默认值:false
,因此不会创建
用户

我所理解/尝试的 据我所知,
Table
类的
buildRules
方法是实施应用于实体的应用程序逻辑规则的有用地方。例如,电子邮件在数据库中是唯一的

当验证确保数据的形式或语法正确时,规则侧重于将数据与应用程序和/或网络的现有状态进行比较

这些类型的规则通常称为“域规则”或“应用程序规则”。CakePHP通过在实体持久化之前应用的“RuleSchecker”公开了这个概念。一些域规则示例如下:

  • 确保电子邮件的唯一性
  • 状态转换或工作流步骤(例如,更新发票状态)
  • 防止修改软删除的项目
  • 强制执行使用率/费率上限
我希望在创建过程中对实体应用类似的规则,但了解请求数据中的其他实体,这样我就可以访问正在创建的所有
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()
    访问
    封送前
    中的数据,但我知道此方法更适合于
    在持久化之前进行数据操作,因此可能不合适
    为了我的需要
    
  • 在许多可能负责创建
    UsersQuestionnaires
    记录(无论是直接创建还是通过关联创建)的控制器中使用此功能感觉不那么枯燥 和SRP,因为它需要
    用户::create
    (例如)了解并基于 取决于
    UsersQuestionnaires
    有效负载数据中的行是否包含
    default:true
    ,而不管它是否由某种可重用的帮助器包装
问题 应用
buildRules
可以检查作为此请求一部分的所有实体,这样validaiton只有在创建了所有实体后才会失败或通过,我是否缺少什么


也许是一种用更多请求上下文覆盖/重载
构建规则的方法?或者这种业务逻辑更适合于另一个位置还是使用框架的不同功能?

您的规则函数可以采用第二个参数,该参数接收传递给
save
函数的选项。所以在你的控制器里

$this->UsersQuestionnaires->saveMany($entities, ['entities' => $entities]);
然后在你的桌子上:

$enforceFirstAsDefault = function ($entity, $options) {
    // Use $options['entities'] here to access the set of entities being saved
}

很好,谢谢你。不知道从
save
中筛选出的内容以及规则。你能链接到烹饪书/API文档中详细说明这一点的章节吗?如果这是我在旅行中错过的东西,我会向你道歉,但是谢谢你花时间来帮助我!是的,我没有看到规则、验证或保存部分中明确提到的连接。在文档存储库中提出可能是一个好问题?