diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 881b50c..3476aa3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,7 +24,6 @@ jobs: strategy: matrix: php-version: - - "7.3" - "7.4" - "8.0" runs-on: ubuntu-latest diff --git a/README.md b/README.md index 5bf3cdd..90f4830 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,12 @@ # DTO Bundle Package for an automatic request to predefined structures conversion in symfony applications. -[![Build Status](https://travis-ci.org/vseinstrumentiru/dto-bundle.svg?branch=master)](https://travis-ci.org/github/vseinstrumentiru/dto-bundle) [![Coverage Status](https://coveralls.io/repos/github/vseinstrumentiru/dto-bundle/badge.svg?branch=master)](https://coveralls.io/github/vseinstrumentiru/dto-bundle?branch=master) ## Installation ```bash -$ composer require vi-tech/dto-bundle +$ composer require vseinstrumentiru/dto-bundle ``` Declare bundle in configuration: @@ -15,17 +14,25 @@ Declare bundle in configuration: ```php // config/bundles.php return [ - \ViTech\DataObjectBundle\DataObjectBundle::class => ['all' => true], + \Vseinstrumentiru\DataObjectBundle\DataObjectBundle::class => ['all' => true], ]; ``` ## Usage +Keep in mind that resolver matches only one strategy at a time and is fully dependent on +Request::getMethod. +**GET** Requests are mapped from query `Request->query->all()` . +Every other method is mapped from request body `Request->request->all()` + +> This means that one can not map data from body and query in the same request. +> Normally there should not be such a situation. + ```php 0 + + 0 + diff --git a/src/DataObjectBundle.php b/src/DataObjectBundle.php index 1acf356..ef7f6e5 100644 --- a/src/DataObjectBundle.php +++ b/src/DataObjectBundle.php @@ -2,9 +2,9 @@ declare(strict_types=1); -namespace ViTech\DataObjectBundle; +namespace Vseinstrumentiru\DataObjectBundle; -use ViTech\DataObjectBundle\Resolver\RequestObjectResolver; +use Vseinstrumentiru\DataObjectBundle\Resolver\RequestObjectResolver; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Reference; @@ -17,11 +17,11 @@ public function build(ContainerBuilder $container) parent::build($container); $definition = new Definition(ObjectFactory::class); - $container->setDefinition('vi_tech.dto.object_factory', $definition); - $container->setAlias(ObjectFactoryInterface::class, 'vi_tech.dto.object_factory'); + $container->setDefinition('vseinstrumentiru.dto.object_factory', $definition); + $container->setAlias(ObjectFactoryInterface::class, 'vseinstrumentiru.dto.object_factory'); $definition = new Definition(RequestObjectResolver::class, [new Reference(ObjectFactoryInterface::class)]); $definition->addTag('controller.argument_value_resolver'); - $container->setDefinition('vi_tech.dto.resolver.request_object', $definition); + $container->setDefinition('vseinstrumentiru.dto.resolver.request_object', $definition); } } diff --git a/src/Exception/ObjectInitError.php b/src/Exception/ObjectInitError.php index e053dc9..14e399a 100644 --- a/src/Exception/ObjectInitError.php +++ b/src/Exception/ObjectInitError.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace ViTech\DataObjectBundle\Exception; +namespace Vseinstrumentiru\DataObjectBundle\Exception; class ObjectInitError extends \Exception { diff --git a/src/Object/AbstractObject.php b/src/Object/AbstractObject.php index 54760c4..4128a57 100644 --- a/src/Object/AbstractObject.php +++ b/src/Object/AbstractObject.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace ViTech\DataObjectBundle\Object; +namespace Vseinstrumentiru\DataObjectBundle\Object; use Spatie\DataTransferObject\DataTransferObject; diff --git a/src/Object/DataObjectInterface.php b/src/Object/DataObjectInterface.php index fe754ee..1fef5b1 100644 --- a/src/Object/DataObjectInterface.php +++ b/src/Object/DataObjectInterface.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace ViTech\DataObjectBundle\Object; +namespace Vseinstrumentiru\DataObjectBundle\Object; /** * Data object interface diff --git a/src/ObjectFactory.php b/src/ObjectFactory.php index 5049851..7318eb2 100644 --- a/src/ObjectFactory.php +++ b/src/ObjectFactory.php @@ -2,11 +2,11 @@ declare(strict_types=1); -namespace ViTech\DataObjectBundle; +namespace Vseinstrumentiru\DataObjectBundle; use Throwable; -use ViTech\DataObjectBundle\Exception\ObjectInitError; -use ViTech\DataObjectBundle\Object\AbstractObject; +use Vseinstrumentiru\DataObjectBundle\Exception\ObjectInitError; +use Vseinstrumentiru\DataObjectBundle\Object\AbstractObject; class ObjectFactory implements ObjectFactoryInterface { diff --git a/src/ObjectFactoryInterface.php b/src/ObjectFactoryInterface.php index 95d4e85..1e98169 100644 --- a/src/ObjectFactoryInterface.php +++ b/src/ObjectFactoryInterface.php @@ -2,9 +2,9 @@ declare(strict_types=1); -namespace ViTech\DataObjectBundle; +namespace Vseinstrumentiru\DataObjectBundle; -use ViTech\DataObjectBundle\Exception\ObjectInitError; +use Vseinstrumentiru\DataObjectBundle\Exception\ObjectInitError; interface ObjectFactoryInterface { diff --git a/src/Resolver/RequestObjectResolver.php b/src/Resolver/RequestObjectResolver.php index 9314184..32a1772 100644 --- a/src/Resolver/RequestObjectResolver.php +++ b/src/Resolver/RequestObjectResolver.php @@ -2,10 +2,10 @@ declare(strict_types=1); -namespace ViTech\DataObjectBundle\Resolver; +namespace Vseinstrumentiru\DataObjectBundle\Resolver; -use ViTech\DataObjectBundle\Exception\ObjectInitError; -use ViTech\DataObjectBundle\ObjectFactoryInterface; +use Vseinstrumentiru\DataObjectBundle\Exception\ObjectInitError; +use Vseinstrumentiru\DataObjectBundle\ObjectFactoryInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface; use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; @@ -13,8 +13,10 @@ class RequestObjectResolver implements ArgumentValueResolverInterface { - /** @var ObjectFactoryInterface */ - private $objectFactory; + /** + * Dto initializer + */ + private ObjectFactoryInterface $objectFactory; public function __construct(ObjectFactoryInterface $objectFactory) { @@ -40,7 +42,11 @@ public function resolve(Request $request, ArgumentMetadata $argument) yield null; } - $requestData = $request->request->all(); + if ($request->isMethod('GET')) { + $requestData = $request->query->all(); + } else { + $requestData = $request->request->all(); + } try { yield $this->objectFactory->createDataObject($requestData, $argument->getType()); diff --git a/test/Fixture/CollectionItemDto.php b/test/Fixture/CollectionItemDto.php index 2300469..51dcc2f 100644 --- a/test/Fixture/CollectionItemDto.php +++ b/test/Fixture/CollectionItemDto.php @@ -2,19 +2,13 @@ declare(strict_types=1); -namespace Test\ViTech\DataObjectBundle\Fixture; +namespace Test\Vseinstrumentiru\DataObjectBundle\Fixture; -use ViTech\DataObjectBundle\Object\AbstractObject; +use Vseinstrumentiru\DataObjectBundle\Object\AbstractObject; class CollectionItemDto extends AbstractObject { - /** - * @var string - */ - public $name; + public string $name; - /** - * @var float - */ - public $order; + public float $order; } diff --git a/test/Fixture/SomeDto.php b/test/Fixture/SomeDto.php index 8e36c60..600215a 100644 --- a/test/Fixture/SomeDto.php +++ b/test/Fixture/SomeDto.php @@ -2,25 +2,19 @@ declare(strict_types=1); -namespace Test\ViTech\DataObjectBundle\Fixture; +namespace Test\Vseinstrumentiru\DataObjectBundle\Fixture; -use ViTech\DataObjectBundle\Object\AbstractObject; +use Vseinstrumentiru\DataObjectBundle\Object\AbstractObject; class SomeDto extends AbstractObject { - /** - * @var string - */ - public $someProperty; + public string $someProperty; - /** - * Fully qualified namespace is required by spatie/dto - * @var \Test\ViTech\DataObjectBundle\Fixture\SomeSubDto - */ - public $someEmbeddedProperty; + public SomeSubDto $someEmbeddedProperty; /** - * @var \Test\ViTech\DataObjectBundle\Fixture\CollectionItemDto[] + * Fully qualified namespace is required by spatie/dto. + * @var \Test\Vseinstrumentiru\DataObjectBundle\Fixture\CollectionItemDto[] */ - public $collectionItems; + public array $collectionItems; } diff --git a/test/Fixture/SomeSubDto.php b/test/Fixture/SomeSubDto.php index 16517bd..6c090ad 100644 --- a/test/Fixture/SomeSubDto.php +++ b/test/Fixture/SomeSubDto.php @@ -2,19 +2,13 @@ declare(strict_types=1); -namespace Test\ViTech\DataObjectBundle\Fixture; +namespace Test\Vseinstrumentiru\DataObjectBundle\Fixture; -use ViTech\DataObjectBundle\Object\AbstractObject; +use Vseinstrumentiru\DataObjectBundle\Object\AbstractObject; class SomeSubDto extends AbstractObject { - /** - * @var int - */ - public $property1; + public int $property1; - /** - * @var string - */ - public $property2; + public string $property2; } diff --git a/test/Resolver/RequestObjectResolverTest.php b/test/Resolver/RequestObjectResolverTest.php index f5a9233..36b0c4f 100644 --- a/test/Resolver/RequestObjectResolverTest.php +++ b/test/Resolver/RequestObjectResolverTest.php @@ -2,80 +2,124 @@ declare(strict_types=1); -namespace Test\ViTech\DataObjectBundle\Resolver; +namespace Test\Vseinstrumentiru\DataObjectBundle\Resolver; use PHPUnit\Framework\TestCase; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Controller\ArgumentResolver; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; -use ViTech\DataObjectBundle\Exception\ObjectInitError; -use ViTech\DataObjectBundle\ObjectFactory; -use ViTech\DataObjectBundle\Resolver\RequestObjectResolver; -use Test\ViTech\DataObjectBundle\Fixture\SomeDto; +use Test\Vseinstrumentiru\DataObjectBundle\Fixture\CollectionItemDto; +use Vseinstrumentiru\DataObjectBundle\Exception\ObjectInitError; +use Vseinstrumentiru\DataObjectBundle\ObjectFactory; +use Vseinstrumentiru\DataObjectBundle\Resolver\RequestObjectResolver; +use Test\Vseinstrumentiru\DataObjectBundle\Fixture\SomeDto; class RequestObjectResolverTest extends TestCase { - /** - * @var Request - */ - private $request; - - /** - * @var ArgumentResolver - */ - private $argumentsResolver; + private ArgumentResolver $argumentsResolver; protected function setUp(): void { parent::setUp(); - $this->request = new Request(); $requestObjectResolver = new RequestObjectResolver(new ObjectFactory()); $this->argumentsResolver = new ArgumentResolver(null, [$requestObjectResolver]); } public function testUnsupportedArgumentResolve(): void { - $controller = function (\stdClass $someArgument) {}; + $controller = function (\stdClass $someArgument) { + }; $this->expectException(\RuntimeException::class); - $this->argumentsResolver->getArguments($this->request, $controller); + $this->argumentsResolver->getArguments(new Request(), $controller); } public function testInvalidRequestResolve(): void { - $controller = function (SomeDto $someArgument) {}; + $controller = function (SomeDto $someArgument) { + }; $this->expectException(BadRequestHttpException::class); $this->expectExceptionMessage("Invalid request is passed"); $this->expectExceptionCode(ObjectInitError::CODE_GENERAL_INIT_ERROR); - $this->argumentsResolver->getArguments($this->request, $controller); + $this->argumentsResolver->getArguments(new Request(), $controller); + } + + /** + * @param array $data + * @param Request $request + * + * @dataProvider requestProvider + */ + public function testArgumentResolve(array $data, Request $request): void + { + $controller = function (SomeDto $someArgument) { + }; + + $arguments = $this->argumentsResolver->getArguments($request, $controller); + self::assertCount(1, $arguments); + + /** @var SomeDto $resolved */ + $resolved = $arguments[0]; + self::assertInstanceOf(SomeDto::class, $resolved); + self::assertEquals(new SomeDto($data), $resolved); + + self::assertEquals($data['someProperty'], $resolved->someProperty); + self::assertEquals($data['someEmbeddedProperty']['property1'], $resolved->someEmbeddedProperty->property1); + self::assertEquals($data['someEmbeddedProperty']['property2'], $resolved->someEmbeddedProperty->property2); + self::assertContainsOnlyInstancesOf(CollectionItemDto::class, $resolved->collectionItems); + self::assertCount(2, $resolved->collectionItems); + self::assertEquals($data['collectionItems'][0]['name'], $resolved->collectionItems[0]->name); + self::assertSame($data['collectionItems'][0]['order'], $resolved->collectionItems[0]->order); + self::assertEquals($data['collectionItems'][1]['name'], $resolved->collectionItems[1]->name); + self::assertSame($data['collectionItems'][1]['order'], $resolved->collectionItems[1]->order); } - public function testArgumentResolve(): void + public function requestProvider(): iterable { $data = [ - 'someProperty' => 'some value', + 'someProperty' => 'some value', 'someEmbeddedProperty' => [ 'property1' => 123, - 'property2' => 'sub value property 2' + 'property2' => 'sub value property 2', ], - 'collectionItems' => [ + 'collectionItems' => [ [ - 'name' => 'some name', - 'order' => 321.00, - ] + 'name' => 'some name', + 'order' => 321.09, + ], + [ + 'name' => 'Another name', + 'order' => -123.45, + ], ], ]; - $controller = function (SomeDto $someArgument) {}; - $this->request->request->add($data); + $request = new Request(); + $request->setMethod('GET'); + $request->query->add($data); + + yield [$data, $request]; + + $request = new Request(); + $request->setMethod('POST'); + $request->request->add($data); + + yield [$data, $request]; + + $request = new Request(); + $request->setMethod('PUT'); + $request->request->add($data); + + yield [$data, $request]; - $arguments = $this->argumentsResolver->getArguments($this->request, $controller); - $this->assertCount(1, $arguments); + $request = new Request(); + $request->setMethod('DELETE'); + $request->request->add($data); - $this->assertEquals(new SomeDto($data), $arguments[0]); + yield [$data, $request]; } }