Skip to content

Commit ec15b9c

Browse files
committed
feat(provider): better support for service callable from object mapper
1 parent 053b056 commit ec15b9c

File tree

12 files changed

+103
-60
lines changed

12 files changed

+103
-60
lines changed

src/Event/GenerateMapperEvent.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use AutoMapper\ConstructorStrategy;
88
use AutoMapper\Metadata\Discriminator;
99
use AutoMapper\Metadata\MapperMetadata;
10+
use AutoMapper\Metadata\Provider;
1011
use Symfony\Contracts\EventDispatcher\Event;
1112

1213
/**
@@ -20,15 +21,14 @@ final class GenerateMapperEvent extends Event
2021
public function __construct(
2122
public readonly MapperMetadata $mapperMetadata,
2223
public array $properties = [],
23-
public ?string $provider = null,
24+
public ?Provider $provider = null,
2425
public ?bool $checkAttributes = null,
2526
public ?ConstructorStrategy $constructorStrategy = null,
2627
public ?bool $allowReadOnlyTargetToPopulate = null,
2728
public ?bool $strictTypes = null,
2829
public ?bool $allowExtraProperties = null,
2930
public ?Discriminator $sourceDiscriminator = null,
3031
public ?Discriminator $targetDiscriminator = null,
31-
public bool $isProviderFromObjectMapper = false,
3232
) {
3333
}
3434
}

src/EventListener/ApiPlatform/JsonLdListener.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use AutoMapper\Event\PropertyMetadataEvent;
1212
use AutoMapper\Event\SourcePropertyMetadata;
1313
use AutoMapper\Event\TargetPropertyMetadata;
14+
use AutoMapper\Metadata\Provider;
1415
use AutoMapper\Provider\ApiPlatform\IriProvider;
1516
use AutoMapper\Transformer\ApiPlatform\JsonLdContextTransformer;
1617
use AutoMapper\Transformer\ApiPlatform\JsonLdIdTransformer;
@@ -68,7 +69,7 @@ public function __invoke(GenerateMapperEvent $event): void
6869
}
6970

7071
if ($event->mapperMetadata->source === 'array' && $this->resourceClassResolver->isResourceClass($event->mapperMetadata->target)) {
71-
$event->provider ??= IriProvider::class;
72+
$event->provider ??= new Provider(Provider::TYPE_SERVICE, IriProvider::class);
7273
}
7374
}
7475
}

src/EventListener/Doctrine/DoctrineProviderListener.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace AutoMapper\EventListener\Doctrine;
66

77
use AutoMapper\Event\GenerateMapperEvent;
8+
use AutoMapper\Metadata\Provider;
89
use AutoMapper\Provider\Doctrine\DoctrineProvider;
910
use Doctrine\Persistence\ObjectManager;
1011

@@ -21,6 +22,6 @@ public function __invoke(GenerateMapperEvent $event): void
2122
return;
2223
}
2324

24-
$event->provider ??= DoctrineProvider::class;
25+
$event->provider ??= new Provider(Provider::TYPE_SERVICE, DoctrineProvider::class);
2526
}
2627
}

src/EventListener/MapProviderListener.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use AutoMapper\Attribute\MapProvider;
88
use AutoMapper\Event\GenerateMapperEvent;
99
use AutoMapper\Exception\BadMapDefinitionException;
10+
use AutoMapper\Metadata\Provider;
1011

1112
/**
1213
* @internal
@@ -60,7 +61,7 @@ public function __invoke(GenerateMapperEvent $event): void
6061
if (false === $eventProvider) {
6162
$event->provider = null;
6263
} else {
63-
$event->provider = $eventProvider;
64+
$event->provider = new Provider(Provider::TYPE_SERVICE, $eventProvider);
6465
}
6566
}
6667
}

src/EventListener/ObjectMapper/MapListener.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use AutoMapper\Transformer\ReferenceTransformer;
1212
use AutoMapper\Transformer\ServiceLocatorTransformer;
1313
use AutoMapper\Transformer\TransformerInterface;
14+
use Psr\Container\ContainerInterface;
1415
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
1516
use Symfony\Component\ExpressionLanguage\SyntaxError;
1617
use Symfony\Component\ObjectMapper\Attribute\Map;
@@ -19,6 +20,7 @@
1920
abstract readonly class MapListener
2021
{
2122
public function __construct(
23+
protected ContainerInterface $serviceLocator,
2224
private ExpressionLanguage $expressionLanguage,
2325
) {
2426
}

src/EventListener/ObjectMapper/MapSourceListener.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use AutoMapper\Event\PropertyMetadataEvent;
1010
use AutoMapper\Event\SourcePropertyMetadata;
1111
use AutoMapper\Event\TargetPropertyMetadata;
12+
use AutoMapper\Metadata\Provider;
1213
use Symfony\Component\ObjectMapper\Attribute\Map;
1314
use Symfony\Component\ObjectMapper\Condition\TargetClass;
1415

@@ -88,8 +89,11 @@ public function __invoke(GenerateMapperEvent $event): void
8889
$callableName = null;
8990

9091
if (\is_callable($mapAttribute->transform, false, $callableName)) {
91-
$event->provider = $callableName;
92-
$event->isProviderFromObjectMapper = true;
92+
$event->provider = new Provider(Provider::TYPE_CALLABLE, $callableName, true);
93+
}
94+
95+
if (\is_string($mapAttribute->transform) && $this->serviceLocator->has($mapAttribute->transform)) {
96+
$event->provider = new Provider(Provider::TYPE_SERVICE_CALLABLE, $mapAttribute->transform, true);
9397
}
9498
}
9599

src/EventListener/ObjectMapper/MapTargetListener.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use AutoMapper\Event\PropertyMetadataEvent;
1010
use AutoMapper\Event\SourcePropertyMetadata;
1111
use AutoMapper\Event\TargetPropertyMetadata;
12+
use AutoMapper\Metadata\Provider;
1213
use Symfony\Component\ObjectMapper\Attribute\Map;
1314

1415
final readonly class MapTargetListener extends MapListener
@@ -74,8 +75,11 @@ public function __invoke(GenerateMapperEvent $event): void
7475
$callableName = null;
7576

7677
if (\is_callable($mapAttribute->transform, false, $callableName)) {
77-
$event->provider = $callableName;
78-
$event->isProviderFromObjectMapper = true;
78+
$event->provider = new Provider(Provider::TYPE_CALLABLE, $callableName, true);
79+
}
80+
81+
if (\is_string($mapAttribute->transform) && $this->serviceLocator->has($mapAttribute->transform)) {
82+
$event->provider = new Provider(Provider::TYPE_SERVICE_CALLABLE, $mapAttribute->transform, true);
7983
}
8084
}
8185
}

src/Generator/MapMethodStatementsGenerator.php

Lines changed: 39 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use AutoMapper\Generator\Shared\DiscriminatorStatementsGenerator;
1010
use AutoMapper\MapperContext;
1111
use AutoMapper\Metadata\GeneratorMetadata;
12+
use AutoMapper\Metadata\Provider;
1213
use AutoMapper\Provider\EarlyReturn;
1314
use PhpParser\Comment;
1415
use PhpParser\Node\Arg;
@@ -420,10 +421,8 @@ private function initializeTargetFromProvider(GeneratorMetadata $metadata): arra
420421
}
421422

422423
$variableRegistry = $metadata->variableRegistry;
423-
$statements = [];
424-
$callableName = null;
425424

426-
if ($metadata->isProviderFromObjectMapper) {
425+
if ($metadata->provider->isFromObjectMapper) {
427426
// When the provider is from the ObjectMapper, we call it with 3 arguments
428427
/*
429428
* $result ?? (new ReflectionClass($metadata->mapperMetadata->target))->newInstanceWithoutConstructor();
@@ -449,58 +448,65 @@ private function initializeTargetFromProvider(GeneratorMetadata $metadata): arra
449448
];
450449
}
451450

452-
if (\is_callable($metadata->provider, false, $callableName)) {
451+
if ($metadata->provider->type === Provider::TYPE_CALLABLE) {
453452
/*
454453
* Get result from callable if available
455454
*
456455
* ```php
457-
* $result ??= callable(Target::class, $value, $context, $this->getTargetIdentifiers($value));
456+
* callable(Target::class, $value, $context, $this->getTargetIdentifiers($value));
458457
* ```
459458
*/
460-
$statements[] = new Stmt\Expression(
461-
new Expr\AssignOp\Coalesce(
462-
$variableRegistry->getResult(),
463-
new Expr\FuncCall(new Name($callableName), $args),
464-
)
465-
);
459+
$providerExpression = new Expr\FuncCall(new Name($metadata->provider->value), $args);
460+
} elseif ($metadata->provider->type === Provider::TYPE_SERVICE_CALLABLE) {
461+
/*
462+
* Get result from provider if available
463+
*
464+
* ```php
465+
* $this->serviceLocator->get($metadata->provider)($source, $context);
466+
* ```
467+
*/
468+
$providerExpression = new Expr\FuncCall(new Expr\MethodCall(new Expr\PropertyFetch(new Expr\Variable('this'), 'serviceLocator'), 'get', [
469+
new Arg(new Scalar\String_($metadata->provider->value)),
470+
]), $args);
466471
} else {
467472
/*
468473
* Get result from provider if available
469474
*
470475
* ```php
471-
* $result ??= $this->providerRegistry->getProvider($metadata->provider)->provide($source, $context);
476+
* $this->serviceLocator->get($metadata->provider)->provide($source, $context);
472477
* ```
473478
*/
474-
$statements[] = new Stmt\Expression(
475-
new Expr\AssignOp\Coalesce(
476-
$variableRegistry->getResult(),
477-
new Expr\MethodCall(new Expr\MethodCall(new Expr\PropertyFetch(new Expr\Variable('this'), 'serviceLocator'), 'get', [
478-
new Arg(new Scalar\String_($metadata->provider)),
479-
]), 'provide', $args),
480-
)
481-
);
479+
$providerExpression = new Expr\MethodCall(new Expr\MethodCall(new Expr\PropertyFetch(new Expr\Variable('this'), 'serviceLocator'), 'get', [
480+
new Arg(new Scalar\String_($metadata->provider->value)),
481+
]), 'provide', $args);
482482
}
483483

