Skip to content

Commit

Permalink
feat(mapper): support generator mapping (#50)
Browse files Browse the repository at this point in the history
  • Loading branch information
joelwurtz authored Mar 11, 2024
1 parent 106eb30 commit 8b26844
Show file tree
Hide file tree
Showing 8 changed files with 82 additions and 5 deletions.
10 changes: 9 additions & 1 deletion src/Extractor/FromSourceMappingExtractor.php
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,20 @@ private function transformType(string $target, Type $type = null): ?Type

$builtinType = $type->getBuiltinType();
$className = $type->getClassName();
$collection = $type->isCollection();

if (Type::BUILTIN_TYPE_OBJECT === $type->getBuiltinType() && \stdClass::class !== $type->getClassName()) {
$builtinType = 'array' === $target ? Type::BUILTIN_TYPE_ARRAY : Type::BUILTIN_TYPE_OBJECT;
$className = 'array' === $target ? null : \stdClass::class;
}

// Use array for generator
if (Type::BUILTIN_TYPE_OBJECT === $type->getBuiltinType() && \Generator::class === $type->getClassName()) {
$builtinType = Type::BUILTIN_TYPE_ARRAY;
$className = null;
$collection = true;
}

// Use string for datetime
if (Type::BUILTIN_TYPE_OBJECT === $type->getBuiltinType() && (\DateTimeInterface::class === $type->getClassName() || is_subclass_of($type->getClassName(), \DateTimeInterface::class))) {
$builtinType = 'string';
Expand All @@ -132,7 +140,7 @@ private function transformType(string $target, Type $type = null): ?Type
$builtinType,
$type->isNullable(),
$className,
$type->isCollection(),
$collection,
$this->transformType($target, $collectionKeyTypes[0] ?? null),
$this->transformType($target, $collectionValueTypes[0] ?? null)
);
Expand Down
4 changes: 2 additions & 2 deletions src/Transformer/ArrayTransformerFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ final class ArrayTransformerFactory extends AbstractUniqueTypeTransformerFactory

protected function createTransformer(Type $sourceType, Type $targetType, MapperMetadataInterface $mapperMetadata): ?TransformerInterface
{
if (!$sourceType->isCollection()) {
if (!($sourceType->isCollection() || ($sourceType->getBuiltinType() === Type::BUILTIN_TYPE_OBJECT && $sourceType->getClassName() === \Generator::class))) {
return null;
}

Expand All @@ -27,7 +27,7 @@ protected function createTransformer(Type $sourceType, Type $targetType, MapperM
}

if ([] === $sourceType->getCollectionValueTypes() || [] === $targetType->getCollectionValueTypes()) {
return new CopyTransformer();
return new DictionaryTransformer(new CopyTransformer());
}

$subItemTransformer = $this->chainTransformerFactory->getTransformer($sourceType->getCollectionValueTypes(), $targetType->getCollectionValueTypes(), $mapperMetadata);
Expand Down
4 changes: 4 additions & 0 deletions src/Transformer/ObjectTransformerFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ private function isObjectType(Type $type): bool
return false;
}

if ($type->getClassName() === \Generator::class) {
return false;
}

return true;
}

Expand Down
28 changes: 28 additions & 0 deletions tests/AutoMapperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
use AutoMapper\Tests\Fixtures\ClassWithNullablePropertyInConstructor;
use AutoMapper\Tests\Fixtures\ClassWithPrivateProperty;
use AutoMapper\Tests\Fixtures\Fish;
use AutoMapper\Tests\Fixtures\FooGenerator;
use AutoMapper\Tests\Fixtures\HasDateTime;
use AutoMapper\Tests\Fixtures\HasDateTimeImmutable;
use AutoMapper\Tests\Fixtures\HasDateTimeImmutableWithNullValue;
Expand Down Expand Up @@ -1277,4 +1278,31 @@ public function testNoErrorWithUninitializedProperty(): void
$this->autoMapper->map(new Uninitialized(), 'array', ['skip_null_values' => true])
);
}

public function testAutoMappingGenerator(): void
{
$this->buildAutoMapper(mapPrivatePropertiesAndMethod: true);
$foo = new FooGenerator();

/** @var Fixtures\BarGenerator $bar */
$bar = $this->autoMapper->map($foo, Fixtures\BarGenerator::class);

// Test mapping to class
self::assertInstanceOf(Fixtures\BarGenerator::class, $bar);

self::assertSame([1, 2, 3, 'foo' => 'bar'], $bar->generator);
self::assertSame([1, 2, 3], $bar->array);

// Test mapping to array
$data = $this->autoMapper->map($foo, 'array');

self::assertSame([1, 2, 3, 'foo' => 'bar'], $data['generator']);
self::assertSame([1, 2, 3], $data['array']);

// Test mapping to stdClass
$data = $this->autoMapper->map($foo, \stdClass::class);

self::assertSame([1, 2, 3, 'foo' => 'bar'], $data->generator);
self::assertSame([1, 2, 3], $data->array);
}
}
12 changes: 12 additions & 0 deletions tests/Fixtures/BarGenerator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace AutoMapper\Tests\Fixtures;

class BarGenerator
{
public array $generator = [];

public array $array = [];
}
21 changes: 21 additions & 0 deletions tests/Fixtures/FooGenerator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace AutoMapper\Tests\Fixtures;

class FooGenerator
{
public function getGenerator(): \Generator
{
yield 1;
yield 2;
yield 3;
yield 'foo' => 'bar';
}

public function getArray(): array
{
return [1, 2, 3];
}
}
4 changes: 4 additions & 0 deletions tests/Fixtures/UserDTO.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ class UserDTO
*/
public $languages = [];

public array $generator = [];

public array $array = [];

public function setName($name)
{
$this->name = $name;
Expand Down
4 changes: 2 additions & 2 deletions tests/Transformer/ArrayTransformerFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use AutoMapper\MapperMetadata;
use AutoMapper\Transformer\ArrayTransformerFactory;
use AutoMapper\Transformer\ChainTransformerFactory;
use AutoMapper\Transformer\CopyTransformer;
use AutoMapper\Transformer\DictionaryTransformer;
use PHPUnit\Framework\TestCase;
use Symfony\Component\PropertyInfo\Type;

Expand All @@ -22,7 +22,7 @@ public function testGetTransformer(): void

$transformer = $factory->getTransformer([new Type('array', false, null, true)], [new Type('array', false, null, true)], $mapperMetadata);

self::assertInstanceOf(CopyTransformer::class, $transformer);
self::assertInstanceOf(DictionaryTransformer::class, $transformer);
}

public function testNoTransformerTargetNoCollection(): void
Expand Down

0 comments on commit 8b26844

Please sign in to comment.