Я пытаюсь реализовать поведение ключ / значение на основе https://github.com/josegonzalez/cakephp-keyvalue
Мое поведение будет вставлять новые строки в базу данных для каждого нового ключа из отправки формы, независимо от количества ключей, и обновлять существующие записи, если user_id и ключ найдены в таблице KeyValue. Я уже связал пользовательскую модель с моделью KeyValue, а также с поведением.
Если в базе данных нет записи user_id / key, она будет правильно вставлять новые записи. Однако я обнаружил, что если я пытаюсь обновить существующие пары ключ-значение одного и того же пользователя, первые два значения будут обновлены правильно, но последнее переданное значение приведет к новой записи.
После некоторого расследования я обнаружил, что в цикле сохранения в beforeSave()
даже если я назначу идентификатор модели в beforeSave()
с $Model->id
перед возвратом истины, он не будет передан Model->save()
учебный класс.
Я использую торт 2.5.4
Model->id
в beforeSave не переходит на Model->save()
в lib/Model/Model.php:# 1841
if ($count > 0) {
$cache = $this->_prepareUpdateFields(array_combine($fields, $values));
**pr($this->id); //this value is empty**
if (!empty($this->id)) {
$this->__safeUpdateMode = true;
try {
$success = (bool)$db->update($this, $fields, $values);
} catch (Exception $e) {
$this->__safeUpdateMode = false;
throw $e;
}
$this->__safeUpdateMode = false;
}
KeyValueBehavior:
public function beforeSave(Model $Model, $options = array()) {
extract($this->options[$Model->alias]);
$keys = array_keys($Model->data[$Model->alias]);
$data = $Model->data;
if (in_array($fields['key'], $keys) && in_array($fields['value'], $keys)) {
return true;
}
if (isset($data[$Model->alias]) && ! empty($data[$Model->alias])) {
$dataTemplate = array($Model->alias => array());
foreach ($data[$Model->alias] as $field => $value) {
if ($Model->hasField($field)) {
$dataTemplate[$Model->alias][$field] = $value;
unset($data[$Model->alias][$field]);
}
}
$index = 0;
foreach ($data[$Model->alias] as $key => $value) {
$index ++;
$insert = $dataTemplate;
$insert[$Model->alias][$fields['key']] = $key;
if ($uniqueKeys) {
$Model->deleteAll(reset($insert));
}
$insert[$Model->alias][$fields['value']] = $value;
//check existing key value
$belongsTo = reset($Model->belongsTo);
$existing = $Model->find('first', array(
'conditions' => array(
$belongsTo['foreignKey'] => $insert[$Model->alias][$belongsTo['foreignKey']],
$fields['key'] => $insert[$Model->alias][$fields['key']]
)
));$Model->create();
if(sizeof($existing) > 0){
$existingKV = reset($existing);
//pr($existingKV);
$Model->read(null, $existingKV['id']);
}if ($index == count($data[$Model->alias])) {
// Even if Model->id is set here, it will not be passed to Model->save()
$Model->id = $existingKV['id'];
$Model->data = $insert;
pr($Model); // Model->id is set here but not in Model->save()
return true;
} else {
pr($insert); //Updates correctly
if (false === $Model->save($insert)) {
return false;
}
}
}
}
UsersController:
public function test() {
if ($this->request->is('post')) {
$this->Userdetail->create();
$this->request->data['Userdetail']['user_id'] = $this->Auth->user('id');
if ($this->Userdetail->save($this->request->data)) {
$this->Session->setFlash(__('The Userdetail has been saved'));
// $this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The Userdetail could not be saved. Please, try again.'));
}
}
$users = $this->Userdetail->User->find('list');
$this->set(compact('users'));
}
Тогда у меня есть три примера полей в моем View View / Users / test.ctp:
<?php
echo $this->Form->create('Userdetail');
echo $this->Form->input('field1');
echo $this->Form->input('field2');
echo $this->Form->input('field3');
echo $this->Form->end('submit');
Чтобы обойти это, я добавил еще один ключ с именем «id_holder» в модель в beforeSave()
и отредактировал Model/Model.php
, Но в конечном итоге я не хочу редактировать ядро CakePHP.
Редактировать: по новому saveKeyValues()
метод:
public function saveKeyValues(Model $Model, $data){
if($Model == null || $data == null){
return false;
}
if (isset($data[$Model->alias]) && ! empty($data[$Model->alias])) {
$dataTemplate = array($Model->alias => array());
foreach ($data[$Model->alias] as $field => $value) {
if ($Model->hasField($field)) {
$dataTemplate[$Model->alias][$field] = $value;
unset($data[$Model->alias][$field]);
}
}
}
$belongsTo = reset($Model->belongsTo);
$index = 0;
foreach ($data[$Model->alias] as $key => $value) {
$index++;
$insert = $dataTemplate;
$insert[$Model->alias][$this->options[$Model->alias]['fields']['key']] = $key;
$insert[$Model->alias][$this->options[$Model->alias]['fields']['value']] = $value;
$insert[$Model->alias][$belongsTo['foreignKey']] = $data[$belongsTo['foreignKey']];
//check existing key value
$existing = $Model->find('first', array(
'conditions' => array(
$belongsTo['foreignKey'] => $data[$belongsTo['foreignKey']],
$this->options[$Model->alias]['fields']['key'] => $key
)
));
//Reset for create/update
$Model->create();
if(sizeof($existing) > 0){
$existingKV = reset($existing);
$Model->read(null, $existingKV['id']);
}
if (false === $Model->save($insert)) {
return false;
}
if($index == count($data[$Model->alias])){
return true;
}
}
}
Задача ещё не решена.
Других решений пока нет …