我有2个模型所有者和用户关联为User BelongsTo Owner。
我只有一个表单来收集两个模型/表的数据。
表单布局在我的add.ctp中声明:
<div class="container-fluid">
<div class="row">
<div class="col-md-9">
<h1><?= __("Création d'un nouveau propriétaire") ?></h1>
<p> </p>
<div class="col-md-19 col-md-offset-2 container-fluid well">
<?= $this->Form->create($owner, array('novalidate' => true)) ?>
<fieldset>
<div class="form-group">
<?= $this->Form->input('username', array('label' => __("Nom d'utilisateur :"), 'class' => 'form-control', 'placeholder' => __("Nom d'utilisateur"), 'autocomplete' => 'off')); ?>
</div>
<div class="form-group">
<?= $this->Form->input('password', array('label' => __("Mot de passe :"), 'class' => 'form-control', 'placeholder' => __("Mot de passe"))); ?>
</div>
// I cut some fields but username and password belong to User, postcode and city belong to Owner
<div class="form-group">
<?= $this->Form->input('postcode', array('label' => __("Code postal :"), 'class' => 'form-control', 'placeholder' => __("Code postal"))); ?>
</div>
<div class="form-group">
<?= $this->Form->input('city', array('label' => __("Ville :"), 'class' => 'form-control', 'placeholder' => __("ville"))); ?>
</div>
</fieldset>
<?= $this->Form->button(__('Enregistrer')) ?>
<?= $this->Form->end() ?>
</div>
</div>
</div>
</div>
此表单由OwnersController.php
控制public function add() {
$this->loadModel('Users');
$user = $this->Users->newEntity($this->request->data);
$owner = $this->Owners->newEntity($this->request->data);
$addDatas = [
'owner_id' => 'id',
'email' => $owner['email'],
'role' => 'owner',
'token' => md5(time() . '-' . uniqid()),
];
$user = $this->Users->patchEntity($user, $addDatas);
$owner->users = [$user];
if ($this->request->is('post')) {
if ($this->Owners->validate($owner)) {
if ($this->Owners->save($owner)) {
$user = $this->Users->get($owner->users[0]['id']);
$email = new Email('gmail');
$email->template('activationLink')
->emailFormat('text')
->to($owner['email'])
->from('myemail@monsite.com')
->subject(__('Votre inscription sur monsite.com'))
->viewVars(['user' => $user])
->send();
$this->Flash->success(__("Merci de vous être enregistré. un email a été envoyé à {0} pour activer votre compte", $owner['email']));
return $this->redirect(['action' => 'index']);
}
$this->Flash->error(__("Impossible de vous enregistrer, veuillez corriger les erreurs"));
} else {
$this->Flash->error(__("Impossible de vous enregistrer, veuillez corriger les erreurs"));
}
}
$this->set(compact('owner'));
}
一切正常,我可以输入我的数据,通过神话般的ORM神奇地验证和保存所有者和用户的数据。
但是我的验证器错误消息有问题。
无论错误来自所有者的验证者还是用户的验证者,我都会看到我的Flash消息告诉表单中有问题,但我只看到字段&#39;所有者数据的错误消息,而不是用户的错误消息。
如果我在提交空白表格后调试所有者,我可以看到:
object(App\Model\Entity\Owner) {
'new' => true,
'accessible' => [
'email' => true,
'phone' => true,
'company' => true,
'tva_number' => true,
'address' => true,
'postcode' => true,
'city' => true,
'users' => true
],
'properties' => [
'company' => '',
'email' => '',
'phone' => '',
'address' => '',
'postcode' => '',
'city' => '',
'users' => [
(int) 0 => object(App\Model\Entity\User) {
'new' => true,
'accessible' => [
'username' => true,
'password' => true,
'first_name' => true,
'last_name' => true,
'email' => true,
'role' => true,
'owner' => true,
'sites_user' => true,
'active' => true,
'token' => true
],
'properties' => [
'username' => '',
'password' => '$2y$10$EtGitvmw7CeIOJOeA4eNKuZBifd97f165O9I5gidpiC7p1NYRGsE.',
'first_name' => '',
'last_name' => '',
'email' => '',
'role' => 'owner',
'token' => '4f842f347e06aff9a3778199c9a8d20a'
],
'dirty' => [
'username' => true,
'password' => true,
'first_name' => true,
'last_name' => true,
'email' => true,
'role' => true,
'token' => true
],
'original' => [],
'virtual' => [],
'errors' => [
'username' => [
(int) 0 => 'Vous devez indiquer un nom d'utilisateur'
],
'first_name' => [
(int) 0 => 'Vous devez indiquer votre prénom'
],
'last_name' => [
(int) 0 => 'Vous devez indiquer votre nom'
],
'email' => [
(int) 0 => 'This field cannot be left empty'
]
],
'repository' => 'Users'
}
]
],
'dirty' => [
'company' => true,
'email' => true,
'phone' => true,
'address' => true,
'postcode' => true,
'city' => true,
'users' => true
],
'original' => [],
'virtual' => [],
'errors' => [
'email' => [
(int) 0 => 'Vous devez saisir votre email'
],
'phone' => [
(int) 0 => 'Vous devez saisir votre téléphone'
],
'address' => [
(int) 0 => 'Vous devez saisir votre adresse'
],
'postcode' => [
(int) 0 => 'Vous devez saisir votre code postal'
],
'city' => [
(int) 0 => 'vous devez saisir votre ville'
]
],
'repository' => 'Owners'
}
正如您所看到的,该对象包含有关所有者和关联用户的错误,但似乎cakePHP无法从用户那里得到错误,原因我无法猜测。
所以我想知道它是否应该有用,如果我在某个地方犯了一个错误,可以解释它无法检索用户的错误。
答案 0 :(得分:1)
如前所述,这里的主要问题是您的输入缺乏适当的关联。
输入获取输入的数据(这可能是您根据评论判断的混乱)的事实与实体上设置或未设置的内容无关!
这是由于实体上下文如何工作(上下文是表单帮助器和数据之间的层),在它尝试检查实体的数据之前,它将检查请求,这就是它拾取的地方例如username
字段,如果它会检查实体中的字段,那么它就不会找到它,因为它会在Owner
实体上查找它,因为缺少字段名称中的关联。
参见 https://github.com/cakephp/cakephp/blob/3.0.0-beta3/src/View/Form/EntityContext.php#L201-L204
因此,虽然您的输入可以获取数据,因为它存储在请求中,并且错误的&#34; fieldname,验证错误只能在实体上找到,这就是代码最终出错的地方,Owner
实体没有username
字段,但这是实体上下文要查找的地方错误。
参见 https://github.com/cakephp/cakephp/blob/3.0.0-beta3/src/View/Form/EntityContext.php#L468
它在那里找不到任何内容,因为错误位于第一个User
实体中,存储在Owner
实体users
属性(Owner->users[0]->errors
)中,为了能够获取这些错误,您的字段名称必须类似于
users.0.username
反映了实体中的结构。
参见 http://book.cakephp.org/3.0/en/views/helpers/form.html#field-naming-conventions
在您的控制器中,您正在创建一个User
实体以及一个Owner
实体,由于您的模型已关联,newEntity()
调用该实体,因此这不是必需的。 Owners
表将创建所需的所有内容,Owner
实体及其数据及其相关的所有数据,即User
实体。
参见 http://book.cakephp.org/3.0/en/orm/table-objects.html#converting-request-data-into-entities
如果您需要为User
实体设置其他数据,只需修补已创建并放置在Owner
实体users
属性中的实体,如下所示:
public function add() {
$this->loadModel('Users');
// Creates an entity with all necessary data
$owner = $this->Owners->newEntity($this->request->data);
if ($this->request->is('post')) {
if(isset($owner->users[0])) {
// Patch the existing (new) entity with some
// additional data
$this->Users->patchEntity($owner->users[0], [
'email' => $owner->email,
'role' => 'owner',
'token' => md5(time() . '-' . uniqid()),
]);
} else {
// Bail out here or check for the existence of
// a user using validation.
//
// You should have some kind of validation somewhere
// in order to make sure that a user (only
// one (1)) was submitted, and the controller
// mostly isn't really the right place for such logic
}
if ($this->Owners->save($owner)) {
$this->Flash->success(__("Merci de vous être enregistré. un email a été envoyé à {0} pour activer votre compte", $owner['email']));
return $this->redirect(['action' => 'index']);
} else {
$this->Flash->error(__("Impossible de vous enregistrer, veuillez corriger les erreurs"));
}
}
$this->set(compact('owner'));
}
请注意,我已从示例中删除了validate()
和get()
来电,明确调用验证并不是必需的,根据您的评论,您可能不需要它,如果您愿意,现在就可以,如果,那么您将禁用save()
电话触发的验证,因为验证两次不应该是{&1}}。是必要的。
参见 http://book.cakephp.org/3.0/en/orm/table-objects.html#validating-entities
该示例应该可以正常运行,但请确保您已阅读有关how to avoid mass assigment attacks的部分!
答案 1 :(得分:0)
您可以使用set方法轻松将错误踢到视图
if ($Models->errors()) {
$errors=$Models->errors();
$this->set(compact('errors'));
}