Skip to content

Commit

Permalink
Add name converter support
Browse files Browse the repository at this point in the history
  • Loading branch information
joelwurtz committed Nov 30, 2018
1 parent 3468752 commit 9d9e639
Show file tree
Hide file tree
Showing 11 changed files with 113 additions and 33 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"symfony/options-resolver": "^3.1 || ^4.0",
"symfony/property-access": "^3.1 || ^4.0",
"symfony/property-info": "^3.4 || ^4.0",
"symfony/serializer": "^3.2 || ^4.0",
"symfony/serializer": "^4.2",
"symfony/yaml": "^3.1 || ^4.0"
},
"replace": {
Expand Down
7 changes: 5 additions & 2 deletions src/AutoMapper/AbstractMapperConfiguration.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,15 @@ abstract class AbstractMapperConfiguration implements MapperConfigurationInterfa

protected $circularReferenceLimit;

public function __construct(string $source, string $target)
protected $classPrefix;

public function __construct(string $source, string $target, $classPrefix = 'Mapper_')
{
$this->source = $source;
$this->target = $target;
$this->isConstructorAllowed = true;
$this->dateTimeFormat = \DateTime::RFC3339;
$this->classPrefix = $classPrefix;
}

public function getSource(): string
Expand All @@ -44,7 +47,7 @@ public function getMapperClassName(): string
return $this->className;
}

return $this->className = sprintf('Mapper_%s_%s', str_replace('\\', '_', $this->source), str_replace('\\', '_', $this->target));
return $this->className = sprintf('%s%s_%s', $this->classPrefix, str_replace('\\', '_', $this->source), str_replace('\\', '_', $this->target));
}

public function createMapper(): Mapper
Expand Down
12 changes: 8 additions & 4 deletions src/AutoMapper/AutoMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
use Symfony\Component\PropertyInfo\PropertyInfoExtractor;
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
use Symfony\Component\Serializer\NameConverter\AdvancedNameConverterInterface;

