Для управления параллелизмом — это означает, что данные, сохраняемые в базе данных, не устарели или уже не отредактированы каким-либо другим пользователем — в моем приложении CakePHP я использую modified
атрибут в моих функциях редактирования. Ниже приведен фрагмент кода, который находится в моем контроллере.
$this->MyModel->recursive = -1;
$event = $this->MyModel->findById($id);
$requestTimeStamp = new DateTime($this->request->data['MyModel']['modified']);
$dbTimeStamp = new DateTime($event['MyModel']['modified']);
if ($requestTimeStamp < $dbTimeStamp) {
$response = array(
'success' => false,
'id' => $id,
'message' => 'A concurrency error occurred while trying to save. Please try again');
echo json_encode($response);
exit;
} else {
//... continue processing
}
Этот код работает нормально, но, пытаясь оптимизировать его в своем приложении, я пытаюсь выяснить, где его лучше разместить. Это лучшее место в моем AppModel
класс или лучше создать Behavior
для того же самого или это просто лучше оставить в контроллере? Я полагаю, что идеальный вариант будет учитывать производительность и минимизировать объем загрузки классов, а также издержки доступа к базе данных.
Кто-нибудь сталкивался / решил эту проблему раньше? Мысли / предложения приветствуются.
Так что я решил это, сделав проверку параллелизма частью моего AppModel->beforeSave()
метод. Ниже приведен код для ссылки других
/*
* Incorporated concurrency check in the beforeSave callback method to ensure that data is not stale before user saves.
* The function checks if the model has a `modified` field, before it proceeds. If the model does not have such a method
* then concurrency does not apply to this data structure. Upon proceeding, the method checks to see if the value of modified
* data is the same in the database as well as the request that invokes this method. If they are not same then the save is
* aborted
* This method requires the view or controller to pass a variable called data[ModelName][modified].
* This variable must contain the value of the modified field when the record was read and it must be passed back as such.
* I usually set a hidden form field in my view like below -
* <input type="hidden" name="data[Model][modified]" value="<?php echo $model['modifed']; ?>" />
*/
public function beforeSave($options = array()) {
if ($this->hasField('modified') && isset($this->data[$this->name]['id']) && isset($this->data[$this->name]['modified'])) {
CakeLog::debug('AppModel: beforeSave - inside concurrency check');
CakeLog::debug($this->data);
$this->recursive = -1;
// run a select statement to ensure the modified date in the database has not changed. If it has changed then
// the below find query will return 0 rows
$row = $this->find('first', array(
'fields' => array(
'id', 'modified'
),
'conditions' => array(
'id' => $this->data[$this->name]['id'],
'modified' => $this->data[$this->name]['modified']
)
));
// if no row is returned then error out and return - basically a concurrency error has occurred
if (!$row) {
CakeLog::error($this->name.':Concurrency error - [row-id:'.$this->data[$this->name]['id'].']');
return false;
}
// if a row was retrned then there is no concurrency error, so proceed but change the modified date
// to current timestamp to reflect accuracy
$this->data[$this->name]['modified'] = date('Y-m-d H:i:s');
return true;
}
}
Других решений пока нет …