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 js调用html页面需要隐藏某个按钮
  • ¥15 ads仿真结果在圆图上是怎么读数的
  • ¥20 Cotex M3的调试和程序执行方式是什么样的?
  • ¥20 java项目连接sqlserver时报ssl相关错误
  • ¥15 一道python难题3
  • ¥15 牛顿斯科特系数表表示
  • ¥15 arduino 步进电机
  • ¥20 程序进入HardFault_Handler
  • ¥15 oracle集群安装出bug
  • ¥15 关于#python#的问题:自动化测试