Reputation: 136
I'm trying to link a coffee profile to a user after the user is in the database. This coffee profile data is in a session and I'm using this session in the postFlush.
However This code is creating an infinite loop and I don't know why:
UserListener.php:
<?php
namespace AppBundle\EventListener;
use FOS\UserBundle\FOSUserEvents;
use FOS\UserBundle\Event\FormEvent;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\HttpFoundation\Session\Session;
use AppBundle\Entity\Consumption;
use AppBundle\Entity\CoffeeOption;
use AppBundle\Entity\Consumeable;
use AppBundle\Entity\MomentPreference;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Doctrine\ORM\Event\PostFlushEventArgs;
class UserListener
{
private $container;
private $user;
public function __construct(ContainerInterface $container = null)
{
$this->container = $container;
}
public function postPersist(LifecycleEventArgs $args)
{
$user = $args->getEntity();
$this->user = $user;
}
public function postFlush(PostFlushEventArgs $args)
{
$session = new Session();
if($session) {
$em = $args->getEntityManager();
$us = $em->getRepository('AppBundle:User')->findOneById($this->user->getId());
$consumption = $session->get('consumption');
$coffee = $session->get('coffee');
$moment = $session->get('moment');
$consumption->setUser($us);
//dummy data for the day, later this needs to be turned into datetime
$moment->setDay('monday');
$moment->setConsumption($consumption);
$em->persist($consumption);
$em->persist($coffee);
$em->persist($moment);
$em->flush();
} else {
return $this->redirectToRoute('fos_user_registration_register');
}
}
}
Services.yml:
zpadmin.listener.user:
class: AppBundle\EventListener\UserListener
arguments: ['@service_container']
tags:
- { name: doctrine.event_listener, event: postPersist }
- { name: doctrine.event_listener, event: postFlush }
What is causing this loop and how can I fix it?
Upvotes: 1
Views: 7205
Reputation: 36
This example try please
use Doctrine\Bundle\DoctrineBundle\EventSubscriber\EventSubscriberInterface;
use Doctrine\ORM\Event\OnFlushEventArgs;
use Doctrine\ORM\Event\PostFlushEventArgs;
use Doctrine\ORM\Events;
use Symfony\Component\DependencyInjection\ContainerInterface;
class DatabaseActivitySubscriber implements EventSubscriberInterface
{
/**
* @var array
*/
protected array $changeUpdateDataEntityList = [];
/**
* @var array
*/
protected array $changeDeleteDataEntityList = [];
/**
* @var \Symfony\Component\DependencyInjection\ContainerInterface
*/
protected ContainerInterface $container;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
public function getSubscribedEvents(): array
{
return [
Events::postFlush,
Events::onFlush
];
}
public function postFlush(PostFlushEventArgs $args): void
{
foreach ($this->changeUpdateDataEntityList as $entity) {
// Do something
}
}
public function onFlush(OnFlushEventArgs $eventArgs): void
{
$em = $eventArgs->getObjectManager();
$uow = $em->getUnitOfWork();
foreach ($uow->getScheduledEntityInsertions() as $entity) {
// Do something
}
foreach ($uow->getScheduledEntityUpdates() as $entity) {
// Do something
}
foreach ($uow->getScheduledEntityDeletions() as $entity) {
// Do something
}
}
}
Upvotes: 1
Reputation: 2596
In your postFlush
event, you're flushing again. That's what causing the infinite loop because the postFlush
event is triggered every time you're calling the flush
method.
I'm not sure what you're trying to achieve but your goal is to create a coffee consumption everytime you're saving a user, you can add a test like this one at the start of your method:
$entity = $args->getObject();
if (!$entity instanceof User) {
return;
}
This will prevent the infinite loop.
And a few more things:
postPersist
method seems useless. It'll be called every time an object is persisted so your $this->user
propety will not necessarily be a User object.$args->getObject()
to get the flushed entity. In addition with the test above, you'll be sure the method will return you a User object.Upvotes: 2
Reputation: 2157
You are calling $em->flush()
inside your postPersist event, in the docs it is stated that:
postFlush is called at the end of EntityManager#flush(). EntityManager#flush() can NOT be called safely inside its listeners.
You should use other events like prePersist
or postPersist
.
If possible try to avoid multiple flush()
on a single request.
by the way, there is no need to do this, because your user object is already contained inside your $user variable.
$us = $em->getRepository('AppBundle:User')->findOneById($this->user->getId());
Upvotes: 1