From c94e11499b90248496514ee1d160fa0870e36e96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Witold=20Kara=C5=9B?= Date: Wed, 17 Jul 2024 13:27:24 +0200 Subject: [PATCH] Switching ArgumentValueResolverInterface into ValueResolverInterface --- config/services.php | 3 +- config/services_test.php | 3 +- src/ValueResolver/DtoValueResolver.php | 46 +++++++++++ .../ValueResolver/DtoValueResolverTest.php | 77 +++++++++++++++++++ 4 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 src/ValueResolver/DtoValueResolver.php create mode 100644 tests/Unit/ValueResolver/DtoValueResolverTest.php diff --git a/config/services.php b/config/services.php index db439e4..8af2cee 100644 --- a/config/services.php +++ b/config/services.php @@ -36,6 +36,7 @@ use DualMedia\DtoRequestBundle\Service\Type\CoercerService; use DualMedia\DtoRequestBundle\Service\Validation\GroupProviderService; use DualMedia\DtoRequestBundle\Service\Validation\TypeValidationHelper; +use DualMedia\DtoRequestBundle\ValueResolver\DtoValueResolver; use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; use Symfony\Component\DependencyInjection\Reference; @@ -137,7 +138,7 @@ ->arg(6, new Reference(ActionValidatorService::class)) ->arg(7, new Reference('validator')); - $services->set(DtoArgumentResolver::class) + $services->set(interface_exists(\Symfony\Component\HttpKernel\Controller\ValueResolverInterface::class) ? DtoValueResolver::class : DtoArgumentResolver::class) ->arg(0, new Reference(DtoResolverInterface::class)) ->arg(1, new Reference('event_dispatcher')) ->tag('controller.argument_value_resolver'); diff --git a/config/services_test.php b/config/services_test.php index 9338525..2b1929a 100644 --- a/config/services_test.php +++ b/config/services_test.php @@ -17,6 +17,7 @@ use DualMedia\DtoRequestBundle\Service\Type\CoercerService; use DualMedia\DtoRequestBundle\Service\Validation\TypeValidationHelper; use DualMedia\DtoRequestBundle\Tests\Service\Entity\DummyModelProvider; +use DualMedia\DtoRequestBundle\ValueResolver\DtoValueResolver; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor; @@ -49,7 +50,7 @@ DtoOADescriber::class, - DtoArgumentResolver::class, + interface_exists(\Symfony\Component\HttpKernel\Controller\ValueResolverInterface::class) ? DtoValueResolver::class : DtoArgumentResolver::class, OnNullActionValidator::class, HttpDtoActionSubscriber::class, diff --git a/src/ValueResolver/DtoValueResolver.php b/src/ValueResolver/DtoValueResolver.php new file mode 100644 index 0000000..6b93fd4 --- /dev/null +++ b/src/ValueResolver/DtoValueResolver.php @@ -0,0 +1,46 @@ + + */ + public function resolve( + Request $request, + ArgumentMetadata $argument + ): iterable { + $class = $argument->getType(); + + if (null === $class || !is_subclass_of($class, DtoInterface::class)) { + return []; + } + + $this->eventDispatcher->dispatch( + new DtoResolvedEvent( + $object = $this->dtoResolver->resolve($request, $class) + ) + ); + + $object->setOptional($argument->isNullable()); + + yield $object; + } + } +} diff --git a/tests/Unit/ValueResolver/DtoValueResolverTest.php b/tests/Unit/ValueResolver/DtoValueResolverTest.php new file mode 100644 index 0000000..069689b --- /dev/null +++ b/tests/Unit/ValueResolver/DtoValueResolverTest.php @@ -0,0 +1,77 @@ +eventMock = $this->createMock(EventDispatcherInterface::class); + self::$container->set('event_dispatcher', $this->eventMock); + + if (interface_exists(\Symfony\Component\HttpKernel\Controller\ValueResolverInterface::class)) { + $this->service = $this->getService(DtoValueResolver::class); + } + } + + public function testResolve(): void + { + if (!interface_exists(\Symfony\Component\HttpKernel\Controller\ValueResolverInterface::class)) { + $this->assertTrue(true); + + return; + } + + $event = $this->deferCallable(function ($event): void { + $this->assertInstanceOf(DtoResolvedEvent::class, $event); + $this->assertInstanceOf(SubDto::class, $event->getDto()); + }); + + $this->eventMock->expects($this->once()) + ->method('dispatch') + ->willReturnCallback(function (...$args) use ($event) { + $event->set($args); + + return $args[0]; + }); + + $request = new Request([], [ + 'value' => 155, + 'floaty_boy' => 22.5, + ]); + + $mock = $this->createMock(ArgumentMetadata::class); + $mock->method('getType') + ->willReturn(SubDto::class); + $mock->method('isNullable') + ->willReturn(false); + + /** + * @var SubDto $dto + * + * @psalm-suppress InvalidArgument + */ + $dto = iterator_to_array($this->service->resolve($request, $mock))[0]; + + $this->assertInstanceOf(SubDto::class, $dto); + $this->assertTrue($dto->isValid()); + $this->assertEquals(155, $dto->value); + $this->assertEquals(22.5, $dto->floatVal); + $this->assertTrue($dto->visited('value')); + $this->assertTrue($dto->visited('floatVal')); + } +}