当关联更改时,CakePHP 3.8 belongsTo 不会保留对新关联的更改

CakePHP 3.8 belongsTo does not persist changes to new association when association is changed

我目前正在使用 CakePHP 为我编写的一些票务逻辑提供基于 api 的 crud。我 运行 遇到了一个问题,我试图更改新关联中的 belongsTo 关联和数据,但它没有持续存在。

执行持久化的控制器如下所示:

<?php

class TasksController extends Cake\Controller\Controller
{
    public function initialize()
    {
        parent::initialize();
    }

    public function edit(array $ids): void
    {
        $validationErrors = [];

        $tasks = $this->Tasks->find('all')
            ->contain($this->setAssociations($query))
            ->where([$this->Model->getAlias().'.id IN' => $ids]);

        foreach ($tasks as $id => $task) {
            $this->Tasks->patchEntity($task, $this->request->getQuery()[$id], [
                'associated' => ['Asset']
            ]);
        }

        if ($this->Tasks->saveMany($tasks)) {
            $this->response = $this->response->withStatus(200);
        } else {
            // Handle errors
        }

        // Render json output for success / errors
        $this->set($this->createViewVars(['entities' => $tasks], $validationErrors));
    }
}

任务中资产的关联 table 如下所示:

<?php

class TasksTable extends Cake\ORM\Table
{
    public function initialize(array $config)
    {
        $this->belongsTo('Asset', [
            'className' => 'Assets',
            'foreignKey' => 'asset_id',
            'joinType' => 'LEFT'
        ]);
    }
}

这些构建规则附加到资产 table:

<?php
    
class AssetsTable extends Cake\ORM\Table
{
    public function buildRules(RulesChecker $rules)
    {
        $rules->add($rules->isUnique(['number', 'group_id'], 'The Number you selected is in use'));
        $rules->add($rules->isUnique(['name', 'group_id'], 'The Name you selected is in use'));
    }
}

我发送的请求正文如下所示:

{
    "421933": {
        "description": "This task was edited by the api!",
        "asset": {
            "id": "138499",
            "description": "This asset was edited by they api!",
            "name": "105",
            "number": "6"
        }
    }
}

基本上,名称 105 和编号 6 被标记为不唯一,因为它们已经设置为资产 138499 上的那些值。查询是尝试将名称 105 和编号 6 编辑到资产实体中目前与 Task 实体 (645163) 相关联,这会触发 isUnquie 构建规则失败。

您可以通过在上面的控制器中调用 saveMany 之前打印 $tasks 来看到这一点:

Array
(
    [0] => App\Model\Entity\Task Object
        (
            [id] => 421933
            [description] => This task was edited by the api!
            .....
            [asset] => App\Model\Entity\Asset Object
                (
                    [id] => 645163
                    [name] => 105
                    [description] => This asset was edited by they api!
                    [number] => 6
                    ....
                )
         
        )

)

似乎将资产 138499 编辑为任务 421933 的关联应该可行,因为它似乎可以在 CakePHP 文档中以这种方式保存 belongsTo 关联,如记录here:

<?php

$data = [
    'title' => 'First Post',
    'user' => [
        'id' => 1,
        'username' => 'mark'
    ]
];

$articles = TableRegistry::getTableLocator()->get('Articles');
$article = $articles->newEntity($data, [
    'associated' => ['Users']
]);

$articles->save($article);

是否可以关联 belongsTo 关联并在同一事务中对其进行编辑?如果是这样,我的请求或代码的结构应该如何不同?

谢谢!

正如评论中所暗示的那样,您 运行 受到编组器的限制,目前还没有过于简单明了的解决方法(您可能想提出一个问题 over at GitHub,也许有人想要承担为此类 marshalling/saving) 添加支持的任务。

书中的例子并不是最好的例子,事实上我个人 remove/change 它只有在允许批量分配主键时才有效(默认情况下对于烘焙实体它不是),并且它也只在创建新记录时起作用,即当要保存的实体被标记为“新”时。然而,这样做会引入各种怪癖,比如验证规则会将数据视为“创建”(新),应用程序规则会将实体视为“更新”(不是新的),但不会收到任何 existing/original 数据,与其他保存阶段回调相同,这会弄乱诸如审计之类的东西,基本上任何你需要新数据 原始数据的东西。

长话短说,即使您可以像那个例子一样工作,您也只会在以后引入其他问题,所以最好暂时忘掉它。我现在想到的唯一解决方法是比较给定的资产主键,手动加载现有资产实体,并在修补数据之前替换已经加载的实体,大致如下:

foreach ($tasks as $task) {
    $data = $this->request->getData($task->id);
    $assetId = (int)\Cake\Utility\Hash::get($data, 'asset.id');
    if ($task->asset->id !== $assetId) {
        $task->asset = $this->Tasks->Asset->get($assetId);
    }

    $this->Tasks->patchEntity($task, $data, [
        'associated' => ['Asset']
    ]);
}

请注意,我已将您的 getQuery() 用法更改为 getData(),因为您似乎不太可能通过查询字符串传递该数据.