diff --git a/src/Symfony/Bridge/Doctrine/CHANGELOG.md b/src/Symfony/Bridge/Doctrine/CHANGELOG.md index 8265e9e682..18885f00b2 100644 --- a/src/Symfony/Bridge/Doctrine/CHANGELOG.md +++ b/src/Symfony/Bridge/Doctrine/CHANGELOG.md @@ -4,7 +4,7 @@ CHANGELOG 4.4.0 ----- - * added `DoctrineClearEntityManagerMiddleware` + * added `DoctrineClearEntityManagerWorkerSubscriber` * deprecated `RegistryInterface`, use `Doctrine\Common\Persistence\ManagerRegistry` * added support for invokable event listeners * added `getMetadataDriverClass` method to deprecate class parameters in service configuration files diff --git a/src/Symfony/Bridge/Doctrine/Messenger/DoctrineClearEntityManagerMiddleware.php b/src/Symfony/Bridge/Doctrine/Messenger/DoctrineClearEntityManagerMiddleware.php deleted file mode 100644 index 0bef9be641..0000000000 --- a/src/Symfony/Bridge/Doctrine/Messenger/DoctrineClearEntityManagerMiddleware.php +++ /dev/null @@ -1,36 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Bridge\Doctrine\Messenger; - -use Doctrine\ORM\EntityManagerInterface; -use Symfony\Component\Messenger\Envelope; -use Symfony\Component\Messenger\Middleware\StackInterface; -use Symfony\Component\Messenger\Stamp\ConsumedByWorkerStamp; - -/** - * Clears entity manager after calling all handlers. - * - * @author Konstantin Myakshin - */ -class DoctrineClearEntityManagerMiddleware extends AbstractDoctrineMiddleware -{ - protected function handleForManager(EntityManagerInterface $entityManager, Envelope $envelope, StackInterface $stack): Envelope - { - try { - return $stack->next()->handle($envelope, $stack); - } finally { - if (null !== $envelope->last(ConsumedByWorkerStamp::class)) { - $entityManager->clear(); - } - } - } -} diff --git a/src/Symfony/Bridge/Doctrine/Messenger/DoctrineClearEntityManagerWorkerSubscriber.php b/src/Symfony/Bridge/Doctrine/Messenger/DoctrineClearEntityManagerWorkerSubscriber.php new file mode 100644 index 0000000000..8fad66c77b --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Messenger/DoctrineClearEntityManagerWorkerSubscriber.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Doctrine\Messenger; + +use Doctrine\Common\Persistence\ManagerRegistry; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\Messenger\Event\WorkerMessageFailedEvent; +use Symfony\Component\Messenger\Event\WorkerMessageHandledEvent; + +/** + * Clears entity managers between messages being handled to avoid outdated data. + * + * @author Ryan Weaver + */ +class DoctrineClearEntityManagerWorkerSubscriber implements EventSubscriberInterface +{ + private $managerRegistry; + + public function __construct(ManagerRegistry $managerRegistry) + { + $this->managerRegistry = $managerRegistry; + } + + public function onWorkerMessageHandled() + { + $this->clearEntityManagers(); + } + + public function onWorkerMessageFailed() + { + $this->clearEntityManagers(); + } + + public static function getSubscribedEvents() + { + yield WorkerMessageHandledEvent::class => 'onWorkerMessageHandled'; + yield WorkerMessageFailedEvent::class => 'onWorkerMessageFailed'; + } + + private function clearEntityManagers() + { + foreach ($this->managerRegistry->getManagers() as $manager) { + $manager->clear(); + } + } +} diff --git a/src/Symfony/Bridge/Doctrine/Tests/Messenger/DoctrineClearEntityManagerMiddlewareTest.php b/src/Symfony/Bridge/Doctrine/Tests/Messenger/DoctrineClearEntityManagerMiddlewareTest.php deleted file mode 100644 index 580cd3fb8e..0000000000 --- a/src/Symfony/Bridge/Doctrine/Tests/Messenger/DoctrineClearEntityManagerMiddlewareTest.php +++ /dev/null @@ -1,76 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Bridge\Doctrine\Tests\Messenger; - -use Doctrine\Common\Persistence\ManagerRegistry; -use Doctrine\ORM\EntityManagerInterface; -use Symfony\Bridge\Doctrine\Messenger\DoctrineClearEntityManagerMiddleware; -use Symfony\Component\Messenger\Envelope; -use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException; -use Symfony\Component\Messenger\Stamp\ConsumedByWorkerStamp; -use Symfony\Component\Messenger\Test\Middleware\MiddlewareTestCase; - -class DoctrineClearEntityManagerMiddlewareTest extends MiddlewareTestCase -{ - public function testMiddlewareClearEntityManager() - { - $entityManager = $this->createMock(EntityManagerInterface::class); - $entityManager->expects($this->once()) - ->method('clear'); - - $managerRegistry = $this->createMock(ManagerRegistry::class); - $managerRegistry - ->method('getManager') - ->with('default') - ->willReturn($entityManager); - - $middleware = new DoctrineClearEntityManagerMiddleware($managerRegistry, 'default'); - - $envelope = new Envelope(new \stdClass(), [ - new ConsumedByWorkerStamp(), - ]); - $middleware->handle($envelope, $this->getStackMock()); - } - - public function testInvalidEntityManagerThrowsException() - { - $managerRegistry = $this->createMock(ManagerRegistry::class); - $managerRegistry - ->method('getManager') - ->with('unknown_manager') - ->will($this->throwException(new \InvalidArgumentException())); - - $middleware = new DoctrineClearEntityManagerMiddleware($managerRegistry, 'unknown_manager'); - - $this->expectException(UnrecoverableMessageHandlingException::class); - - $middleware->handle(new Envelope(new \stdClass()), $this->getStackMock(false)); - } - - public function testMiddlewareDoesNotClearInNonWorkerContext() - { - $entityManager = $this->createMock(EntityManagerInterface::class); - $entityManager->expects($this->never()) - ->method('clear'); - - $managerRegistry = $this->createMock(ManagerRegistry::class); - $managerRegistry - ->method('getManager') - ->with('default') - ->willReturn($entityManager); - - $middleware = new DoctrineClearEntityManagerMiddleware($managerRegistry, 'default'); - - $envelope = new Envelope(new \stdClass()); - $middleware->handle($envelope, $this->getStackMock()); - } -} diff --git a/src/Symfony/Bridge/Doctrine/Tests/Messenger/DoctrineClearEntityManagerWorkerSubscriberTest.php b/src/Symfony/Bridge/Doctrine/Tests/Messenger/DoctrineClearEntityManagerWorkerSubscriberTest.php new file mode 100644 index 0000000000..6a76cf8ad0 --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Tests/Messenger/DoctrineClearEntityManagerWorkerSubscriberTest.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Doctrine\Tests\Messenger; + +use Doctrine\Common\Persistence\ManagerRegistry; +use Doctrine\ORM\EntityManagerInterface; +use Symfony\Bridge\Doctrine\Messenger\DoctrineClearEntityManagerWorkerSubscriber; +use Symfony\Component\Messenger\Test\Middleware\MiddlewareTestCase; + +class DoctrineClearEntityManagerWorkerSubscriberTest extends MiddlewareTestCase +{ + public function testMiddlewareClearEntityManager() + { + $entityManager1 = $this->createMock(EntityManagerInterface::class); + $entityManager1->expects($this->once()) + ->method('clear'); + + $entityManager2 = $this->createMock(EntityManagerInterface::class); + $entityManager2->expects($this->once()) + ->method('clear'); + + $managerRegistry = $this->createMock(ManagerRegistry::class); + $managerRegistry + ->method('getManagers') + ->with() + ->willReturn([$entityManager1, $entityManager2]); + + $subscriber = new DoctrineClearEntityManagerWorkerSubscriber($managerRegistry); + $subscriber->onWorkerMessageHandled(); + } +}