Skip to content

Commit

Permalink
Redefine (array) converting populator configuration (#56)
Browse files Browse the repository at this point in the history
  • Loading branch information
jdreesen authored Dec 5, 2023
1 parent 0c597ab commit 5fd6983
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 26 deletions.
33 changes: 26 additions & 7 deletions src/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Neusta\ConverterBundle\DependencyInjection;

use Neusta\ConverterBundle\Converter\GenericConverter;
use Neusta\ConverterBundle\Populator\ArrayConvertingPopulator;
use Neusta\ConverterBundle\Populator\ConvertingPopulator;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
Expand Down Expand Up @@ -98,8 +99,9 @@ private function addPopulatorSection(ArrayNodeDefinition $rootNode): void
->useAttributeAsKey('name')
->arrayPrototype()
->children()
->scalarNode('populator')
->enumNode('populator')
->info('class of the "Populator" implementation')
->values([ConvertingPopulator::class, ArrayConvertingPopulator::class])
->defaultValue(ConvertingPopulator::class)
->end()
->scalarNode('converter')
Expand All @@ -108,16 +110,33 @@ private function addPopulatorSection(ArrayNodeDefinition $rootNode): void
->cannotBeEmpty()
->end()
->arrayNode('property')
->info('Mapping of source property (value) to target property (key)')
->info('Mapping of source property to target property')
->normalizeKeys(false)
->useAttributeAsKey('target')
->prototype('scalar')
->arrayPrototype()
->beforeNormalization()
->ifNull()
->then(fn () => ['source' => null, 'source_array_item' => null])
->end()
->beforeNormalization()
->ifString()
->then(fn (string $v) => ['source' => $v, 'source_array_item' => null])
->end()
->children()
->scalarNode('source')
->defaultValue(null)
->end()
->scalarNode('source_array_item')
->defaultValue(null)
->end()
->end()
->end()
->end()
->end()
->end()
->validate()
->ifTrue(fn (array $c) => empty($c['property']))
->thenInvalid('At least one "property" must be defined.')
->validate()
->ifTrue(fn (array $c) => ArrayConvertingPopulator::class !== $c['populator'] && !empty($c['property'][array_key_first($c['property'])]['source_array_item']))
->thenInvalid('The "property.<target>.source_array_item" option is only supported for array converting populators.')
->end()
->end()
->end()
->end()
Expand Down
14 changes: 6 additions & 8 deletions src/DependencyInjection/NeustaConverterExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Neusta\ConverterBundle\Populator\ContextMappingPopulator;
use Neusta\ConverterBundle\Populator\ConvertingPopulator;
use Neusta\ConverterBundle\Populator\PropertyMappingPopulator;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
Expand Down Expand Up @@ -80,29 +81,26 @@ private function registerConverterConfiguration(string $id, array $config, Conta
*/
private function registerPopulatorConfiguration(string $id, array $config, ContainerBuilder $container): void
{
$itemProperty = $config['property']['itemProperty'] ?? null;
unset($config['property']['itemProperty']);

$targetProperty = array_key_first($config['property']);
$sourceProperty = $config['property'][$targetProperty] ?? $targetProperty;
$sourceProperty = $config['property'][$targetProperty];

$container->register($id, $config['populator'])
->setPublic(true)
->setArguments(match ($config['populator']) {
ConvertingPopulator::class => [
'$converter' => new TypedReference($config['converter'], Converter::class),
'$sourcePropertyName' => $sourceProperty,
'$targetPropertyName' => $targetProperty,
'$sourcePropertyName' => $sourceProperty['source'] ?? $targetProperty,
'$accessor' => new Reference('property_accessor'),
],
ArrayConvertingPopulator::class => [
'$converter' => new TypedReference($config['converter'], Converter::class),
'$sourceArrayPropertyName' => $sourceProperty,
'$targetPropertyName' => $targetProperty,
'$sourceArrayItemPropertyName' => $itemProperty,
'$sourceArrayPropertyName' => $sourceProperty['source'] ?? $targetProperty,
'$sourceArrayItemPropertyName' => $sourceProperty['source_array_item'] ?? null,
'$accessor' => new Reference('property_accessor'),
],
default => [],
default => throw new InvalidConfigurationException(sprintf('The populator "%s" is not supported.', $config['populator'])),
});
}

Expand Down
94 changes: 84 additions & 10 deletions tests/DependencyInjection/NeustaConverterExtensionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,48 @@ public function test_with_converting_populator(): void
self::assertSame('sourceTest', $populator->getArgument('$sourcePropertyName'));
}

public function test_with_converting_populator_without_source_property_config(): void
{
$container = $this->buildContainer([
'populator' => [
'foobar' => [
'converter' => GenericConverter::class,
'property' => [
'test' => null,
],
],
],
]);

// converter
$populator = $container->getDefinition('foobar');

self::assertSame(ConvertingPopulator::class, $populator->getClass());
self::assertTrue($populator->isPublic());
self::assertInstanceOf(TypedReference::class, $populator->getArgument('$converter'));
self::assertSame(GenericConverter::class, (string) $populator->getArgument('$converter'));
self::assertSame('test', $populator->getArgument('$targetPropertyName'));
self::assertSame('test', $populator->getArgument('$sourcePropertyName'));
}

public function test_with_converting_populator_with_array_converting_populator_config(): void
{
$this->expectExceptionMessage('The "property.<target>.source_array_item" option is only supported for array converting populators.');

$this->buildContainer([
'populator' => [
'foobar' => [
'converter' => GenericConverter::class,
'property' => [
'test' => [
'source_array_item' => 'value',
],
],
],
],
]);
}

public function test_with_array_converting_populator(): void
{
$container = $this->buildContainer([
Expand All @@ -185,6 +227,31 @@ public function test_with_array_converting_populator(): void
self::assertSame('sourceTest', $populator->getArgument('$sourceArrayPropertyName'));
}

public function test_with_array_converting_populator_without_source_property_config(): void
{
$container = $this->buildContainer([
'populator' => [
'foobar' => [
'populator' => ArrayConvertingPopulator::class,
'converter' => GenericConverter::class,
'property' => [
'test' => null,
],
],
],
]);

// converter
$populator = $container->getDefinition('foobar');

self::assertSame(ArrayConvertingPopulator::class, $populator->getClass());
self::assertTrue($populator->isPublic());
self::assertInstanceOf(TypedReference::class, $populator->getArgument('$converter'));
self::assertSame(GenericConverter::class, (string) $populator->getArgument('$converter'));
self::assertSame('test', $populator->getArgument('$targetPropertyName'));
self::assertSame('test', $populator->getArgument('$sourceArrayPropertyName'));
}

public function test_with_array_converting_populator_with_inner_property(): void
{
$container = $this->buildContainer([
Expand All @@ -193,8 +260,10 @@ public function test_with_array_converting_populator_with_inner_property(): void
'populator' => ArrayConvertingPopulator::class,
'converter' => GenericConverter::class,
'property' => [
'targetTest' => 'sourceTest',
'itemProperty' => 'value',
'targetTest' => [
'source' => 'sourceTest',
'source_array_item' => 'value',
],
],
],
],
Expand All @@ -204,19 +273,23 @@ public function test_with_array_converting_populator_with_inner_property(): void
$populator = $container->getDefinition('foobar');

self::assertSame(ArrayConvertingPopulator::class, $populator->getClass());
self::assertSame('targetTest', $populator->getArgument('$targetPropertyName'));
self::assertSame('sourceTest', $populator->getArgument('$sourceArrayPropertyName'));
self::assertSame('value', $populator->getArgument('$sourceArrayItemPropertyName'));
}

public function test_with_array_converting_populator_with_inner_property_same_name(): void
public function test_with_array_converting_populator_with_inner_property_and_empty_source(): void
{
$container = $this->buildContainer([
'populator' => [
'foobar' => [
'populator' => ArrayConvertingPopulator::class,
'converter' => GenericConverter::class,
'property' => [
'test' => null, // in yaml one will write ~
'itemProperty' => 'value',
'test' => [
'source' => null,
'source_array_item' => 'value',
],
],
],
],
Expand All @@ -231,16 +304,17 @@ public function test_with_array_converting_populator_with_inner_property_same_na
self::assertSame('value', $populator->getArgument('$sourceArrayItemPropertyName'));
}

public function test_with_array_converting_populator_with_inner_property_first(): void
public function test_with_array_converting_populator_with_inner_property_and_missing_source_property_config(): void
{
$container = $this->buildContainer([
'populator' => [
'foobar' => [
'populator' => ArrayConvertingPopulator::class,
'converter' => GenericConverter::class,
'property' => [
'itemProperty' => 'value',
'targetTest' => 'sourceTest',
'test' => [
'source_array_item' => 'value',
],
],
],
],
Expand All @@ -250,8 +324,8 @@ public function test_with_array_converting_populator_with_inner_property_first()
$populator = $container->getDefinition('foobar');

self::assertSame(ArrayConvertingPopulator::class, $populator->getClass());
self::assertSame('targetTest', $populator->getArgument('$targetPropertyName'));
self::assertSame('sourceTest', $populator->getArgument('$sourceArrayPropertyName'));
self::assertSame('test', $populator->getArgument('$targetPropertyName'));
self::assertSame('test', $populator->getArgument('$sourceArrayPropertyName'));
self::assertSame('value', $populator->getArgument('$sourceArrayItemPropertyName'));
}

Expand Down
1 change: 0 additions & 1 deletion tests/app/config/packages/neusta_converter.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,3 @@ neusta_converter:
converter: test.address.converter
property:
address: ~

0 comments on commit 5fd6983

Please sign in to comment.