Я реализую ReviewableBehavior для реализации принципа четырех глаз.Поведение реализует beforeDelete()
, beforeSave()
и afterSave()
и использует таблицу reviews для хранения запросов CUD.
- для добавленных записей, создается запись
$review
и сохраняется в afterSave()
(потому что только у нас есть идентификатор вновь добавленной записи, который нам нужно сохранить в $review
) - для отредактированных записей, в
beforeSave()
значения, которые былиизмененные сохраняются в записи $review
, в отредактированной записи значения этих полей возвращаются к своим исходным значениям (поэтому в основном изменения не сохраняются) - для удаленных записей в
beforeDelete()
a $review
сохраняется для сохранения запроса на удаление, и возвращается false, чтобы отменить удаление.
Номер 3. является проблемой, поскольку, хотя $review
всегда имел правильно установленное значение первичного ключа, как если бысохранение было действительно успешным, и save($review)
вернул true, как будто все прошло хорошо, на самом деле он не был сохранен в базе данных.
Причина, насколько я понимаю: удаления по умолчанию выполняются в транзакциификция.Транзакция запускается в delete()
таблицы, затем запускается beforeDelete()
поведения.С помощью обработчика событий я вызываю ReviewTable->save($review)
.Поскольку транзакция была начата, это save()
происходит внутри транзакции.Затем я возвращаю false, потому что я хочу, чтобы удаление было остановлено.Это откатывает транзакцию и вместе с ней ReviewTable->save($review)
.
попытки решения:
- Если я не верну false,
$review
сохраняется в базе данных, но«основная» запись также удаляется.Недостаток: неосуществимый подход, поскольку запись удаляется, что нам не нужно. - Если я позвоню
delete($entity, ['atomic' => false]);
, то транзакция не начнется, следовательно, ReviewTable->save($review)
выполняется.Недостаток: для любой модели, которая использует это поведение, нам нужно было бы изменить каждый вызов на delete()
, чтобы переключить атомарный элемент.Также это отключает использование транзакций, что не кажется мне подходящим. - Метод удаления «Перезаписать» в ReviewableBehavior , поэтому для любой таблицы, использующей это поведение, когда
delete()
называется, на самом деле delete()
из _ReviewableBehavior_ выполняется.Недостаток: технически невозможно переписать табличные методы поведением. - Создайте новый класс таблицы, перезапишите в нем метод
delete()
и извлеките любую таблицу, используя ReviewableBehavior из класса таблицы.Недостаток: уродливый подход, связанный с использованием как поведения, так и нового класса таблицы. - Создайте новый метод
deleteRequest()
в ReviewableBehavior , и вместо вызова Table->delete()
мы вызываем Table->deleteRequest()
.В нем мы можем сохранить запрос на удаление в записи $review
, удаление в любом случае не выполняется, поскольку мы на самом деле не вызывали delete()
.Disdavantage: для любой модели, которая использует это поведение, нам нужно будет изменить каждый вызов на delete()
на deleteRequest()
В настоящее время я использую последний подход, но яочень хотел бы услышать некоторые мнения по этому поводу, а также о том, есть ли лучший способ как-то сохранить транзакцию, но сохранить что-то "между".