更新 belongsToMany 关联数据
Updating belongsToMany association data
我正在设置一个更新 person
和关联 person_to_role
table 的表单,person_to_role
是一个中间 table 链接 person
到 role
在 n..n 关系中。 role
有一个预定义的角色列表,不应从一个人的范围内修改。
我只需要更新 person_to_role
table 和 add/remove 记录中的 role_id
和 description
.
SQL
--person
+-------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-------------+------+-----+---------+----------------+
| ID | int(11) | NO | PRI | NULL | auto_increment |
| NICK_NAME | varchar(16) | YES | | NULL | |
| FIRST_NAME | varchar(24) | NO | | NULL | |
| MIDDLE_NAME | varchar(8) | YES | | NULL | |
| LAST_NAME | varchar(24) | NO | | NULL | |
| BIRTH_DATE | date | NO | | NULL | |
| GENDER | varchar(8) | NO | | NULL | |
+-------------+-------------+------+-----+---------+----------------+
-- role
+-------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+----------------+
| ID | int(11) | NO | PRI | NULL | auto_increment |
| NAME | varchar(24) | NO | | NULL | |
| DESCRIPTION | varchar(100) | YES | | NULL | |
+-------------+--------------+------+-----+---------+----------------+
--person_to_role
+-------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+----------------+
| ID | int(11) | NO | PRI | NULL | auto_increment |
| PERSON_ID | int(11) | NO | MUL | NULL | |
| ROLE_ID | int(11) | NO | MUL | NULL | |
| DESCRIPTION | varchar(100) | YES | | NULL | |
+-------------+--------------+------+-----+---------+----------------+
PersonTable 模型
public 函数初始化(数组 $config)
{
parent::initialize($config);
$this->setTable('person');
$this->setDisplayField('ID');
$this->setPrimaryKey('ID');
// define relations
$this->belongsToMany('Role', [
'joinTable'=> 'person_to_role',
'foreignKey' => 'PERSON_ID'
]);
}
个人控制器 -> edit()
public function edit($id = null)
{
$person = $this->Person->get($id, [
'contain' => ['role']
]);
$this->set('roles', $this->Person->Role->find('list'));
if ($this->request->is(['patch', 'post', 'put'])) {
$person = $this->Person->patchEntity($person, $this->request->getData());
if ($this->Person->save($person)) {
$this->Flash->success(__('The person has been saved.'));
return $this->redirect(['action' => 'index']);
}
$errors = print_r($person->errors(),1);
$this->Flash->error(__('The person could not be saved. Please, try again.<br><pre>'. $errors .'</pre>'),['escape'=> false]);
}
$this->set(compact('person'));
$this->set('_serialize', ['person']);
}
edit.ctp 表单域
echo $this->Form->control('NICK_NAME');
echo $this->Form->control('FIRST_NAME');
echo $this->Form->control('MIDDLE_NAME');
echo $this->Form->control('LAST_NAME');
echo $this->Form->control('BIRTH_DATE');
echo $this->Form->control('GENDER',['type'=>'select','options'=>[''=> '-
Please Select -', 'Male'=>'Male','Female'=>'Female']]);
Assigned roles
...
<?php foreach ($person->role as $k=>$role) { ?>
<tr><td><?php
echo $this->Form->input("role.$k._joinData.ID",['type'=>'hidden','value'=>$person->role[$k]['_joinData']['ID']]);
echo $this->Form->input("role.$k._joinData.ROLE_ID",['value'=>$role-
>ID,'options'=>$roles,'templates'=>['formGroup' =>'{{input}}']])
?></td><td>
<?php echo $this->Form->input("role.$k._joinData.DESCRIPTION", ['value'=>$person->role[$k]['_joinData']['DESCRIPTION'],'templates'=>
['formGroup' =>'{{input}}']]); ?></td></tr>
<?php } ?>
...
这给了我以下 POST 数据:
'NICK_NAME' => 'Johny',
'FIRST_NAME' => 'John',
'MIDDLE_NAME' => 'J.',
'LAST_NAME' => 'Smith',
'BIRTH_DATE' => '1961-01-01',
'GENDER' => 'Male',
'role' => [
(int) 0 => [
'_joinData' => [
'ID' => '1',
'ROLE_ID' => '5',
'DESCRIPTION' => 'person role description'
]
]
]
]
但是更新失败并出现以下错误:
这个人没救了。请再试一次。
Array
(
[role] => Array
(
[0] => Array
(
[NAME] => Array
(
[_required] => This field is required
)
[_joinData] => Array
(
[PERSON_ID] => Array
(
[_required] => This field is required
)
)
)
)
)
它要求提供 person_to_role.person_id
这是 foreignKey(它应该知道当前人的 ID),并且想要 role.name
的值。
我的关联设置错了吗?感谢任何帮助。
更新 2017-08-20
还是不行,尝试了文档和其他 Internet 资源中所有可能的变体。目前,我能够通过对 save
操作的验证,但是生成了 INSERT
查询而不是 UPDATE
并且在违反唯一约束时出错。
我可以访问 person.ID
和 person_to_role.ID
:
protected $_accessible = [
'*' => true,
'ID' => true
];
我的 POST 数据如下所示:
[
'NICK_NAME' => '',
'FIRST_NAME' => 'test',
'MIDDLE_NAME' => '',
'LAST_NAME' => 'user',
'BIRTH_DATE' => '1996-10-01',
'GENDER' => 'Male',
'role' => [
(int) 0 => [
'_joinData' => [
'ID' => '153',
'DESCRIPTION' => 'test edited text'
],
'ID' => '2'
]
]
]
我都试过了,在 _joinData
中使用和不使用 person_to_role
记录 ID,结果相同:
INSERT INTO person_to_role (PERSON_ID, ROLE_ID, DESCRIPTION)
VALUES (129, 2, 'test edited text')
在尝试不同的方法(包括使用 'through' association 时,我将以下几行添加到我的 PersonToRoleTable.php
模型中:
$this->belongsTo('Person');
$this->belongsTo('Role');
注释掉这些之后,一切都按预期工作,我能够保存更新以及添加新记录和删除连接中的现有记录table。
我正在设置一个更新 person
和关联 person_to_role
table 的表单,person_to_role
是一个中间 table 链接 person
到 role
在 n..n 关系中。 role
有一个预定义的角色列表,不应从一个人的范围内修改。
我只需要更新 person_to_role
table 和 add/remove 记录中的 role_id
和 description
.
SQL
--person
+-------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-------------+------+-----+---------+----------------+
| ID | int(11) | NO | PRI | NULL | auto_increment |
| NICK_NAME | varchar(16) | YES | | NULL | |
| FIRST_NAME | varchar(24) | NO | | NULL | |
| MIDDLE_NAME | varchar(8) | YES | | NULL | |
| LAST_NAME | varchar(24) | NO | | NULL | |
| BIRTH_DATE | date | NO | | NULL | |
| GENDER | varchar(8) | NO | | NULL | |
+-------------+-------------+------+-----+---------+----------------+
-- role
+-------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+----------------+
| ID | int(11) | NO | PRI | NULL | auto_increment |
| NAME | varchar(24) | NO | | NULL | |
| DESCRIPTION | varchar(100) | YES | | NULL | |
+-------------+--------------+------+-----+---------+----------------+
--person_to_role
+-------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+----------------+
| ID | int(11) | NO | PRI | NULL | auto_increment |
| PERSON_ID | int(11) | NO | MUL | NULL | |
| ROLE_ID | int(11) | NO | MUL | NULL | |
| DESCRIPTION | varchar(100) | YES | | NULL | |
+-------------+--------------+------+-----+---------+----------------+
PersonTable 模型
public 函数初始化(数组 $config) { parent::initialize($config);
$this->setTable('person');
$this->setDisplayField('ID');
$this->setPrimaryKey('ID');
// define relations
$this->belongsToMany('Role', [
'joinTable'=> 'person_to_role',
'foreignKey' => 'PERSON_ID'
]);
}
个人控制器 -> edit()
public function edit($id = null)
{
$person = $this->Person->get($id, [
'contain' => ['role']
]);
$this->set('roles', $this->Person->Role->find('list'));
if ($this->request->is(['patch', 'post', 'put'])) {
$person = $this->Person->patchEntity($person, $this->request->getData());
if ($this->Person->save($person)) {
$this->Flash->success(__('The person has been saved.'));
return $this->redirect(['action' => 'index']);
}
$errors = print_r($person->errors(),1);
$this->Flash->error(__('The person could not be saved. Please, try again.<br><pre>'. $errors .'</pre>'),['escape'=> false]);
}
$this->set(compact('person'));
$this->set('_serialize', ['person']);
}
edit.ctp 表单域
echo $this->Form->control('NICK_NAME');
echo $this->Form->control('FIRST_NAME');
echo $this->Form->control('MIDDLE_NAME');
echo $this->Form->control('LAST_NAME');
echo $this->Form->control('BIRTH_DATE');
echo $this->Form->control('GENDER',['type'=>'select','options'=>[''=> '-
Please Select -', 'Male'=>'Male','Female'=>'Female']]);
Assigned roles
...
<?php foreach ($person->role as $k=>$role) { ?>
<tr><td><?php
echo $this->Form->input("role.$k._joinData.ID",['type'=>'hidden','value'=>$person->role[$k]['_joinData']['ID']]);
echo $this->Form->input("role.$k._joinData.ROLE_ID",['value'=>$role-
>ID,'options'=>$roles,'templates'=>['formGroup' =>'{{input}}']])
?></td><td>
<?php echo $this->Form->input("role.$k._joinData.DESCRIPTION", ['value'=>$person->role[$k]['_joinData']['DESCRIPTION'],'templates'=>
['formGroup' =>'{{input}}']]); ?></td></tr>
<?php } ?>
...
这给了我以下 POST 数据:
'NICK_NAME' => 'Johny',
'FIRST_NAME' => 'John',
'MIDDLE_NAME' => 'J.',
'LAST_NAME' => 'Smith',
'BIRTH_DATE' => '1961-01-01',
'GENDER' => 'Male',
'role' => [
(int) 0 => [
'_joinData' => [
'ID' => '1',
'ROLE_ID' => '5',
'DESCRIPTION' => 'person role description'
]
]
]
]
但是更新失败并出现以下错误:
这个人没救了。请再试一次。
Array
(
[role] => Array
(
[0] => Array
(
[NAME] => Array
(
[_required] => This field is required
)
[_joinData] => Array
(
[PERSON_ID] => Array
(
[_required] => This field is required
)
)
)
)
)
它要求提供 person_to_role.person_id
这是 foreignKey(它应该知道当前人的 ID),并且想要 role.name
的值。
我的关联设置错了吗?感谢任何帮助。
更新 2017-08-20
还是不行,尝试了文档和其他 Internet 资源中所有可能的变体。目前,我能够通过对 save
操作的验证,但是生成了 INSERT
查询而不是 UPDATE
并且在违反唯一约束时出错。
我可以访问 person.ID
和 person_to_role.ID
:
protected $_accessible = [
'*' => true,
'ID' => true
];
我的 POST 数据如下所示:
[
'NICK_NAME' => '',
'FIRST_NAME' => 'test',
'MIDDLE_NAME' => '',
'LAST_NAME' => 'user',
'BIRTH_DATE' => '1996-10-01',
'GENDER' => 'Male',
'role' => [
(int) 0 => [
'_joinData' => [
'ID' => '153',
'DESCRIPTION' => 'test edited text'
],
'ID' => '2'
]
]
]
我都试过了,在 _joinData
中使用和不使用 person_to_role
记录 ID,结果相同:
INSERT INTO person_to_role (PERSON_ID, ROLE_ID, DESCRIPTION)
VALUES (129, 2, 'test edited text')
在尝试不同的方法(包括使用 'through' association 时,我将以下几行添加到我的 PersonToRoleTable.php
模型中:
$this->belongsTo('Person');
$this->belongsTo('Role');
注释掉这些之后,一切都按预期工作,我能够保存更新以及添加新记录和删除连接中的现有记录table。