diff --git a/src/AutoMapperBundle.php b/src/AutoMapperBundle.php
index 173b3f7..aa4b1af 100644
--- a/src/AutoMapperBundle.php
+++ b/src/AutoMapperBundle.php
@@ -4,6 +4,7 @@
use AutoMapper\Bundle\DependencyInjection\Compiler\MapperConfigurationPass;
use AutoMapper\Bundle\DependencyInjection\Compiler\TransformerFactoryPass;
+use Jane\Bundle\AutoMapperBundle\DependencyInjection\Compiler\PropertyInfoPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;
@@ -14,6 +15,7 @@ public function build(ContainerBuilder $container)
parent::build($container);
$container->addCompilerPass(new MapperConfigurationPass());
+ $container->addCompilerPass(new PropertyInfoPass());
$container->addCompilerPass(new TransformerFactoryPass());
}
}
diff --git a/src/DependencyInjection/Compiler/PropertyInfoPass.php b/src/DependencyInjection/Compiler/PropertyInfoPass.php
new file mode 100644
index 0000000..f5f5046
--- /dev/null
+++ b/src/DependencyInjection/Compiler/PropertyInfoPass.php
@@ -0,0 +1,81 @@
+has('property_info')) {
+ return;
+ }
+
+ $propertyInfoDefinition = $container->findDefinition('property_info');
+
+ $container->setDefinition(
+ 'automapper.property_info.reflection_extractor.inner',
+ new Definition(
+ ReflectionExtractor::class,
+ [
+ '$accessFlags' => ReflectionExtractor::ALLOW_PUBLIC | ReflectionExtractor::ALLOW_PROTECTED | ReflectionExtractor::ALLOW_PRIVATE,
+ ]
+ )
+ );
+
+ $container->setDefinition(
+ 'automapper.property_info.reflection_extractor',
+ new Definition(
+ MapToContextPropertyInfoExtractorDecorator::class,
+ [
+ new Reference('automapper.property_info.reflection_extractor.inner'),
+ ]
+ )
+ );
+
+ $container->setDefinition(
+ 'automapper.property_info',
+ new Definition(
+ PropertyInfoExtractor::class,
+ [
+ $this->replaceReflectionExtractor($propertyInfoDefinition->getArgument(0)),
+ $this->replaceReflectionExtractor($propertyInfoDefinition->getArgument(1)),
+ $this->replaceReflectionExtractor($propertyInfoDefinition->getArgument(2)),
+ $this->replaceReflectionExtractor($propertyInfoDefinition->getArgument(3)),
+ $this->replaceReflectionExtractor($propertyInfoDefinition->getArgument(4)),
+ ]
+ )
+ );
+
+ $container->setDefinition(
+ 'automapper.property_info.cache',
+ new Definition(PropertyInfoCacheExtractor::class, [
+ new Reference('.inner'),
+ new Reference('cache.property_info'),
+ ])
+ )->setDecoratedService('automapper.property_info');
+ }
+
+ private function replaceReflectionExtractor(IteratorArgument $extractors): IteratorArgument
+ {
+ $newExtractors = [];
+
+ /** @var Reference $extractor */
+ foreach ($extractors->getValues() as $extractor) {
+ $newExtractors[] = (string) $extractor === 'property_info.reflection_extractor'
+ ? new Reference('automapper.property_info.reflection_extractor')
+ : $extractor;
+ }
+
+ return new IteratorArgument($newExtractors);
+ }
+}
diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php
index f6d1faa..f4cbb76 100644
--- a/src/DependencyInjection/Configuration.php
+++ b/src/DependencyInjection/Configuration.php
@@ -29,6 +29,7 @@ public function getConfigTreeBuilder(): TreeBuilder
->scalarNode('cache_dir')->defaultValue('%kernel.cache_dir%/automapper')->end()
->scalarNode('date_time_format')->defaultValue(\DateTimeInterface::RFC3339)->end()
->booleanNode('hot_reload')->defaultValue($this->debug)->end()
+ ->booleanNode('map_private_properties')->defaultTrue()->end()
->booleanNode('allow_readonly_target_to_populate')->defaultFalse()->end()
->arrayNode('warmup')
->arrayPrototype()
diff --git a/src/DependencyInjection/JaneAutoMapperExtension.php b/src/DependencyInjection/JaneAutoMapperExtension.php
index 09786e8..b597680 100644
--- a/src/DependencyInjection/JaneAutoMapperExtension.php
+++ b/src/DependencyInjection/JaneAutoMapperExtension.php
@@ -45,6 +45,11 @@ public function load(array $configs, ContainerBuilder $container)
$loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
$loader->load('services.xml');
+ $container->getDefinition(MapperGeneratorMetadataFactory::class)
+ ->replaceArgument(5, $config['date_time_format'])
+ ->replaceArgument(6, $config['map_private_properties'])
+ ;
+
$container->getDefinition(MapperGeneratorMetadataFactory::class)->replaceArgument(5, $config['date_time_format']);
$container->getDefinition(FileLoader::class)->replaceArgument(2, $config['hot_reload']);
$container->registerForAutoconfiguration(TransformerFactoryInterface::class)->addTag('jane_auto_mapper.transformer_factory');
diff --git a/src/Resources/config/services.xml b/src/Resources/config/services.xml
index 07eed81..936a6a4 100644
--- a/src/Resources/config/services.xml
+++ b/src/Resources/config/services.xml
@@ -119,10 +119,5 @@
-
-
diff --git a/tests/Fixtures/ClassWithMapToContextAttribute.php b/tests/Fixtures/ClassWithMapToContextAttribute.php
new file mode 100644
index 0000000..5befb29
--- /dev/null
+++ b/tests/Fixtures/ClassWithMapToContextAttribute.php
@@ -0,0 +1,33 @@
+value}_{$suffix}";
+ }
+
+ public function getVirtualProperty(
+ #[MapToContext('prefix')] string $prefix,
+ #[MapToContext('suffix')] string $suffix,
+ ): string {
+ return "{$prefix}_{$this->value}_{$suffix}";
+ }
+
+ public function getPropertyWithDefaultValue(
+ string $someVar = 'foo',
+ ): string {
+ return $someVar;
+ }
+}
diff --git a/tests/Fixtures/ClassWithPrivateProperty.php b/tests/Fixtures/ClassWithPrivateProperty.php
new file mode 100644
index 0000000..4ab1dea
--- /dev/null
+++ b/tests/Fixtures/ClassWithPrivateProperty.php
@@ -0,0 +1,15 @@
+enum = SomeEnum::FOO;
self::assertSame(['enum' => 'foo'], $autoMapper->map($dto, 'array'));
}
+
+ /**
+ * This test validates that PropertyInfoPass is correctly applied.
+ */
+ public function testMapClassWithPrivateProperty(): void
+ {
+ static::bootKernel();
+ $container = static::$kernel->getContainer();
+ $autoMapper = $container->get(AutoMapperInterface::class);
+
+ self::assertEquals(
+ new ClassWithPrivateProperty('bar'),
+ $autoMapper->map(['foo' => 'bar'], ClassWithPrivateProperty::class)
+ );
+ }
+
+ /**
+ * We need to test that the mapToContext attribute is correctly used,
+ * because this behavior is dependent of the dependency injection.
+ */
+ public function testMapToContextAttribute(): void
+ {
+ static::bootKernel();
+ $container = static::$kernel->getContainer();
+ $autoMapper = $container->get(AutoMapperInterface::class);
+
+ self::assertSame(
+ [
+ 'value' => 'foo_bar_baz',
+ 'virtualProperty' => 'foo_bar_baz',
+ 'propertyWithDefaultValue' => 'foo',
+ ],
+ $autoMapper->map(
+ new ClassWithMapToContextAttribute('bar'),
+ 'array',
+ [MapperContext::MAP_TO_ACCESSOR_PARAMETER => ['suffix' => 'baz', 'prefix' => 'foo']]
+ )
+ );
+ }
}