doulan6245 2017-02-21 18:38
浏览 14
已采纳

CakePhp 3:在键值表中插入/更新相关字段之间切换

I'm having trouble modifying the logic for saving one of my associated table. The two tables are:

  • Clients
  • ClientMetadatas (storing the client's metadata with key/value pairs)

In the Clients Controller, the method edit(), classic, baked with cakephp, with the associated table in addition:

    $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']);

An example of how I edit a client and its metadatas would be, calling '/clients/edit/clientid.json'

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

Here's my problem: I'd like to verify if there is no metadata existing with this client_id and metadata's name. If it exists, I'd perform an update rather than an insert.

It seems that the ideal solution would be to do it in the Model directly.

I tried to use the callback methods:

  • beforeSave(), but I wasn't able to modify the entity
  • beforeFind(), but I wasn't able to modify the query

Any advice on how to properly do the verification and the switch between insert/update before saving the entity?

PS: I hope no information in missing. If it the case, don't hesitate, I'll add them...

Thank you !

  • 写回答

1条回答 默认 最新

  • dongtang3155 2017-02-21 19:15
    关注

    Insert/update determination works out of the box

    CakePHPs ORM can do that on its own out of the box. Whether an update or an insert is being performed, is figured based on the persistence status of the entity that is to be saved, ie based on the return value of Entity::isNew().

    Quote from the Table::save() API docs:

    This method will determine whether the passed entity needs to be inserted or updated in the database. It does that by checking the isNew method on the entity.

    Primary key values need to be present

    In order to have this being set up properly automatically, you have to provide the possible existing primary key values of those records in your data, so that the marshaller can prepare the entities properly when patching in the request data.

    So where/however you are preparing that data, make sure that you include the primary key value(s) in case they exist, so that you send something like this:

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

    The first set would be an update (given that a record with such an id primary key value exists), the second one would be an insert.

    Find existing records based on custom criteria

    Surely it's also possible to handle things on your own, ie without passing the primary key values in the request data, at least as long as there is another unique column. Searching for other, custom criterias, like the name of the record, and then modifying the entity accordingly so that the respective row is being updated, should work fine.

    You could do that in the beforeSave callback/event, or even in the beforeMarshall callback/event, depending on when you want to this to apply, something along the lines of:

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

    See also

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 WPF动态创建页面内容
  • ¥15 如何对TBSS的结果进行统计学的分析已完成置换检验,如何在最终的TBSS输出结果提取除具体值及如何做进一步相关性分析
  • ¥15 SQL数据库操作问题
  • ¥100 关于lm339比较电路出现的问题
  • ¥15 Matlab安装yalmip和cplex功能安装失败
  • ¥15 加装宝马安卓中控改变开机画面
  • ¥15 STK安装问题问问大家,这种情况应该怎么办
  • ¥15 关于罗技鼠标宏lua文件的问题
  • ¥15 halcon ocr mlp 识别问题
  • ¥15 已知曲线满足正余弦函数,根据其峰值,还原出整条曲线