Skip to content

Commit

Permalink
[Messenger] DoctrineEnvelopeEntityReference custom exception flow
Browse files Browse the repository at this point in the history
  • Loading branch information
mpoiriert committed Dec 13, 2024
1 parent 6807f88 commit ee2ee36
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 78 deletions.
11 changes: 10 additions & 1 deletion app/src/Message/NewUserMessage.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,28 @@

use App\Entity\User;
use Draw\Component\Messenger\AutoStamp\Message\StampingAwareInterface;
use Draw\Component\Messenger\DoctrineEnvelopeEntityReference\Exception\ObjectNotFoundException;
use Draw\Component\Messenger\DoctrineEnvelopeEntityReference\Message\DoctrineReferenceAwareInterface;
use Draw\Component\Messenger\DoctrineEnvelopeEntityReference\Stamp\PropertyReferenceStamp;
use Draw\Component\Messenger\Message\AsyncLowPriorityMessageInterface;
use Draw\Component\Messenger\Searchable\Stamp\SearchableTagStamp;
use Symfony\Component\Messenger\Envelope;

class NewUserMessage implements DoctrineReferenceAwareInterface, AsyncLowPriorityMessageInterface, StampingAwareInterface
{
public function __construct(private ?User $user)
private PropertyReferenceStamp|User|null $user;

public function __construct(User $user)
{
$this->user = $user;
}

public function getUser(): User
{
if ($this->user instanceof PropertyReferenceStamp) {
throw new ObjectNotFoundException(User::class, $this->user);
}

return $this->user;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,25 @@
use Doctrine\Persistence\ManagerRegistry;
use Doctrine\Persistence\ObjectManager;
use Draw\Component\Core\Reflection\ReflectionAccessor;
use Draw\Component\Core\Reflection\ReflectionExtractor;
use Draw\Component\Messenger\DoctrineEnvelopeEntityReference\Message\DoctrineReferenceAwareInterface;
use Draw\Component\Messenger\DoctrineEnvelopeEntityReference\Stamp\PropertyReferenceStamp;
use Draw\Component\Messenger\SerializerEventDispatcher\Event\BaseSerializerEvent;
use Draw\Component\Messenger\SerializerEventDispatcher\Event\PostDecodeEvent;
use Draw\Component\Messenger\SerializerEventDispatcher\Event\PostEncodeEvent;
use Draw\Component\Messenger\SerializerEventDispatcher\Event\PreEncodeEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
use Symfony\Component\Messenger\Stamp\SentToFailureTransportStamp;

class PropertyReferenceEncodingListener implements EventSubscriberInterface
class PropertyReferenceEncodingListener
{
public static function getSubscribedEvents(): array
{
return [
PreEncodeEvent::class => 'createPropertyReferenceStamps',
PostEncodeEvent::class => 'restoreDoctrineObjects',
PostDecodeEvent::class => 'restoreDoctrineObjects',
];
}

public function __construct(
private ?ManagerRegistry $ormManagerRegistry,
private ?ManagerRegistry $odmManagerRegistry,
) {
}

#[AsEventListener]
public function createPropertyReferenceStamps(PreEncodeEvent $event): void
{
$envelope = $event->getEnvelope();
Expand Down Expand Up @@ -79,6 +72,10 @@ public function createPropertyReferenceStamps(PreEncodeEvent $event): void
$event->setEnvelope($envelope->with(...$stamps));
}

#[
AsEventListener(event: PostEncodeEvent::class),
AsEventListener(event: PostDecodeEvent::class)
]
public function restoreDoctrineObjects(BaseSerializerEvent $event): void
{
$message = $event->getEnvelope()->getMessage();
Expand All @@ -90,11 +87,35 @@ public function restoreDoctrineObjects(BaseSerializerEvent $event): void
$stamps = $event->getEnvelope()->all(PropertyReferenceStamp::class);

foreach ($stamps as $stamp) {
$object = $this->getManagerForClass($stamp->getClass())
->find($stamp->getClass(), $stamp->getIdentifiers())
;

if ($object) {
ReflectionAccessor::setPropertyValue(
$message,
$stamp->getPropertyName(),
$object
);

continue;
}

$propertyReflection = ReflectionAccessor::getPropertyReflection(
$message,
$stamp->getPropertyName(),
);

$classes = ReflectionExtractor::getClasses($propertyReflection->getType());

if (!\in_array(PropertyReferenceStamp::class, $classes, true)) {
continue;
}

ReflectionAccessor::setPropertyValue(
$message,
$stamp->getPropertyName(),
$this->getManagerForClass($stamp->getClass())
->find($stamp->getClass(), $stamp->getIdentifiers())
$stamp,
);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

namespace Draw\Component\Messenger\DoctrineEnvelopeEntityReference\Exception;

use Draw\Component\Messenger\DoctrineEnvelopeEntityReference\Stamp\PropertyReferenceStamp;
use Symfony\Component\Messenger\Exception\UnrecoverableExceptionInterface;

class ObjectNotFoundException extends \Exception implements UnrecoverableExceptionInterface
{
public function __construct(
private string $objectClass,
private ?PropertyReferenceStamp $propertyReferenceStamp = null,
) {
$message = \sprintf(
'Object of class [%s] not found.',
$objectClass,
);

if ($propertyReferenceStamp) {
$message .= \sprintf(
' Identifiers [%s]',
json_encode($propertyReferenceStamp->getIdentifiers())
);
}

parent::__construct($message);
}

public function getObjectClass(): string
{
return $this->objectClass;
}

public function getPropertyReferenceStamp(): ?PropertyReferenceStamp
{
return $this->propertyReferenceStamp;
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@
use Doctrine\ORM\EntityManagerInterface;
use Draw\Bundle\TesterBundle\PHPUnit\Extension\SetUpAutowire\AutowireService;
use Draw\Component\Core\Reflection\ReflectionAccessor;
use Draw\Component\Messenger\DoctrineEnvelopeEntityReference\Exception\ObjectNotFoundException;
use Draw\Component\Messenger\SerializerEventDispatcher\Event\PostEncodeEvent;
use Draw\Component\Messenger\SerializerEventDispatcher\Event\PreEncodeEvent;
use Draw\Component\Tester\PHPUnit\Extension\SetUpAutowire\AutowiredInterface;
use Draw\Contracts\Messenger\EnvelopeFinderInterface;
use PHPUnit\Framework\Attributes\Depends;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;

/**
* @internal
Expand All @@ -25,23 +26,25 @@ class PropertyReferenceEncodingListenerTest extends KernelTestCase implements Au
#[AutowireService]
private EnvelopeFinderInterface $envelopeFinder;

#[AutowireService]
private EntityManagerInterface $entityManager;

#[AutowireService]
private EventDispatcherInterface $eventDispatcher;

private bool $preEncodeEventCalled = false;

private bool $postEncodeEventCalled = false;

private static string $email;
private static User $user;

public function testSend(): void
{
$container = static::getContainer();

$entityManager = $container->get(EntityManagerInterface::class);
$eventDispatcher = $container->get(EventDispatcherInterface::class);
self::$user = (new User())
->setEmail(uniqid().'@example.com')
;

$user = new User();
$user->setEmail(self::$email = uniqid().'@example.com');

$eventDispatcher->addListener(
$this->eventDispatcher->addListener(
PreEncodeEvent::class,
function (PreEncodeEvent $event): void {
$message = $event->getEnvelope()->getMessage();
Expand All @@ -62,9 +65,9 @@ function (PreEncodeEvent $event): void {
-1
);

$eventDispatcher->addListener(
$this->eventDispatcher->addListener(
PostEncodeEvent::class,
function (PostEncodeEvent $event) use ($user): void {
function (PostEncodeEvent $event): void {
$message = $event->getEnvelope()->getMessage();
if (!$message instanceof NewUserMessage) {
return;
Expand All @@ -73,7 +76,7 @@ function (PostEncodeEvent $event) use ($user): void {
$this->postEncodeEventCalled = true;

static::assertSame(
$user,
self::$user,
ReflectionAccessor::getPropertyValue(
$message,
'user'
Expand All @@ -84,9 +87,9 @@ function (PostEncodeEvent $event) use ($user): void {
-1
);

$entityManager->persist($user);
$this->entityManager->persist(self::$user);

$entityManager->flush();
$this->entityManager->flush();

static::assertTrue($this->preEncodeEventCalled);

Expand All @@ -96,18 +99,45 @@ function (PostEncodeEvent $event) use ($user): void {
#[Depends('testSend')]
public function testLoad(): void
{
$envelope = $this->envelopeFinder->findByTags([self::$email])[0];
$envelope = $this->envelopeFinder->findByTags([self::$user->getEmail()])[0];

$message = $envelope->getMessage();

static::assertInstanceOf(NewUserMessage::class, $message);

static::assertSame(
self::$email,
self::$user->getEmail(),
$message->getUser()->getEmail()
);
}

#[Depends('testSend')]
public function testLoadNotFound(): void
{
$this->entityManager
->getConnection()
->delete('draw_acme__user', ['email' => self::$user->getEmail()])
;

$envelope = $this->envelopeFinder->findByTags([self::$user->getEmail()])[0];

$message = $envelope->getMessage();

static::assertInstanceOf(NewUserMessage::class, $message);

$this->expectException(ObjectNotFoundException::class);

$this->expectExceptionMessage(
\sprintf(
'Object of class [%s] not found. Identifiers [%s]',
User::class,
json_encode(['id' => self::$user->getId()]),
)
);

$message->getUser();
}

public function testODM(): void
{
$testDocument = new TestDocument();
Expand Down

0 comments on commit ee2ee36

Please sign in to comment.