У меня есть класс Listener, который при создании объекта Post или Thread обновляет эти поля в таблице категорий:
last_post_thread_title
last_post_thread_slug
last_poster_username
last_post_body
last_post_created_at
is_last_post_op
и last_post_created_at в таблице потоков.
class LastPostListener
{
public function postPersist(LifeCycleEventArgs $args)
{
$entity = $args->getObject();
$entityManager = $args->getObjectManager();
$this->handleEvent($entityManager, $entity);
}
public function postUpdate(LifeCycleEventArgs $args)
{
$entity = $args->getObject();
$entityManager = $args->getObjectManager();
$this->handleEvent($entityManager, $entity);
}
public function handleEvent($entityManager, $entity)
{
if (!$entity instanceof Post && !$entity instanceof Thread) {
return;
}
$isPost = $entity instanceof Post;
$thread = $isPost ? $entity->getThread() : $entity;
$post = $isPost ? $entity : $thread;
$category = $thread->getCategory();
$category->setLastPostThreadTitle($thread->getTitle());
$category->setLastPostThreadSlug($thread->getSlug());
$category->setLastPostBody($post->getBody());
$category->setLastPosterUsername($post->getUser()->getUsername());
$category->setLastPostCreatedAt($post->getCreatedAt());
$category->setIsLastPostOp(!$isPost);
$thread->setLastPostCreatedAt($entity->getCreatedAt());
$entityManager->persist($thread, $category);
$entityManager->flush();
}
}
Однако, когда редактируется СУЩЕСТВУЮЩАЯ тема или сообщение, ранее упомянутые поля таблицы категорий не обновляются.
То же самое с событиями prePersist() и preUpdate(), с очисткой или без нее.
Конечно, можно добавить все линии $category->set напрямую в функцию контроллера update, но это грязно.
Какое событие следует использовать здесь или, может быть, есть какое-то другое решение? Спасибо
Поскольку событие postUpdate вызывается внутри метода сброса, а изменения объекта не имеют значения, вы должны использовать другой способ обновления данных. См. doctrine-project.org/projects/doctrine-orm/en/2.6/reference/… Это может быть хорошим подходом stackoverflow.com/a/25312851/3497902.




Причина такого поведения объясняется в Документация по доктрине с подробным описанием разрешенных операций в каждом из типов событий. Если вы посмотрите на эту статью, то увидите, что событие preUpdate очень ограничено, а postUpdate даже не имеет значения. Вообще говоря, основная причина вашей текущей проблемы - это попытка вызова flush(), когда flush() уже запущен.
Если вы хотите синхронизировать информацию - есть несколько способов:
onFlush. Это событие дает вам доступ ко всем рассчитанным изменениям, запланированным для фиксации, и позволяет вам изучить эти изменения, чтобы решить, что нужно обновить. Однако это может быть не так просто, потому что вам придется иметь дело с методами UnitOfWork, которые раскрывают внутренние представления вычисляемых изменений, например. getScheduledEntityUpdates() и другие подобные методы. Также потребуется вручную пересчитать наборы изменений в случае, если вы будете вносить какие-либо изменения в сущности в рамках этого события.Вы можете реализовать отдельный класс, который будет предоставлять собственный метод flush(), который должен будет выглядеть примерно так:
class CustomFlush {
/**
* @var EntityManager
*/
private $em;
/**
* @var array
*/
private $changes = [];
public function flush($entity = null) {
// Perform normal flushing operation
$this->em->flush($entity);
// If there was some changes collected - apply them
if (!empty($this->changes)) {
$categories = [];
// Apply changes from $this->changes to Category entities,
// collect them in $categories and flush separately
if (!empty($categories)) {
$this->em->flush($categories);
}
}
}
public function preUpdate(LifeCycleEventArgs $args) {
// Collect updates from Post and Thread and store it into $this->changes
}
}
Было бы хорошо, если бы вы обновили свой вопрос объяснениями того, что вы подразумеваете под «не работает». Что вы пытаетесь реализовать с помощью этого кода?