class AutoMapper extends AbstractAutoMapper
{
Expand All @@ -32,7 +33,7 @@ class AutoMapper extends AbstractAutoMapper
*
* @internal
*/
public static function create(bool $private = true, MapperClassLoaderInterface $loader = null): self
public static function create(bool $private = true, MapperClassLoaderInterface $loader = null, AdvancedNameConverterInterface $nameConverter = null, string $classPrefix = 'Mapper_'): self
{
if ($loader === null) {
$loader = new EvalLoader(new Compiler());
Expand Down Expand Up @@ -66,20 +67,23 @@ public static function create(bool $private = true, MapperClassLoaderInterface $
$propertyInfoExtractor,
$accessorExtractor,
$transformerFactory,
$classMetadataFactory
$classMetadataFactory,
$nameConverter
);

$fromSourceMappingExtractor = new FromSourcePropertiesMappingExtractor(
$propertyInfoExtractor,
$accessorExtractor,
$transformerFactory,
$classMetadataFactory
$classMetadataFactory,
$nameConverter
);

$autoMapper = new self($loader, new MapperConfigurationFactory(
$sourceTargetMappingExtractor,
$fromSourceMappingExtractor,
$fromTargetMappingExtractor
$fromTargetMappingExtractor,
$classPrefix
));

$transformerFactory->addTransformerFactory(new MultipleTransformerFactory($transformerFactory));
Expand Down
26 changes: 21 additions & 5 deletions src/AutoMapper/Compiler/FromSourcePropertiesMappingExtractor.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,27 @@

namespace Jane\AutoMapper\Compiler;

use Jane\AutoMapper\Compiler\Accessor\AccessorExtractorInterface;
use Jane\AutoMapper\Compiler\Accessor\WriteMutator;
use Jane\AutoMapper\Compiler\Transformer\TransformerFactoryInterface;
use Jane\AutoMapper\MapperConfigurationInterface;
use SebastianBergmann\GlobalState\RuntimeException;
use Symfony\Component\PropertyInfo\PropertyInfoExtractorInterface;
use Symfony\Component\PropertyInfo\Type;
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
use Symfony\Component\Serializer\NameConverter\AdvancedNameConverterInterface;

class FromSourcePropertiesMappingExtractor extends PropertiesMappingExtractor
{
private $nameConverter;

public function __construct(PropertyInfoExtractorInterface $propertyInfoExtractor, AccessorExtractorInterface $accessorExtractor, TransformerFactoryInterface $transformerFactory, ClassMetadataFactoryInterface $classMetadataFactory = null, AdvancedNameConverterInterface $nameConverter = null)
{
parent::__construct($propertyInfoExtractor, $accessorExtractor, $transformerFactory, $classMetadataFactory);

$this->nameConverter = $nameConverter;
}

public function getPropertiesMapping(string $source, string $target, MapperConfigurationInterface $mapperConfiguration): array
{
$sourceProperties = $this->propertyInfoExtractor->getProperties($source);
Expand Down Expand Up @@ -47,11 +61,9 @@ public function getPropertiesMapping(string $source, string $target, MapperConfi
continue;
}

$targetMutator = $this->getWriteMutator($target, $property);
$sourceAccessor = $this->accessorExtractor->getReadAccessor($source, $property);
$mapping[] = new PropertyMapping(
$sourceAccessor,
$targetMutator,
$this->getReadAccessor($source, $target, $property),
$this->getWriteMutator($source, $target, $property),
$transformer,
$property,
false,
Expand Down Expand Up @@ -93,8 +105,12 @@ private function transformType(string $target, Type $type = null): ?Type
);
}

public function getWriteMutator(string $target, string $property): WriteMutator
public function getWriteMutator(string $source, string $target, string $property): WriteMutator
{
if ($this->nameConverter !== null) {
$property = $this->nameConverter->normalize($property, $source, $target);
}

$targetMutator = new WriteMutator(WriteMutator::TYPE_ARRAY_DIMENSION, $property, false);

if ($target === \stdClass::class) {
Expand Down
41 changes: 31 additions & 10 deletions src/AutoMapper/Compiler/FromTargetPropertiesMappingExtractor.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,27 @@

namespace Jane\AutoMapper\Compiler;

use Jane\AutoMapper\Compiler\Accessor\AccessorExtractorInterface;
use Jane\AutoMapper\Compiler\Accessor\ReadAccessor;
use Jane\AutoMapper\Compiler\Transformer\TransformerFactoryInterface;
use Jane\AutoMapper\MapperConfigurationInterface;
use SebastianBergmann\GlobalState\RuntimeException;
use Symfony\Component\PropertyInfo\PropertyInfoExtractorInterface;
use Symfony\Component\PropertyInfo\Type;
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
use Symfony\Component\Serializer\NameConverter\AdvancedNameConverterInterface;

class FromTargetPropertiesMappingExtractor extends PropertiesMappingExtractor
{
private $nameConverter;

public function __construct(PropertyInfoExtractorInterface $propertyInfoExtractor, AccessorExtractorInterface $accessorExtractor, TransformerFactoryInterface $transformerFactory, ClassMetadataFactoryInterface $classMetadataFactory = null, AdvancedNameConverterInterface $nameConverter = null)
{
parent::__construct($propertyInfoExtractor, $accessorExtractor, $transformerFactory, $classMetadataFactory);

$this->nameConverter = $nameConverter;
}

public function getPropertiesMapping(string $source, string $target, MapperConfigurationInterface $mapperConfiguration): array
{
$targetProperties = array_unique($this->propertyInfoExtractor->getProperties($target));
Expand Down Expand Up @@ -46,17 +60,9 @@ public function getPropertiesMapping(string $source, string $target, MapperConfi
continue;
}

$sourceAccessor = new ReadAccessor(ReadAccessor::TYPE_ARRAY_DIMENSION, $property);

if ($source === \stdClass::class) {
$sourceAccessor = new ReadAccessor(ReadAccessor::TYPE_PROPERTY, $property);
}

$targetMutator = $this->accessorExtractor->getWriteMutator($target, $property, $mapperConfiguration->isConstructorAllowed());

$mapping[] = new PropertyMapping(
$sourceAccessor,
$targetMutator,
$this->getReadAccessor($source, $target, $property),
$this->getWriteMutator($source, $target, $property),
$transformer,
$property,
true,
Expand All @@ -69,6 +75,21 @@ public function getPropertiesMapping(string $source, string $target, MapperConfi
return $mapping;
}

public function getReadAccessor(string $source, string $target, string $property): ?ReadAccessor
{
if (null !== $this->nameConverter) {
$property = $this->nameConverter->normalize($property, $target, $source);
}

$sourceAccessor = new ReadAccessor(ReadAccessor::TYPE_ARRAY_DIMENSION, $property);

if ($source === \stdClass::class) {
$sourceAccessor = new ReadAccessor(ReadAccessor::TYPE_PROPERTY, $property);
}

return $sourceAccessor;
}

private function transformType(string $source, Type $type = null): ?Type
{
if ($type === null) {
Expand Down
4 changes: 2 additions & 2 deletions src/AutoMapper/Compiler/PropertiesMappingExtractor.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ public function __construct(PropertyInfoExtractorInterface $propertyInfoExtracto
$this->classMetadataFactory = $classMetadataFactory;
}

public function getReadAccessor(string $source, string $property): ?ReadAccessor
public function getReadAccessor(string $source, string $target, string $property): ?ReadAccessor
{
return $this->accessorExtractor->getReadAccessor($source, $property);
}

public function getWriteMutator(string $target, string $property): ?WriteMutator
public function getWriteMutator(string $source, string $target, string $property): ?WriteMutator
{
return $this->accessorExtractor->getWriteMutator($target, $property);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ interface PropertiesMappingExtractorInterface
*/
public function getPropertiesMapping(string $source, string $target, MapperConfigurationInterface $mapperConfiguration): array;

public function getReadAccessor(string $source, string $property): ?ReadAccessor;
public function getReadAccessor(string $source, string $target, string $property): ?ReadAccessor;

public function getWriteMutator(string $target, string $property): ?WriteMutator;
public function getWriteMutator(string $source, string $target, string $property): ?WriteMutator;
}
8 changes: 4 additions & 4 deletions src/AutoMapper/MapperConfiguration.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ class MapperConfiguration extends AbstractMapperConfiguration

private $customMapping = [];

public function __construct(PropertiesMappingExtractorInterface $mappingExtractor, string $source, string $target)
public function __construct(PropertiesMappingExtractorInterface $mappingExtractor, string $source, string $target, string $classPrefix = 'Mapper_')
{
$this->mappingExtractor = $mappingExtractor;

parent::__construct($source, $target);
parent::__construct($source, $target, $classPrefix);
}

/**
Expand All @@ -30,7 +30,7 @@ public function getPropertiesMapping(): array
foreach ($this->customMapping as $property => $callback) {
$mappings[] = new PropertyMapping(
new ReadAccessor(ReadAccessor::TYPE_SOURCE, $property),
$this->mappingExtractor->getWriteMutator($this->target, $property),
$this->mappingExtractor->getWriteMutator($this->source, $this->target, $property),
new CallbackTransformer($property),
$property,
false
Expand Down Expand Up @@ -87,7 +87,7 @@ public function hasConstructor(): bool
}

foreach ($mandatoryParameters as $mandatoryParameter) {
$readAccessor = $this->mappingExtractor->getReadAccessor($this->source, $mandatoryParameter->getName());
$readAccessor = $this->mappingExtractor->getReadAccessor($this->source, $this->target, $mandatoryParameter->getName());

if ($readAccessor === null) {
return false;
Expand Down
7 changes: 5 additions & 2 deletions src/AutoMapper/MapperConfigurationFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,18 @@ class MapperConfigurationFactory
private $sourceTargetPropertiesMappingExtractor;
private $fromSourcePropertiesMappingExtractor;
private $fromTargetPropertiesMappingExtractor;
private $classPrefix;

public function __construct(
SourceTargetPropertiesMappingExtractor $sourceTargetPropertiesMappingExtractor,
FromSourcePropertiesMappingExtractor $fromSourcePropertiesMappingExtractor,
FromTargetPropertiesMappingExtractor $fromTargetPropertiesMappingExtractor
FromTargetPropertiesMappingExtractor $fromTargetPropertiesMappingExtractor,
string $classPrefix = 'Mapper_'
) {
$this->sourceTargetPropertiesMappingExtractor = $sourceTargetPropertiesMappingExtractor;
$this->fromSourcePropertiesMappingExtractor = $fromSourcePropertiesMappingExtractor;
$this->fromTargetPropertiesMappingExtractor = $fromTargetPropertiesMappingExtractor;
$this->classPrefix = $classPrefix;
}

public function create($source, $target): MapperConfigurationInterface
Expand All @@ -34,6 +37,6 @@ public function create($source, $target): MapperConfigurationInterface
$extractor = $this->fromSourcePropertiesMappingExtractor;
}

return new MapperConfiguration($extractor, $source, $target);
return new MapperConfiguration($extractor, $source, $target, $this->classPrefix);
}
}
33 changes: 33 additions & 0 deletions src/AutoMapper/Tests/AutoMapperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
use Jane\AutoMapper\Tests\Domain\UserDTONoAge;
use Jane\AutoMapper\Tests\Domain\UserDTONoName;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Serializer\NameConverter\AdvancedNameConverterInterface;

class AutoMapperTest extends TestCase
{
Expand Down Expand Up @@ -364,4 +365,36 @@ public function testIgnoredAttributes()

self::assertNull($userDto->name);
}

public function testNameConverter()
{
$nameConverter = new class() implements AdvancedNameConverterInterface {
public function normalize($propertyName, string $class = null, string $format = null, array $context = [])
{
if ($propertyName === 'id') {
return '@id';
}

return $propertyName;
}

public function denormalize($propertyName, string $class = null, string $format = null, array $context = [])
{
if ($propertyName === '@id') {
return 'id';
}

return $propertyName;
}
};

$autoMapper = AutoMapper::create(true, null, $nameConverter, 'Mapper2_');
$user = new User(1, 'yolo', '13');

$userArray = $autoMapper->map($user, 'array', new Context());

self::assertInternalType('array', $userArray);
self::assertArrayHasKey('@id', $userArray);
self::assertSame(1, $userArray['@id']);
}
}
2 changes: 1 addition & 1 deletion src/AutoMapper/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"doctrine/annotations": "^1.5",
"phpunit/phpunit": "^6.0",
"symfony/framework-bundle": "^4.0",
"symfony/serializer": "^3.4|^4.0"
"symfony/serializer": "^4.2"
},
"config": {
"process-timeout": 1800,
Expand Down

0 comments on commit 9d9e639

Please sign in to comment.