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 linux驱动,linux应用,多线程
  • ¥20 我要一个分身加定位两个功能的安卓app
  • ¥15 基于FOC驱动器,如何实现卡丁车下坡无阻力的遛坡的效果
  • ¥15 IAR程序莫名变量多重定义
  • ¥15 (标签-UDP|关键词-client)
  • ¥15 关于库卡officelite无法与虚拟机通讯的问题
  • ¥15 目标检测项目无法读取视频
  • ¥15 GEO datasets中基因芯片数据仅仅提供了normalized signal如何进行差异分析
  • ¥100 求采集电商背景音乐的方法
  • ¥15 数学建模竞赛求指导帮助