484484
/*
485-
* Return early if the result is an EarlyReturn instance
485+
* $result ??= provider(...);
486486
*
487487
* if ($result instanceof EarlyReturn) {
488488
* return $result->value;
489489
* }
490490
* ```
491491
*/
492-
$statements[] = new Stmt\If_(
493-
new Expr\Instanceof_($variableRegistry->getResult(), new Name(EarlyReturn::class)),
494-
[
495-
'stmts' => [
496-
new Stmt\Return_(
497-
new Expr\PropertyFetch($variableRegistry->getResult(), 'value')
498-
),
499-
],
500-
]
501-
);
502-
503-
return $statements;
492+
return [
493+
new Stmt\Expression(
494+
new Expr\AssignOp\Coalesce(
495+
$variableRegistry->getResult(),
496+
$providerExpression,
497+
)
498+
),
499+
new Stmt\If_(
500+
new Expr\Instanceof_($variableRegistry->getResult(), new Name(EarlyReturn::class)),
501+
[
502+
'stmts' => [
503+
new Stmt\Return_(
504+
new Expr\PropertyFetch($variableRegistry->getResult(), 'value')
505+
),
506+
],
507+
]
508+
),
509+
];
504510
}
505511

506512
/**

src/Metadata/GeneratorMetadata.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,9 @@ public function __construct(
2626
public readonly ConstructorStrategy $constructorStrategy = ConstructorStrategy::AUTO,
2727
public readonly bool $allowReadOnlyTargetToPopulate = false,
2828
public readonly bool $strictTypes = false,
29-
public readonly ?string $provider = null,
29+
public readonly ?Provider $provider = null,
3030
public readonly ?Discriminator $sourceDiscriminator = null,
3131
public readonly ?Discriminator $targetDiscriminator = null,
32-
public readonly bool $isProviderFromObjectMapper = false,
3332
) {
3433
$this->variableRegistry = new VariableRegistry();
3534
}

src/Metadata/MetadataFactory.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,6 @@ private function createGeneratorMetadata(MapperMetadata $mapperMetadata): Genera
336336
$mapperEvent->provider,
337337
$mapperEvent->sourceDiscriminator,
338338
$mapperEvent->targetDiscriminator,
339-
$mapperEvent->isProviderFromObjectMapper,
340339
);
341340
}
342341

@@ -394,8 +393,8 @@ public static function create(
394393
$eventDispatcher->addListener(GenerateMapperEvent::class, new MapProviderListener());
395394

396395
if (interface_exists(ObjectMapperInterface::class)) {
397-
$eventDispatcher->addListener(GenerateMapperEvent::class, new MapSourceListener($expressionLanguage));
398-
$eventDispatcher->addListener(GenerateMapperEvent::class, new MapTargetListener($expressionLanguage));
396+
$eventDispatcher->addListener(GenerateMapperEvent::class, new MapSourceListener($serviceLocator, $expressionLanguage));
397+
$eventDispatcher->addListener(GenerateMapperEvent::class, new MapTargetListener($serviceLocator, $expressionLanguage));
399398
}
400399

401400
// Create transformer factories

0 commit comments

Comments
 (0)