Created
March 29, 2015 23:39
-
-
Save index0h/fa7f41aa5f9d9a6e5224 to your computer and use it in GitHub Desktop.
History.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Поведение для отслеживания изменений. | |
* | |
* **ВНИМАНИЕ!!!** | |
* Данное поведение не работает с моножественными действиями: update и delete, будьте внимательны. | |
* | |
* ### Подготовка: | |
* | |
* - Необходимо создать такую же таблицу с суфиксом **_history**, как отслежуемая, но с дополнительными полями: | |
* | |
* ```php | |
* <?php | |
* 'historyId' => 'BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY', | |
* 'historyState' => "ENUM('create','update','delete') NOT NULL COMMENT 'Тип изменения.'", | |
* 'historyDate' => "TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT 'Дата изменения.'", | |
* 'historyUserId' => "INT UNSIGNED NULL COMMENT 'Идентификатор пользователя, выполнившего изменение.'", | |
* 'historyContext' => "text NULL COMMENT 'JSON объект для дополнительных данных.'" | |
* ``` | |
* | |
* - Так же для поля **id** **убираем** ключ **PRIMARY**. | |
* - Создаем модель для данный таблицы с суфиксом **History**. | |
* - Подключаем поведение в отслеживаемую модель. | |
* | |
* ```php | |
* <?php | |
* public function behaviors() | |
* { | |
* return array( | |
* 'history' => array( | |
* 'class' => '\some_namespace_here\History' | |
* ) | |
* ); | |
* } | |
* ``` | |
* | |
* ### Использование: | |
* | |
* В общем тут все просто: при сохранении, изменении, или удалении отслеживаемой модели все действия с историей | |
* выполняются автоматически. | |
* | |
* Для сохранения смыслового контекста (причина изменений) - используется атрибут historyContext, в СУБД он | |
* сохраняется как JSON-строка. | |
* | |
* ```php | |
* <?php | |
* $model->history->context = array('userType' => 'guest'); | |
*/ | |
namespace some_namespace_here; | |
/** | |
* Поведение для отслеживания изменений. | |
*/ | |
class History extends \CActiveRecordBehavior | |
{ | |
/** | |
* Дата изменения, на случай необходимости задания "вручную". | |
*/ | |
public $date; | |
/** | |
* Контекст изменения, должне сохранять допонтиельные данные связанные с причиной изменения. | |
*/ | |
public $context; | |
/** | |
* Регистрирует изменение при вставке, или обновлении. | |
* | |
* @param \CEvent $event Событие вызова afterSave. | |
*/ | |
public function afterSave($event) | |
{ | |
$state = ($this->owner->scenario === 'insert') ? 'create': 'update'; | |
$this->saveState($state); | |
} | |
/** | |
* Регистрирует удаление записи. | |
* | |
* @param \CEvent $event Событие вызова afterDelete. | |
*/ | |
public function afterDelete($event) | |
{ | |
$this->saveState('delete'); | |
} | |
/** | |
* Выполняет подготовку атрибутов вспомогательной модели слежения перед ее сохранением. | |
* | |
* @param array $attributes Атрибуты обслуживаемой модели. | |
* @param string $state Состояние изменения (create, update, delete). | |
*/ | |
protected function prepareAttributes($attributes, $state) | |
{ | |
try { | |
$userId = \Yii::app()->user->id; | |
} catch (\Exception $error) { | |
// Возникает в случае консольного вызова, по этой причине не логгируется. | |
$userId = null; | |
} | |
$context = ($this->context === null)? null: json_encode($this->context); | |
$date = ($this->date === null)? components\Date::timestamp(): $this->date; | |
return \CMap::mergeArray( | |
$attributes, | |
array( | |
'historyState' => $state, | |
'historyDate' => $date, | |
'historyContext' => $context, | |
'historyUserId' => $userId | |
) | |
); | |
} | |
/** | |
* Создает и сохраняет вспомогательную модель слежения. | |
* | |
* @param $state Состояние изменения (create, update, delete). | |
*/ | |
protected function saveState($state) | |
{ | |
$historyModel = get_class($this->owner) . 'History'; | |
$model = new $historyModel; | |
$attributes = $this->prepareAttributes($this->owner->attributes, $state); | |
foreach ($attributes as $key => $value) { | |
$model->$key = $value; | |
} | |
$model->insert(); | |
$this->context = null; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment