php - CakePHP 4 - 如何验证需要将数据保存到多个表的表单
问题描述
抱歉,如果以前有人问过这个问题。我能找到的所有示例都是旧的或适用于 CakePHP 的旧版本,例如cakephp:使用一种形式保存到多个模型已有7 年的历史。
我在 CakePHP 4.1.6 中有一个应用程序。数据库中的两个表被调用tbl_users
和tbl_orgs
(在这种情况下,“orgs”表示“组织”)。
当我添加一个组织时,我还想创建一个作为组织内主要联系人的用户。这涉及在提交表单时同时保存到表tbl_orgs
和表中。tbl_users
我遇到的问题是如何让表单以在提交时运行验证规则的方式 工作tbl_users
。tbl_orgs
这就是我们的应用程序当前的结构:
中调用add()
了一个Controller方法src/Controller/TblOrgsController.php
。这由生成bake
并最初用于将新组织插入tbl_orgs
表中。在这一点上,它没有做任何事情,tbl_users
但它在保存新组织和运行适当的验证规则方面起作用。
一个验证规则是其中的每条companyname
记录都tbl_orgs
必须是唯一的。如果您尝试插入超过 1 个名称为“My Company Limited”的公司,则会出现验证错误“该公司名称已存在”:
// src/Model/Table/TblOrgsTable.php
public function buildRules(RulesChecker $rules): RulesChecker
{
$rules->add(
$rules->isUnique(['companyname']),
[
'errorField' => 'companyname',
'message' => 'This company name already exists',
]
);
return $rules;
}
虽然以上适用于我们,TblOrgs
但我们也有一个buildRules()
在字段TblUsers
上应用类似逻辑的email
方法,以确保每个用户的所有电子邮件地址都是唯一的。
在add()
Controller 方法中,我们首先为 指定一个新的空实体TblOrgs
:
// src/Controller/TblOrgsController.php
public function add()
{
$org = $this->TblOrgs->newEmptyEntity();
// ...
$this->set(compact('org'));
}
创建表单时,我们通过$org
:
// templates/TblOrgs/add.php
<?= $this->Form->create($org) ?>
<?= $this->Form->control('companyname') ?>
<?= $this->Form->end() ?>
当TblOrgs
浏览器渲染字段时,我们可以检查 HTML 并查看这些字段是否遵循相应的模型。这很清楚,因为诸如required="required"
和maxlength="100"
对应于字段不允许为空并且是VARCHAR(100)
数据库中的字段的事实:
<input type="text" name="companyname" required="required" id="companyname" maxlength="100">
它也适用于buildRules
for中指定的规则TblOrgs
。例如,如果我两次输入相同的公司名称,它会显示相应的在线错误:
然后我尝试为TblUsers
. 我在表单字段前加上点符号,例如,这旨在对应于tbl_users.email
输入字段:
<?= $this->Form->control('TblUser.email') ?>
检查 HTML 时,它不会做与 for 等效的操作TblOrgs
。例如像maxlength
或required
不存在的东西。它实际上不知道TblUsers
. 我知道$org
在我的 Controller 方法中为TblOrgs
and not指定了一个新实体TblUsers
。我查看了关于通过关联保存的 CakePHP 文档,其中说
该
save()
方法还能够为关联创建新记录
但是,在文档中给出的示例:
$firstComment = $articlesTable->Comments->newEmptyEntity();
// ...
$tag2 = $articlesTable->Tags->newEmptyEntity();
在这种情况下Tags
,是一个不同的模型,Comments
但newEmtpyEntity()
适用于两者。考虑到这一点,我将我的add()
方法调整为:
$org = $this->TblOrgs->TblUsers->newEmptyEntity();
但这现在为TblUsers
. 似乎你可以有一个或另一个,但不能同时拥有。
这对我的用例不起作用的原因是我可以为TblOrgs
(但不是TblUsers
)运行我的验证规则,反之亦然。
您如何设置它以运行两个模型的验证规则?一个表单可能需要将数据保存到多个表中,并且您希望每个表的验证规则都运行,这似乎不是一个不合理的要求。我从文档中得到的印象是它是可能的,但不清楚如何。
作为参考,这两个表之间存在适当的关系:
// src/Model/Table/TblOrgsTable.php
public function initialize(array $config): void
{
$this->hasMany('TblUsers', [
'foreignKey' => 'o_id',
'joinType' => 'INNER',
]);
}
和
// src/Model/Table/TblUsersTable.php
public function initialize(array $config): void
{
$this->belongsTo('TblOrgs', [
'foreignKey' => 'o_id',
'joinType' => 'INNER',
]);
}
解决方案
好的,这里有很多混乱需要清理。:-) 根据您所写的内容,我在这里的假设是您正在尝试使用单个表单来添加一个新组织以及其中的第一个用户,然后也许稍后您会添加更多用户组织。
首先,$this->TblOrgs->TblUsers
是你的用户表对象,所以当你使用
$org = $this->TblOrgs->TblUsers->newEmptyEntity();
您正在做的是创建一个新的用户实体。您通过 orgs 表获得该表对象并且您正在调用它的事实$org
并没有改变这一点。它不会以某种方式神奇地创建一个包含空白用户实体的空白组织实体。但是这里根本不需要那个实体结构,只需要空的 org 实体。回到简单的:
$org = $this->TblOrgs->newEmptyEntity();
现在,在你的表单中,你会想要这样的东西:
<?= $this->Form->create($org) ?>
<?= $this->Form->control('companyname') ?>
<?= $this->Form->control('tbl_users.0.email') ?>
<?= $this->Form->end() ?>
调用该字段是tbl_users.0.email
因为:
- 表名被转换为小写下划线格式。
- 这是一个从组织到用户的 hasMany 关系,所以它期待一组用户;我们必须为该数组提供一个数字索引,而 0 是一个很好的起点。如果您要同时添加第二个用户,则该字段将为
tbl_users.1.email
.
注意:确定表单助手希望您以何种格式创建字段名称的一个好方法是从数据库中读取现有记录集(在本例中为组织及其用户),然后将其转储数据,类似debug($org);
. 您会看到它$org
有一个名为 的属性tbl_users
,它是一个数组,它将直接指向我上面描述的这个结构。
使用这样设置的字段,您应该能够将结果数据直接修补到$org
控制器中的实体中,并保存它而无需任何其他工作。补丁将创建整个结构,实体为 class TblOrg
,tbl_users
属性为包含单个实体 class 的数组TblUser
,并且对它们都进行了验证。(至少应该;您可以使用debug($org);
上述方法来确认。)并且当您保存此实体时,它将首先保存TblOrg
实体,然后在保存之前将新ID添加到TblUser
实体中,以及检查规则两者,并确保如果不能全部保存,则不会将任何内容保存到数据库中。只需一个电话,这一切都会为您自动发生save
!
如果您的关联是 hasOne 或 belongsTo 关系(例如,如果您要添加新用户以及他们所在的组织,而不是相反),您可以转储一个 sample $user
,并查看它有一个属性称为tbl_org
它只是一个直接的实体,而不是一组实体,请注意tbl_org
现在是单数的,因为它只是一个实体而不是一堆。在这种情况下,要使用的字段名称是tbl_org.companyname
,其中根本没有数组索引。
推荐阅读
- google-api - 使用服务帐户使用 Google Drive API 创建文件不会在授权用户帐户的 GD 上呈现文件
- javascript - Material UI 自动完成,多个默认值
- lua - 尝试在 Lua/Love2D 中绘制平台时出错
- node.js - 执行 npm start 时出现 Azure 函数节点错误
- javascript - 从javascript中的异步函数获取返回值
- django - 除非打开 chrome 开发人员工具,否则 React/Redux 应用程序无法工作?
- javascript - InfiniteScroll - 如何重置所有网格?
- css - 是否可以在不同的屏幕中查看页面?
- quill - 如何使 Quill delta 输出变平?
- c++ - 分支定界根节点是否适合使用继承?