From 578097cacaab41b5a6aaefa22356e0db4dacccb8 Mon Sep 17 00:00:00 2001 From: Jacob Dreesen Date: Sat, 21 Jan 2023 14:44:41 +0100 Subject: [PATCH 1/7] Add GenericTargetFactory and related configuration --- docs/usage.md | 55 ++++++++++--------- src/DependencyInjection/Configuration.php | 9 ++- .../NeustaConverterExtension.php | 10 +++- src/TargetFactory/GenericTargetFactory.php | 43 +++++++++++++++ .../NeustaConverterExtensionTest.php | 25 +++++++++ 5 files changed, 112 insertions(+), 30 deletions(-) create mode 100644 src/TargetFactory/GenericTargetFactory.php diff --git a/docs/usage.md b/docs/usage.md index d15d4f6..aa629f1 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -1,7 +1,6 @@ ## Usage -After the bundle is activated, you can directly use it by implementing a factory and a populator for your target and -source types. +After the bundle is activated, you can directly use it by implementing populators for your target and source types. Imagine your source type is `User`: @@ -41,31 +40,6 @@ Separation of Concerns. You should use the Converter-and-Populator-pattern. But how?! -Implement the following three artifacts: - -### Factory - -Implement a comfortable factory for your target type: - -```php -use Neusta\ConverterBundle\Converter\Context\GenericContext; -use Neusta\ConverterBundle\TargetFactory; - -/** - * @implements TargetFactory - */ -class PersonFactory implements TargetFactory -{ - public function create(?object $ctx = null): Person - { - return new Person(); - } -} -``` - -Skip thinking about the converter context at the moment. It will help you... -maybe not now but in a few weeks. You will see. - ### Populators Implement one or several populators: @@ -91,8 +65,32 @@ As you can see, implementation here is quite simple - just concatenation of two But however transformation will become more and more complex, it should be done in a testable, separated Populator or in several of them. +Skip thinking about the converter context at the moment. It will help you... +maybe not now but in a few weeks. You will see. + ### Configuration +First register the populator as a service: + +```yaml +# config/services.yaml +services: + YourNamespace\PersonNamePopulator: ~ +``` + +Then declare the following converter in your package config: + +```yaml +# config/packages/neusta_converter.yaml +neusta_converter: + converter: + person.converter: + target: YourNamespace\Person + populators: + - YourNamespace\PersonNamePopulator + # additional populators may follow +``` + To put things together, register the factory and populator as services: ```yaml @@ -118,6 +116,9 @@ neusta_converter: > Note: You can use a custom implementation of the `Converter` interface via the `converter` keyword. > Its constructor must contain the two parameters `TargetFactory $factory` and `array $populators`. +> Note: You can use a custom implementation of the `TargetTypeFactory` interface via the `target_factory` keyword, +> if you have special needs when creating the target object. + #### Mapping properties If you just want to map a single property from the source to the target without transforming it in between, you don't diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 974a4bb..ba0750b 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -40,10 +40,11 @@ private function addConverterSection(ArrayNodeDefinition $rootNode): void ->info('Class name of the "Converter" implementation') ->defaultValue(GenericConverter::class) ->end() + ->scalarNode('target') + ->info('Class name of the target') + ->end() ->scalarNode('target_factory') ->info('Service id of the "TargetFactory"') - ->isRequired() - ->cannotBeEmpty() ->end() ->arrayNode('populators') ->info('Service ids of the "Populator"s') @@ -82,6 +83,10 @@ private function addConverterSection(ArrayNodeDefinition $rootNode): void ->prototype('scalar')->end() ->end() ->end() + ->validate() + ->ifTrue(fn (array $c) => !isset($c['target']) && !isset($c['target_factory'])) + ->thenInvalid('Either "target" or "target_factory" must be defined.') + ->end() ->validate() ->ifTrue(fn (array $c) => empty($c['populators']) && empty($c['properties']) && empty($c['context'])) ->thenInvalid('At least one "populator", "property" or "context" must be defined.') diff --git a/src/DependencyInjection/NeustaConverterExtension.php b/src/DependencyInjection/NeustaConverterExtension.php index 28947df..d34ab69 100644 --- a/src/DependencyInjection/NeustaConverterExtension.php +++ b/src/DependencyInjection/NeustaConverterExtension.php @@ -9,6 +9,7 @@ use Neusta\ConverterBundle\Populator\ContextMappingPopulator; use Neusta\ConverterBundle\Populator\ConvertingPopulator; use Neusta\ConverterBundle\Populator\PropertyMappingPopulator; +use Neusta\ConverterBundle\TargetFactory\GenericTargetFactory; use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -41,6 +42,13 @@ public function loadInternal(array $mergedConfig, ContainerBuilder $container): */ private function registerConverterConfiguration(string $id, array $config, ContainerBuilder $container): void { + if (!$targetFactoryId = $config['target_factory'] ?? null) { + $container->register($targetFactoryId = "{$id}.target_factory", GenericTargetFactory::class) + ->setArguments([ + '$type' => new Reference($config['target']), + ]); + } + foreach ($config['properties'] ?? [] as $targetProperty => $sourceConfig) { $skipNull = false; if (str_ends_with($targetProperty, '?')) { @@ -74,7 +82,7 @@ private function registerConverterConfiguration(string $id, array $config, Conta $container->register($id, $config['converter']) ->setPublic(true) ->setArguments([ - '$factory' => new Reference($config['target_factory']), + '$factory' => new Reference($targetFactoryId), '$populators' => array_map( static fn (string $populator) => new Reference($populator), $config['populators'], diff --git a/src/TargetFactory/GenericTargetFactory.php b/src/TargetFactory/GenericTargetFactory.php new file mode 100644 index 0000000..4b3638d --- /dev/null +++ b/src/TargetFactory/GenericTargetFactory.php @@ -0,0 +1,43 @@ + + */ +final class GenericTargetFactory implements TargetFactory +{ + /** @var \ReflectionClass */ + private \ReflectionClass $type; + + /** + * @param class-string $type + */ + public function __construct(string $type) + { + $this->type = new \ReflectionClass($type); + + if (!$this->type->isInstantiable()) { + throw new \InvalidArgumentException(sprintf('Target class "%s" is not instantiable.', $type)); + } + + if ($this->type->getConstructor()?->getNumberOfRequiredParameters()) { + throw new \InvalidArgumentException(sprintf('Target class "%s" has required constructor parameters.', $type)); + } + } + + public function create(?object $ctx = null): object + { + try { + return $this->type->newInstance(); + } catch (\ReflectionException $e) { + throw new \LogicException(sprintf('Cannot create new instance of "%s" because: %s', $this->type->getName(), $e->getMessage()), 0, $e); + } + } +} diff --git a/tests/DependencyInjection/NeustaConverterExtensionTest.php b/tests/DependencyInjection/NeustaConverterExtensionTest.php index fdf833a..1842720 100644 --- a/tests/DependencyInjection/NeustaConverterExtensionTest.php +++ b/tests/DependencyInjection/NeustaConverterExtensionTest.php @@ -12,7 +12,9 @@ use Neusta\ConverterBundle\Populator\ContextMappingPopulator; use Neusta\ConverterBundle\Populator\ConvertingPopulator; use Neusta\ConverterBundle\Populator\PropertyMappingPopulator; +use Neusta\ConverterBundle\TargetFactory\GenericTargetFactory; use Neusta\ConverterBundle\Tests\Fixtures\Model\Target\Factory\PersonFactory; +use Neusta\ConverterBundle\Tests\Fixtures\Model\Person; use Neusta\ConverterBundle\Tests\Fixtures\Populator\PersonNamePopulator; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\TypedReference; @@ -45,6 +47,29 @@ public function test_with_generic_converter(): void $this->assertContainerBuilderHasServiceDefinitionWithArgument('foobar', '$populators', [new Reference(PersonNamePopulator::class)]); } + public function test_with_generic_target_factory(): void + { + $container = $this->buildContainer([ + 'converter' => [ + 'foobar' => [ + 'target' => Person::class, + 'populators' => [ + PersonNamePopulator::class, + ], + ], + ], + ]); + + // converter + $converter = $container->getDefinition('foobar'); + self::assertIsReference('foobar.target_factory', $converter->getArgument('$factory')); + + // target type factory + $factory = $container->getDefinition('foobar.target_factory'); + self::assertSame(GenericTargetFactory::class, $factory->getClass()); + self::assertIsReference(Person::class, $factory->getArgument('$type')); + } + public function test_with_mapped_properties(): void { $this->load([ From 45dbc1643a68879937d09c0e4a9d9973fda4cde0 Mon Sep 17 00:00:00 2001 From: Jacob Dreesen Date: Wed, 1 Feb 2023 23:55:27 +0100 Subject: [PATCH 2/7] Move GenericTargetFactory from TargetFactory to Target namespace --- src/DependencyInjection/NeustaConverterExtension.php | 2 +- src/{TargetFactory => Target}/GenericTargetFactory.php | 2 +- tests/DependencyInjection/NeustaConverterExtensionTest.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename src/{TargetFactory => Target}/GenericTargetFactory.php (96%) diff --git a/src/DependencyInjection/NeustaConverterExtension.php b/src/DependencyInjection/NeustaConverterExtension.php index d34ab69..1a6f1c8 100644 --- a/src/DependencyInjection/NeustaConverterExtension.php +++ b/src/DependencyInjection/NeustaConverterExtension.php @@ -9,7 +9,7 @@ use Neusta\ConverterBundle\Populator\ContextMappingPopulator; use Neusta\ConverterBundle\Populator\ConvertingPopulator; use Neusta\ConverterBundle\Populator\PropertyMappingPopulator; -use Neusta\ConverterBundle\TargetFactory\GenericTargetFactory; +use Neusta\ConverterBundle\Target\GenericTargetFactory; use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\ContainerBuilder; diff --git a/src/TargetFactory/GenericTargetFactory.php b/src/Target/GenericTargetFactory.php similarity index 96% rename from src/TargetFactory/GenericTargetFactory.php rename to src/Target/GenericTargetFactory.php index 4b3638d..01dfe82 100644 --- a/src/TargetFactory/GenericTargetFactory.php +++ b/src/Target/GenericTargetFactory.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Neusta\ConverterBundle\TargetFactory; +namespace Neusta\ConverterBundle\Target; use Neusta\ConverterBundle\TargetFactory; diff --git a/tests/DependencyInjection/NeustaConverterExtensionTest.php b/tests/DependencyInjection/NeustaConverterExtensionTest.php index 1842720..5614114 100644 --- a/tests/DependencyInjection/NeustaConverterExtensionTest.php +++ b/tests/DependencyInjection/NeustaConverterExtensionTest.php @@ -12,7 +12,7 @@ use Neusta\ConverterBundle\Populator\ContextMappingPopulator; use Neusta\ConverterBundle\Populator\ConvertingPopulator; use Neusta\ConverterBundle\Populator\PropertyMappingPopulator; -use Neusta\ConverterBundle\TargetFactory\GenericTargetFactory; +use Neusta\ConverterBundle\Target\GenericTargetFactory; use Neusta\ConverterBundle\Tests\Fixtures\Model\Target\Factory\PersonFactory; use Neusta\ConverterBundle\Tests\Fixtures\Model\Person; use Neusta\ConverterBundle\Tests\Fixtures\Populator\PersonNamePopulator; From 5c57f2bc5c52125fec1fc7d8e3f7ba1332f7b113 Mon Sep 17 00:00:00 2001 From: Michael Albrecht Date: Sat, 4 Feb 2023 16:23:32 +0100 Subject: [PATCH 3/7] Update src/DependencyInjection/NeustaConverterExtension.php I like that much more... Co-authored-by: Jacob Dreesen --- src/DependencyInjection/NeustaConverterExtension.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/DependencyInjection/NeustaConverterExtension.php b/src/DependencyInjection/NeustaConverterExtension.php index 1a6f1c8..19c04c4 100644 --- a/src/DependencyInjection/NeustaConverterExtension.php +++ b/src/DependencyInjection/NeustaConverterExtension.php @@ -42,8 +42,10 @@ public function loadInternal(array $mergedConfig, ContainerBuilder $container): */ private function registerConverterConfiguration(string $id, array $config, ContainerBuilder $container): void { - if (!$targetFactoryId = $config['target_factory'] ?? null) { - $container->register($targetFactoryId = "{$id}.target_factory", GenericTargetFactory::class) + $targetFactoryId = $config['target_factory'] ?? "{$id}.target_factory"; + + if (!isset($config['target_factory'])) { + $container->register($targetFactoryId, GenericTargetFactory::class) ->setArguments([ '$type' => new Reference($config['target']), ]); From e0312346ffa03295a650a665e6578b25e5ac58a7 Mon Sep 17 00:00:00 2001 From: Michael Albrecht Date: Thu, 18 Apr 2024 13:19:21 +0200 Subject: [PATCH 4/7] #33 fix test for NeustaConverterExtension --- .../NeustaConverterExtensionTest.php | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/tests/DependencyInjection/NeustaConverterExtensionTest.php b/tests/DependencyInjection/NeustaConverterExtensionTest.php index 5614114..6040acc 100644 --- a/tests/DependencyInjection/NeustaConverterExtensionTest.php +++ b/tests/DependencyInjection/NeustaConverterExtensionTest.php @@ -14,7 +14,7 @@ use Neusta\ConverterBundle\Populator\PropertyMappingPopulator; use Neusta\ConverterBundle\Target\GenericTargetFactory; use Neusta\ConverterBundle\Tests\Fixtures\Model\Target\Factory\PersonFactory; -use Neusta\ConverterBundle\Tests\Fixtures\Model\Person; +use Neusta\ConverterBundle\Tests\Fixtures\Model\Target\Person; use Neusta\ConverterBundle\Tests\Fixtures\Populator\PersonNamePopulator; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\TypedReference; @@ -49,7 +49,7 @@ public function test_with_generic_converter(): void public function test_with_generic_target_factory(): void { - $container = $this->buildContainer([ + $this->load([ 'converter' => [ 'foobar' => [ 'target' => Person::class, @@ -61,13 +61,9 @@ public function test_with_generic_target_factory(): void ]); // converter - $converter = $container->getDefinition('foobar'); - self::assertIsReference('foobar.target_factory', $converter->getArgument('$factory')); - - // target type factory - $factory = $container->getDefinition('foobar.target_factory'); - self::assertSame(GenericTargetFactory::class, $factory->getClass()); - self::assertIsReference(Person::class, $factory->getArgument('$type')); + $this->assertContainerBuilderHasPublicService('foobar', GenericConverter::class); + $this->assertContainerBuilderHasService('foobar.target_factory', GenericTargetFactory::class); + $this->assertContainerBuilderHasServiceDefinitionWithArgument('foobar', '$factory', new Reference('foobar.target_factory')); } public function test_with_mapped_properties(): void From ad4fbb465dba9155463f0d28bd61121509e487bf Mon Sep 17 00:00:00 2001 From: Michael Albrecht Date: Thu, 18 Apr 2024 13:47:06 +0200 Subject: [PATCH 5/7] #33 add exceptional test case for NeustaConverterExtension and test case for Converter with target option --- .../NeustaConverterExtension.php | 5 ++++- .../NeustaConverterExtensionTest.php | 18 ++++++++++++++++++ tests/Fixtures/Config/person.yaml | 3 +-- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/DependencyInjection/NeustaConverterExtension.php b/src/DependencyInjection/NeustaConverterExtension.php index 19c04c4..5c461ef 100644 --- a/src/DependencyInjection/NeustaConverterExtension.php +++ b/src/DependencyInjection/NeustaConverterExtension.php @@ -45,9 +45,12 @@ private function registerConverterConfiguration(string $id, array $config, Conta $targetFactoryId = $config['target_factory'] ?? "{$id}.target_factory"; if (!isset($config['target_factory'])) { + if (!class_exists($config['target'])) { + throw new InvalidConfigurationException(sprintf('Target type (class) %s does not exist.', $config['target'])); + } $container->register($targetFactoryId, GenericTargetFactory::class) ->setArguments([ - '$type' => new Reference($config['target']), + '$type' => $config['target'], ]); } diff --git a/tests/DependencyInjection/NeustaConverterExtensionTest.php b/tests/DependencyInjection/NeustaConverterExtensionTest.php index 6040acc..de7e8e1 100644 --- a/tests/DependencyInjection/NeustaConverterExtensionTest.php +++ b/tests/DependencyInjection/NeustaConverterExtensionTest.php @@ -16,6 +16,7 @@ use Neusta\ConverterBundle\Tests\Fixtures\Model\Target\Factory\PersonFactory; use Neusta\ConverterBundle\Tests\Fixtures\Model\Target\Person; use Neusta\ConverterBundle\Tests\Fixtures\Populator\PersonNamePopulator; +use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\TypedReference; @@ -66,6 +67,23 @@ public function test_with_generic_target_factory(): void $this->assertContainerBuilderHasServiceDefinitionWithArgument('foobar', '$factory', new Reference('foobar.target_factory')); } + public function test_with_generic_target_factory_exceptional_case(): void + { + $this->expectException(InvalidConfigurationException::class); + $this->expectExceptionMessage('Target type (class) UnknownClass does not exist.'); + + $this->load([ + 'converter' => [ + 'foobar' => [ + 'target' => 'UnknownClass', + 'populators' => [ + PersonNamePopulator::class, + ], + ], + ], + ]); + } + public function test_with_mapped_properties(): void { $this->load([ diff --git a/tests/Fixtures/Config/person.yaml b/tests/Fixtures/Config/person.yaml index 0001c21..0e16f4c 100644 --- a/tests/Fixtures/Config/person.yaml +++ b/tests/Fixtures/Config/person.yaml @@ -1,8 +1,7 @@ neusta_converter: converter: test.person.converter: - converter: Neusta\ConverterBundle\Converter\GenericConverter - target_factory: Neusta\ConverterBundle\Tests\Fixtures\Model\Target\Factory\PersonFactory + target: Neusta\ConverterBundle\Tests\Fixtures\Model\Target\Person context: group: ~ # same property name locale: language # different property names From f352d35ecfd33a572024b557a8b15bd793a9d77d Mon Sep 17 00:00:00 2001 From: Michael Albrecht Date: Thu, 18 Apr 2024 13:52:31 +0200 Subject: [PATCH 6/7] #33 update documentation for usage --- docs/usage.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/docs/usage.md b/docs/usage.md index aa629f1..3aeaf07 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -91,12 +91,11 @@ neusta_converter: # additional populators may follow ``` -To put things together, register the factory and populator as services: +To put things together, register the populator as services: ```yaml # config/services.yaml services: - YourNamespace\PersonFactory: ~ YourNamespace\PersonNamePopulator: ~ ``` @@ -107,7 +106,7 @@ And then declare the following converter in your package config: neusta_converter: converter: person.converter: - target_factory: YourNamespace\PersonFactory + target: YourNamespace\Person populators: - YourNamespace\PersonNamePopulator # additional populators may follow @@ -132,7 +131,7 @@ You can use it in your converter config via the `properties` keyword: neusta_converter: converter: person.converter: - # ... + target: YourNamespace\Person properties: email: ~ phoneNumber: phone @@ -160,7 +159,7 @@ neusta_converter: converter: person.converter: properties: - # ... + target: YourNamespace\Person phoneNumber: source: phone default: '0123456789' @@ -182,7 +181,7 @@ You can use it in your converter config via the `context` keyword: neusta_converter: converter: person.converter: - # ... + target: YourNamespace\Person context: group: ~ locale: language From 5c9ca5b1b39284e1b15eef8307ee955f869073e4 Mon Sep 17 00:00:00 2001 From: Jacob Dreesen Date: Tue, 7 May 2024 16:06:21 +0200 Subject: [PATCH 7/7] Some cleanup and enhancements --- src/DependencyInjection/Configuration.php | 8 ++++ .../NeustaConverterExtension.php | 8 +--- src/Target/GenericTargetFactory.php | 8 +++- .../NeustaConverterExtensionTest.php | 39 ++++++++++++++++++- tests/Fixtures/Config/person.yaml | 1 + 5 files changed, 54 insertions(+), 10 deletions(-) diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index ba0750b..8e657d4 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -42,6 +42,10 @@ private function addConverterSection(ArrayNodeDefinition $rootNode): void ->end() ->scalarNode('target') ->info('Class name of the target') + ->validate() + ->ifTrue(fn ($v) => !class_exists($v)) + ->thenInvalid('The target type %s does not exist.') + ->end() ->end() ->scalarNode('target_factory') ->info('Service id of the "TargetFactory"') @@ -87,6 +91,10 @@ private function addConverterSection(ArrayNodeDefinition $rootNode): void ->ifTrue(fn (array $c) => !isset($c['target']) && !isset($c['target_factory'])) ->thenInvalid('Either "target" or "target_factory" must be defined.') ->end() + ->validate() + ->ifTrue(fn (array $c) => isset($c['target'], $c['target_factory'])) + ->thenInvalid('Either "target" or "target_factory" must be defined, but not both.') + ->end() ->validate() ->ifTrue(fn (array $c) => empty($c['populators']) && empty($c['properties']) && empty($c['context'])) ->thenInvalid('At least one "populator", "property" or "context" must be defined.') diff --git a/src/DependencyInjection/NeustaConverterExtension.php b/src/DependencyInjection/NeustaConverterExtension.php index 5c461ef..767ebf6 100644 --- a/src/DependencyInjection/NeustaConverterExtension.php +++ b/src/DependencyInjection/NeustaConverterExtension.php @@ -43,15 +43,9 @@ public function loadInternal(array $mergedConfig, ContainerBuilder $container): private function registerConverterConfiguration(string $id, array $config, ContainerBuilder $container): void { $targetFactoryId = $config['target_factory'] ?? "{$id}.target_factory"; - if (!isset($config['target_factory'])) { - if (!class_exists($config['target'])) { - throw new InvalidConfigurationException(sprintf('Target type (class) %s does not exist.', $config['target'])); - } $container->register($targetFactoryId, GenericTargetFactory::class) - ->setArguments([ - '$type' => $config['target'], - ]); + ->setArgument('$type', $config['target']); } foreach ($config['properties'] ?? [] as $targetProperty => $sourceConfig) { diff --git a/src/Target/GenericTargetFactory.php b/src/Target/GenericTargetFactory.php index 01dfe82..ea0d5bb 100644 --- a/src/Target/GenericTargetFactory.php +++ b/src/Target/GenericTargetFactory.php @@ -9,7 +9,7 @@ /** * @template T of object * - * @implements TargetFactory + * @implements TargetFactory */ final class GenericTargetFactory implements TargetFactory { @@ -18,6 +18,9 @@ final class GenericTargetFactory implements TargetFactory /** * @param class-string $type + * + * @throws \ReflectionException + * @throws \InvalidArgumentException */ public function __construct(string $type) { @@ -32,6 +35,9 @@ public function __construct(string $type) } } + /** + * @throws \LogicException + */ public function create(?object $ctx = null): object { try { diff --git a/tests/DependencyInjection/NeustaConverterExtensionTest.php b/tests/DependencyInjection/NeustaConverterExtensionTest.php index de7e8e1..ff6c25b 100644 --- a/tests/DependencyInjection/NeustaConverterExtensionTest.php +++ b/tests/DependencyInjection/NeustaConverterExtensionTest.php @@ -65,12 +65,13 @@ public function test_with_generic_target_factory(): void $this->assertContainerBuilderHasPublicService('foobar', GenericConverter::class); $this->assertContainerBuilderHasService('foobar.target_factory', GenericTargetFactory::class); $this->assertContainerBuilderHasServiceDefinitionWithArgument('foobar', '$factory', new Reference('foobar.target_factory')); + $this->assertContainerBuilderHasServiceDefinitionWithArgument('foobar.target_factory', '$type', Person::class); } - public function test_with_generic_target_factory_exceptional_case(): void + public function test_with_generic_target_factory_for_unknown_type(): void { $this->expectException(InvalidConfigurationException::class); - $this->expectExceptionMessage('Target type (class) UnknownClass does not exist.'); + $this->expectExceptionMessage('The target type "UnknownClass" does not exist.'); $this->load([ 'converter' => [ @@ -84,6 +85,40 @@ public function test_with_generic_target_factory_exceptional_case(): void ]); } + public function test_without_target_and_target_factory(): void + { + $this->expectException(InvalidConfigurationException::class); + $this->expectExceptionMessage('Either "target" or "target_factory" must be defined.'); + + $this->load([ + 'converter' => [ + 'foobar' => [ + 'populators' => [ + PersonNamePopulator::class, + ], + ], + ], + ]); + } + + public function test_with_target_and_target_factory(): void + { + $this->expectException(InvalidConfigurationException::class); + $this->expectExceptionMessage('Either "target" or "target_factory" must be defined, but not both.'); + + $this->load([ + 'converter' => [ + 'foobar' => [ + 'target' => Person::class, + 'target_factory' => PersonFactory::class, + 'populators' => [ + PersonNamePopulator::class, + ], + ], + ], + ]); + } + public function test_with_mapped_properties(): void { $this->load([ diff --git a/tests/Fixtures/Config/person.yaml b/tests/Fixtures/Config/person.yaml index 0e16f4c..6a2de89 100644 --- a/tests/Fixtures/Config/person.yaml +++ b/tests/Fixtures/Config/person.yaml @@ -9,6 +9,7 @@ neusta_converter: - Neusta\ConverterBundle\Tests\Fixtures\Populator\PersonNamePopulator test.person.converter.extended: + converter: Neusta\ConverterBundle\Converter\GenericConverter target_factory: Neusta\ConverterBundle\Tests\Fixtures\Model\Target\Factory\PersonWithDefaultsFactory properties: fullName: