Инструменты пользователя

Инструменты сайта


eaze:samples:одновременное_редактирование_объектов

Различия

Здесь показаны различия между двумя версиями данной страницы.

Ссылка на это сравнение

Следущая версия
Предыдущая версия
eaze:samples:одновременное_редактирование_объектов [2012/11/23 17:19]
sergeyfast создано
eaze:samples:одновременное_редактирование_объектов [2014/03/23 13:36] (текущий)
sergeyfast
Строка 1: Строка 1:
 ====== Отслеживание одновременного редактирования объектов в VT ====== ====== Отслеживание одновременного редактирования объектов в VT ======
-По умолчанию в VT при сохранении объектов действует правило ​"​кто последний нажал сохранить,​ того и форма :)". Попробуем исправить это, поставив следующую задачу:​+По умолчанию в VT при сохранении объектов действует правило"​кто последний нажал сохранить,​ того и форма :)". Попробуем исправить это, поставив следующую задачу:​
  
 >В VT при редактировании объекта давать сохранять именно ту версию объекта,​ которая была открыта на тот момент. ​ >В VT при редактировании объекта давать сохранять именно ту версию объекта,​ которая была открыта на тот момент. ​
->​Если редактирование одновременно было открыто два раза, то при нажатии кнопки "​сохранить"​ во второй раз система не должна позволить сделать ​это, так как в первый раз уже было произведено сохранение. ​+>​Если ​страница ​редактирования одновременно была открыта два раза, то при нажатии кнопки "​сохранить"​ во второй раз система не должна позволить сохранить изменения, так как в первый раз уже было произведено сохранение. ​
  
 Эта схема называется [[https://​en.wikipedia.org/​wiki/​Optimistic_concurrency_control|"​Optimistic Concurrency Control"​]] Эта схема называется [[https://​en.wikipedia.org/​wiki/​Optimistic_concurrency_control|"​Optimistic Concurrency Control"​]]
Строка 9: Строка 9:
 ===== Реализация ===== ===== Реализация =====
 Решение данной задачи можно рассматривать в различных вариантах,​ но мы, как программисты,​ определим свои ограничения заранее. Решение данной задачи можно рассматривать в различных вариантах,​ но мы, как программисты,​ определим свои ограничения заранее.
-У объекта могут быть связанные объекты (листы),​ обычно они редактируются на одной странице,​ поэтому нам важен сам факт нажатия кнопки "​Сохранить и закрыть"​ или "​Применить"​. ​+У объекта могут быть связанные объекты (листы),​ обычно они редактируются на одной странице,​ поэтому нам важен сам факт нажатия кнопки "​Сохранить и закрыть"​ или "​Применить"​, а не то, что изменилось в объекте
 Если в объекте ничего не поменялось,​ мы не учитываем это. По своей сути задача сводится к записи времени последнего редактирования объекта. Если в объекте ничего не поменялось,​ мы не учитываем это. По своей сути задача сводится к записи времени последнего редактирования объекта.
  
Строка 38: Строка 38:
  
 ==== ObjectHistoryUtility.php ==== ==== ObjectHistoryUtility.php ====
-Утилита {{:​eaze:​samples:​objecthistoryutility.phps|}} будет работать только с теми объектами,​ у которых уже есть Factory.+Утилита {{:​eaze:​samples:​objecthistoryutility.phps|ObjectHistoryUtility.phps}} будет работать только с теми объектами,​ у которых уже есть Factory.
 Переменная ''​$InsertsOnly''​ отвечает за режим работы. Если значение ''​true'',​ то в ''​objectHistory''​ будет хронология всех изменений,​ иначе - только последнее изменение. Переменная ''​$InsertsOnly''​ отвечает за режим работы. Если значение ''​true'',​ то в ''​objectHistory''​ будет хронология всех изменений,​ иначе - только последнее изменение.
  
Строка 44: Строка 44:
  
 ==== Save<​Class>​Action.php ==== ==== Save<​Class>​Action.php ====
 +=== beforeAction() ===
 <code php> <code php>
         /**         /**
Строка 65: Строка 65:
             // initialize ohCreatedAt             // initialize ohCreatedAt
             if ( !$this->​action && !$this->​ohCreatedAt && $this->​originalObject ​ ) {             if ( !$this->​action && !$this->​ohCreatedAt && $this->​originalObject ​ ) {
 +                $this->​ohCreatedAt = DateTimeWrapper::​Now();​
 +            } else if ( $this->​action == BaseSaveAction::​DeleteAction ) {
                 $this->​ohCreatedAt = DateTimeWrapper::​Now();​                 $this->​ohCreatedAt = DateTimeWrapper::​Now();​
             }             }
Строка 72: Строка 74:
 </​code>​ </​code>​
  
-В данном куске кода мы определили переменные ''​user''​(текущий пользователь VT) , ''​ohCreatedAt''​ (дата открытия страницы редактирования)+В данном куске кода мы определили переменные ''​user''​ (текущий пользователь ​в VT) , ''​ohCreatedAt''​ (дата открытия страницы редактирования, инициализируем её при первом открытии). 
 +Не забудьте добавить в массив опций ''​options''​ : ''​WithReturningKeys => true''​ в конструкторе. 
 + 
 +=== validate() === 
 + 
 +Добавим в ''​validate()''​ следующую проверку перед ''​return $errors'':​ 
 +<code php> 
 +ObjectHistoryUtility::​ValidateObject( $this->​originalObject,​ $this->​ohCreatedAt,​ $errors ); 
 +</​code>​ 
 +Метод ''​ObjectHistoryUtility::​ValidateObject'' ​ модифицирует массив ''​$errors''​ в случае необходимости,​ проверка идет при заполненном поле ''​$this->​originalObject''​. 
 + 
 +=== add() === 
 + 
 +<code php> 
 +        protected function add( $object ) { 
 +            ConnectionFactory::​BeginTransaction();​ 
 +             
 +            $result = parent::​$factory->​Add( $object, $this->​options ); 
 +            $result = $result && ObjectHistoryUtility::​Save( $object, $this->​user ); 
 +             
 +            ConnectionFactory::​CommitTransaction( $result ); 
 +            return $result; 
 +        } 
 +</​code>​ 
 + 
 +=== update() === 
 +<code php> 
 +        protected function update( $object ) { 
 +            ConnectionFactory::​BeginTransaction();​ 
 +            $result = parent::​$factory->​Update( $object ); 
 + 
 +            $result = $result && ObjectHistoryUtility::​Save( $object, $this->​user ); 
 +            if ( $result ) { 
 +                Response::​setParameter( '​ohCreatedAt',​ ObjectHistoryUtility::​$LastCreatedAt ); 
 +            } 
 + 
 +            ConnectionFactory::​CommitTransaction( $result ); 
 +            return $result; 
 +        } 
 +</​code>​ 
 +Обновление ''​ohCreatedAt''​ необходимо для кнопки "​Применить"​. 
 +code php 
 +==== edit.tmpl.php ==== 
 + 
 +Перед подключением шаблона ''​data.tmpl.php''​ добавьте:​ 
 +<code php> 
 +<?= FormHelper::​FormHidden( '​ohCreatedAt',​ !empty( $ohCreatedAt ) ? $ohCreatedAt->​format('​c'​) : ''​ ); ?> 
 +</​code>​ 
 + 
 + 
 +==== data.tmpl.php ==== 
 +После ''​$errors["​fatal"​]''​ добавьте:​ 
 +<code php> 
 +// Render Errors from Object History 
 +echo ObjectHistoryUtility::​RenderErrors( $errors ); 
 +</​code>​ 
 + 
 +==== ru.xml ====  
 +Перед закрытием тега ''​errors''​ добавьте:​ 
 + 
 +<code xml> 
 +    <​objectHistory>​ 
 +        <​alreadyUpdated><​![CDATA[Объект уже был обновлен ранее в %s. Вы не можете применить свои изменения. Снова <a href="​%s">​переоткройте</​a>​ эту страницу.]]></​alreadyUpdated>​ 
 +        <​empty><​![CDATA[Не удалось определить время открытия страницы. Вы не можете применить свои изменения. Снова <a href="​%s">​переоткройте</​a>​ эту страницу.]]></​empty>​ 
 +    </​objectHistory>​ 
 +</​code>​ 
 + 
 +===== Результат ===== 
 +При одновременном сохранении объекта второй получит вот такую ошибку:​ 
 + 
 +{{ :​eaze:​samples:​objecthistory-tv.png?​ |}} 
 + 
 +==== Плюсы ==== 
 +  * Универсальное решение для любого объекта в VT. 
 +  * Минимальные правки в код. 
 +  * Простая интеграция в существующие проекты. 
 + 
 +==== Минусы ==== 
 +  * Если открыть страницу,​ ничего не менять,​ и нажать кнопку "​сохранить изменения",​ то дата последнего изменения обновится,​ хотя по логике вещей не должна - мы же ничего не меняли:​). 
 + 
 +==== Дальнейшее развитие ==== 
 +  * Можно добавить кнопку на яваскрипте - "​Все равно сохранить мою версию"​ (кнопка меняет значение ohCreatedAt на now() и делает submit формы). 
 +  * Можно добавить в таблицу ''​objectHistory''​ поле ''​changes'',​ в котором в сериализованном виде хранить изменившиеся значения полей у объекта (и его листов). После создания такой функциональности берегитесь своей бурной фантазии :)
eaze/samples/одновременное_редактирование_объектов.1353676775.txt.gz · Последние изменения: 2012/11/23 17:19 — sergeyfast