Symfony 2 - флеш в postUpdate fire preUpdate event
Я обнаружил эту проблему "спасибо" исключению, которое я получил:
Catchable Fatal Error: Argument 3 passed to
Doctrine\ORM\Event\PreUpdateEventArgs::__construct()
must be an array, null given, called in
/.../vendor/doctrine/lib/Doctrine/ORM/UnitOfWork.php on line 804
and defined in
/.../vendor/doctrine/lib/Doctrine/ORM/Event/PreUpdateEventArgs.php line 28
Я работаю над проектом, который требует определенной логики:
Когда поле order
в объекте book
изменено, мне нужно обновить поле books_order_modified_at
в родительском объекте bookstore
(это поле позволяет мне узнать, был ли изменен порядок книг в книжном магазине).
Я решил сделать это в прослушивателе событий, так как в коде есть много мест, которые могут изменить порядок книг.
Я не нашел способа обновить связанный объект из события preUpdate
, поэтому у меня есть приватное поле в классе слушателя, которое я использую, чтобы сообщить postUpdate
событию обновить соответствующий объект bookstore
.
Моя проблема в том, что когда я делаю так, событие preUpdate
объекта book
запускается.
Когда я проверяю набор изменений, он содержит только поле modified_at
, но имеет то же значение до и после.
Если у кого-то есть другая идея, как решить проблему - отлично.
Если нет - любая идея, как я могу предотвратить событие preUpdate
от запуска, когда флеш вызывается в теге postUpdate
event??
Ответы
Ответ 1
На самом деле это проблема из доктрины Doctrine Issue DDC-2726. Решив его, добавив четкий вызов менеджера сущностей после флеша в слушателе, так что 3-й аргумент этого конструктора, который на самом деле является entityChangeSets, будет переписан.
Ответ 2
Как насчет обновления modified_at
внутри ваших объектов и позволить доктрине справиться с этим? Вы изменили бы метод setOrder в своей книге, чтобы обновить объект BookOrder следующим образом:
class Book {
public function setOrder($order) {
// modify book
$this->bookOrder->updateModifiedAt();
}
}
Конечно, вашему BookOrder пришлось бы реализовать modifiedAt:
class BookOrder {
public function updateModifiedAt() {
$this->modifiedAt = new \DateTime();
}
}
Если вы используете другие классы для своего Datetime, вы, конечно, должны изменить этот код!
Доктрина должна признать, что BookOrder изменился и должен обновить его без необходимости использования прослушивателя событий.
Ответ 3
Я могу предложить вам использовать Timestampable extension для Doctrine из DoctrineExtensionsBundle.
Используя его, вам не нужно устанавливать значения created_at
или modified_at
. Это расширение делает это автоматически. Даже он может устанавливать modified_at
только при изменении определенных полей. См. пример.
Я думаю, вы пишете что-то вроде этого расширения. Итак, вам не нужно это делать, потому что это уже сделано:)
Ответ 4
У меня была аналогичная проблема. Попытка использовать preupdate
для изменения дочерних элементов вызвала ту же ошибку. В конце концов, мое решение просто обновить дочерние элементы родителя. Явный запрос на flush
не требуется.
/**
* Update expiry dates for all runners belonging to a campaign
*
* @param $runners
* @param $expiryDate
*/
private function updateCampaignRunners($runners, $expiryDate){
foreach($runners as $runner){
$runner->setExpiresAt($expiryDate);
$this->getModelManager()->update($runner);
}
}
/**
* Post update and persist lifecycle callback
*
* @param Campaign $campaign
*/
private function postAction(Campaign $campaign)
{
$runnerExpire = $this->getForm()->get("runnerExpire")->getData();
if($runnerExpiryDate && $campaign->getRunners()){
$this->updateCampaignRunners($campaign->getRunners(), $runnersExpiryDate);
}
}