CakePHP 3 补丁实体创建新的关联实体

CakePHP 3 patch entity creates new associated entities

我正在尝试使用 patchEntity() 函数更新 ClientContactName 实体,该函数具有 ClientContactAddresses 关联。 ClientContactName 实体如我所料更新。但是,即使 ClientContactAddress 是一个现有实体,patchEntity() 函数也会创建一个 new ClientContactAddress 实体,并在保存时将其添加到 table。

如果我在视图中包含隐藏的 id 字段并将 id 添加为关联数组中的 accessibleField,它确实会更新现有的 ClientContactAddress,但我很难想象这是处理事情的正确方法。

我的问题是:如何编写修补函数代码以便更新现有关联而不是创建新关联?

关系是 ClientContactName hasMany ClientContactAddresses。下面是我的代码,没有隐藏 id 字段和 accessibleField 调整。

我在控制器中的 edit() 函数如下所示:

public function edit($id = null) 
{
    $clientContactName = $this->ClientContactNames->get($id, [
        'contain' => [
            'Clients',
            'ClientContactAddresses'
        ]
    ]);
    if ($this->getRequest()->is(['patch', 'post', 'put'])) {
        $data = $this->getRequest()->getData();
        $clientContactName = $this->ClientContactNames->patchEntity(
            $clientContactName,
            $data, [
                'associated' => ['ClientContactAddresses']
            ]
        );
        if ($this->ClientContactNames->save($clientContactName)) {
            $this->Flash->success(__('The client contact has been saved.'));
            return $this->redirect(['controller' => 'Clients', 'action' => 'view', $clientContactName->client->id]);
        }
        $this->Flash->error(__('The client contact could not be saved. Please, try again.'));
    }
    $this->set(compact('clientContactName'));
}

视图如下所示:

<div class="container-fluid clearfix col-lg-10">
    <?= $this->Form->create($clientContactName) ?>
    <fieldset>
        <!--bits that matter-->
        <div class="row stack-row">
            <div class="col-6">
                <?= $this->Form->control('first_name') ?>
            </div>
            <div class="col-6">
                <?= $this->Form->control('last_name') ?>
            </div>
        </div>
        <?= $this->element('address_form', ['showTopper' => true, 'entity' => 'client_contact_addresses.0']) ?>
    </fieldset>
    <?= $this->Form->button(__('Submit'), ['class' => 'btn btn-primary']) ?>
    <?= $this->Form->end() ?>
</div>

这是元素:

<?php
$prefix = ((empty($entity)) ? '' : $entity . '.');
if (!empty($showTopper)):
?>
<div class="row stack-row">
    <div class="col">
        <legend class="sub-topper"><?= __('Address') ?></legend>
    </div>
</div>
<?php endif; ?>
<div class="row stack-row">
    <div class="col-lg-6">
        <?php
        echo $this->Form->control($prefix . 'address_1');
        echo $this->Form->control($prefix . 'address_2');
        echo $this->Form->control($prefix . 'address_3');
        ?>
    </div>
</div>
<!--etc.-->

在修补之前,实体的相关部分如我所料,即 [new] 设置为 false

object(App\Model\Entity\ClientContactName) {
    'id' => (int) 1,
    'first_name' => 'xxxx',
    'last_name' => 'xxxx',
    'client_id' => (int) 19,
    'client_contact_addresses' => [
        (int) 0 => object(App\Model\Entity\ClientContactAddress) {
            'id' => (int) 12,
            'address_1' => 'xxxx',
            'address_2' => 'xxxx',
            'address_3' => 'xxxx',
            etc...
            'client_contact_name_id' => (int) 1,
            '[new]' => false,
            '[accessible]' => [
                'address_1' => true,
                'address_2' => true,
                'address_3' => true,
                etc.
                'client' => true
             ],
            '[dirty]' => [],
            '[original]' => [],
            '[virtual]' => [],
            '[hasErrors]' => false,
            '[errors]' => [],
            '[invalid]' => [],
            '[repository]' => 'ClientContactAddresses'
     }],
     //..//

请求数据显示地址字段值。虽然因为我没有隐藏的 id 字段,所以不会出现 id 值:

'first_name' => 'xxxx',
'last_name' => 'xxxx',
'client_contact_addresses' => [
    (int) 0 => [
        'address_1' => 'xxxx',
        'address_2' => 'xxxx',
        'address_3' => 'xxxx',
        etc.
    ]
],

并且在打补丁之后,创建了新实体,即[new]设置为true:

object(App\Model\Entity\ClientContactName) {

    'id' => (int) 1,
    'first_name' => 'xxxx',
    'last_name' => 'xxxx',
    'client_id' => (int) 19,
    'client_contact_addresses' => [
        (int) 0 => object(App\Model\Entity\ClientContactAddress) {
            'address_1' => 'xxxx',
            'address_2' => 'xxxx',
            'address_3' => 'xxxx',
            etc.
            '[new]' => true,
            '[accessible]' => [
            'address_1' => true,
            'address_2' => true,
            'address_3' => true,
            etc.
            'id' => true
            ],
            '[dirty]' => [
                'address_1' => true,
                'address_2' => true,
                'address_3' => true,
                etc.
            ],
            '[original]' => [],
            '[virtual]' => [],
            '[hasErrors]' => false,
            '[errors]' => [],
            '[invalid]' => [],
            '[repository]' => 'ClientContactAddresses'

        }],
     //..//

您不需要使 id 字段可访问,事实上您真的不应该这样做,因为它可能存在安全风险。

您需要做的就是在数据中传递记录的ID。编组器需要该值以便能够找出要用其余数据修补的现有实体。

使用隐藏字段传递 ID 绝对没问题。表单助手在为主键列生成控件时会自动选择一个隐藏字段。

另见