【问题标题】:CakePhp 3: switch between insert/update associated fields in a key-value tableCakePhp 3:在键值表中插入/更新关联字段之间切换
【发布时间】:2017-07-11 13:11:48
【问题描述】:

我无法修改用于保存关联表之一的逻辑。 这两个表是:

  • 客户
  • ClientMetadatas(使用键/值对存储客户端元数据)

在客户端控制器中,方法edit(),经典,用cakephp烘焙,另外还有关联的表:

    $client = $this->Clients->get($id, [
        'contain' => ['ClientMetadatas']
    ]); 
    if ($this->request->is(['patch', 'post', 'put'])) {
        $client = $this->Clients->patchEntity($client, $this->request->data);
        if ($this->Clients->save($client, ['associated' => ['ClientMetadatas']])) {
            $this->Flash->success(__('The client has been saved.'));
        } else {
            $this->Flash->error(__('The client could not be saved. Please, try again.'));
            $this->response->statusCode(500);
            $client=$client->errors();
        }   
    }   
    $this->set(compact('client'));
    $this->set('_serialize', ['client']);

我如何编辑客户端及其元数据的一个示例是调用'/clients/edit/clientid.json'

{
        "firstname": "John",
        "firstname": "Smith",
        "client_metadatas": 
        [
            {
                "name": "test",
                "value": "test"
            }
        ]
}

这是我的问题:我想验证是否不存在具有此 client_id 和元数据名称的元数据。如果它存在,我会执行更新而不是插入。

似乎理想的解决方案是直接在模型中进行。

我尝试使用回调方法:

  • beforeSave(),但我无法修改实体
  • beforeFind(),但我无法修改查询

关于如何在保存实体之前正确进行验证以及在插入/更新之间切换的任何建议?

PS:我希望没有信息丢失。如果是这样,请不要犹豫,我会添加它们...

谢谢!

【问题讨论】:

    标签: php cakephp orm model cakephp-3.0


    【解决方案1】:

    插入/更新确定工作开箱即用

    CakePHPs ORM 可以开箱即用地自行完成。是更新还是插入,取决于要保存的实体的持久化状态,即基于Entity::isNew()的返回值。

    引用自 Table::save() API 文档:

    此方法将确定传递的实体是否需要在数据库中插入或更新。它通过检查实体上的isNew 方法来实现。

    需要存在主键值

    为了使其自动正确设置,您必须在数据中提供这些记录的可能现有主键值,以便编组器在修补请求数据时可以正确准备实体。

    因此,无论您在何处/如何准备该数据,请确保包含主键值以防它们存在,以便您发送如下内容:

    {
        "firstname": "John",
        "firstname": "Smith",
        "client_metadatas": 
        [
            {
                "id": 1,
                "name": "existing",
                "value": "existing"
            },
            {
                "name": "non-existing",
                "value": "non-existing"
            }
        ]
    }
    

    第一个集合将是更新(假设存在具有此类 id 主键值的记录),第二个将是插入。

    根据自定义条件查找现有记录

    当然,您也可以自己处理事情,即无需在请求数据中传递主键值,至少只要有另一个唯一列。搜索其他自定义条件,例如记录名称,然后相应地修改实体以更新相应的行,应该可以正常工作。

    您可以在beforeSave 回调/事件中执行此操作,甚至可以在beforeMarshall 回调/事件中执行此操作,具体取决于您希望何时应用它,类似于:

    public function beforeSave(
        \Cake\Event\Event $event,
        \Cake\Datasource\EntityInterface $entity,
        \ArrayObject $options
    )
    {
        if ($entity->isNew()) {
            $existing = $this
                ->find()
                ->where([
                    'name' => $entity->get('name')
                ])
                ->first();
    
            if ($existing) {
                $entity->set('id', $existing->get('id'));
                $entity->isNew(false);
            }
        }
    
        return true;
    }
    

    另见

    【讨论】:

    • 我可以更改 beforeSave 上的实体,将 id 设置为现有记录并将 isNew() 设置为 false 吗?当我这样做时,它似乎不起作用。编辑:您的解决方案有效,但在控制器中。我想直接在Model中实现(因为我在其他几个地方编辑过这个表)
    • @WitoldW 这应该是可能的,是的......我已经更新了我的答案。
    • 我没想到会有这么好的和完整的答案。工作得很好而且很干净!非常感谢
    猜你喜欢
    • 2019-02-07
    • 2018-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-11
    • 1970-01-01
    • 2013-01-22
    相关资源
    最近更新 更多