CakePhp 3:在键值表

时间:2017-02-21 18:38:44

标签: php cakephp orm model cakephp-3.0

我在修改保存其中一个关联表的逻辑时遇到问题。 这两个表是:

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

在客户端控制器中,方法edit(),classic,用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:我希望没有丢失的信息。如果是这样,请不要犹豫,我会添加它们......

谢谢!

1 个答案:

答案 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;
}

另见