{{tag>DEV Инвентаризация history model}}
====== Инвентаризация: DEV: Model History ======
Как нам вести историю изменения моделей.
++++ Первоначальная задумка |
заводим таблицу, которая
* содержит те же поля что и исходная таблица
* master_id - ID в мастер таблице где хранится актуальная версия модели
* строковые поля, содержащие id ссылок через запятую для many-2-many realtions
* changed_at - время начала периода действия записи (unix epoch)
* changed_by - автор изменений (string login)
* changed_comment - комментарий к изменениям
* changed_attributes - список изменившихся атрибутов (кроме ['id','updated_at','updated_by','changed_attributes','updated_comment'])
после изменения модели добавляем запись в таблицу истории с новыми значениями и автором
Возможно получится это залепить через Behaviour (некогда разбираться)
Также очевидно, что изменение полей относящихся к many2many связям приводит к "изменению" связанных объектов. Почему в кавычках? Потому что в самой таблице модели изменений нет, но если посмотреть many2many атрибуты (из других таблиц), то изменения есть. Таким образом надо внести в класс истории модели
* функцию вытаскивания many2many связанных объектов
* список полей которые надо будет прописывать в журнал связанных объектов из инициатора изменений: udated_at,updated_by,updated_comment придется брать из журнала инициатора, т.к. связанный объект явно не изменялся
* функцию журналирования состояния с возможностью указания инициатора изменений
Для возможности отображения загруженного из журнала объекта через те же формы, журнальный объект должен мимикрировать под оригинал. Для этого целесообразно все вычисляемые параметры вынести в Trait и подключить трейты и к оригиналу и к журналу
++++
++++ Кандидаты на аудит |
* Сервисы (важный узел, нужно видеть кто что меняет)
* Документы - видеть кто косячит при заведении
* Оборудование - косяки при заведении
* Модели оборудования - косяки при заведении
* ACL - чувствительные данные
++++
====== Как добавить историю модели ======
===== Таблицы =====
В самой модели должны быть поля
* updated_at (timestamp()) - время обновления модели
* updated_by (string(32)) - логин обновившего (т.к. логин может скакать между пользователями, которые на самом деле сотрудники, а не пользователи)
$this->addColumnIfNotExist('aces','updated_at',$this->timestamp(),true);
$this->addColumnIfNotExist('aces','updated_by',$this->string(32),true);
Создаем таблицу для модели истории
Там должны быть поля
* master_id (integer()) - ссылка на оригинальную модель **+ индекс**
* updated_at (timestamp()) - отметка о времени записи изменения **+ индекс**
* updated_by (string(32)) - логин изменившего **+ индекс**
* (опционально) updated_comment (string()) - можно комментировать каждое изменение
* changed_attributes (text()) - список полей изменившихся относительно прошлой записи (через запятую)
Все поля оригинальной модели нужно также добавить в том же виде (если не добавить, то их история не будет вестись)
Также (если) нужно добавить поля для many-2-many и обратных ссылок в виде (text()) полей. Туда будут складываться ID объектов связанных с моделью.
Например:
* users_ids (text())
* comps_ids (text())
$this->createTable('aces_history',[
'id'=>$this->primaryKey(),
'master_id'=>$this->integer(),
'updated_at'=>$this->timestamp(),
'updated_by'=>$this->string(32),
'updated_comment'=>$this->string(),
'changed_attributes'=>$this->text(),
'comment'=>$this->string(),
'notepad'=>$this->text(),
'acls_id'=>$this->integer(),
'users_ids'=>$this->text(),
'comps_ids'=>$this->text(),
'access_types_ids'=>$this->text(),
'ips'=>$this->text(),
]);
$this->createIndex('aces_history-master_id','aces_history','master_id');
$this->createIndex('aces_history-updated_at','aces_history','updated_at');
$this->createIndex('aces_history-updated_by','aces_history','updated_by');
===== Модели =====
==== Исходная ====
Должна наследоваться от ArmsModel, тогда в процессе afterSave будет проверяться наличие класса истории, и если он есть, то история изменений будет сохранена
=== Атрибуты Ссылки ===
надо, чтобы в оригинальной модели были доступны атрибуты с ID объектов с many-2-many и one-2-many обратными ссылками. Если это many-2-many ссылки, то они там уже объявлены через Behaviour. Для обратных ссылок one-2-many можно использовать тот же механизм, прописав эти поля в Behaviour many-2-many
/**
* В списке поведений прикручиваем many-to-many ссылки
* @return array
*/
public function behaviors()
{
return [
[
'class' => \voskobovich\linker\LinkerBehavior::className(),
'relations' => [
'users_ids' => 'users',
'comps_ids' => 'comps',
'access_types_ids' => 'accessTypes',
]
]
];
}
=== Атрибут Name ===
Должен быть, если ссылки на этот объект есть в истории других объектов
сойдет даже вычисляемый getName()