Skip to content

Commit

Permalink
feat(SubMapper): Now available as additional argument in `PropertyM…
Browse files Browse the repository at this point in the history
…apper` & `ObjectMapper`.
  • Loading branch information
priyadi committed Feb 4, 2024
1 parent 69baf42 commit abe8450
Show file tree
Hide file tree
Showing 12 changed files with 66 additions and 24 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
* feat: `ObjectMapper`
* refactor: Compiler pass namespace.
* refactor(`CompilerPass`): Reduce code duplication.
* feat(`SubMapper`): Now available as additional argument in `PropertyMapper` &
`ObjectMapper`.

## 0.5.26

Expand Down
1 change: 1 addition & 0 deletions config/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@
->args([
'$objectToObjectMetadataFactory' => service('rekalogika.mapper.object_to_object_metadata_factory'),
'$propertyMapperLocator' => tagged_locator('rekalogika.mapper.property_mapper'),
'$subMapperFactory' => service('rekalogika.mapper.sub_mapper.factory'),
])
->tag('rekalogika.mapper.transformer', ['priority' => -900]);

Expand Down
1 change: 1 addition & 0 deletions src/MapperFactory/MapperFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@ protected function getObjectToObjectTransformer(): TransformerInterface
$this->objectToObjectTransformer = new ObjectToObjectTransformer(
objectToObjectMetadataFactory: $this->getObjectToObjectMetadataFactory(),
propertyMapperLocator: $this->getPropertyMapperLocator(),
subMapperFactory: $this->getSubMapperFactory(),
);
}

Expand Down
2 changes: 2 additions & 0 deletions src/ServiceMethod/ServiceMethodExtraArgumentUtil.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use Rekalogika\Mapper\Context\Context;
use Rekalogika\Mapper\Exception\InvalidArgumentException;
use Rekalogika\Mapper\MainTransformer\MainTransformerInterface;
use Rekalogika\Mapper\SubMapper\SubMapperInterface;

class ServiceMethodExtraArgumentUtil
{
Expand Down Expand Up @@ -54,6 +55,7 @@ public static function getExtraArguments(
$extraArguments[] = match ($type->getName()) {
Context::class => ServiceMethodSpecification::ARGUMENT_CONTEXT,
MainTransformerInterface::class => ServiceMethodSpecification::ARGUMENT_MAIN_TRANSFORMER,
SubMapperInterface::class => ServiceMethodSpecification::ARGUMENT_SUB_MAPPER,
default => throw new InvalidArgumentException(
sprintf(
'Extra argument with type "%s" for property mapper "%s" in class "%s" is unsupported.',
Expand Down
23 changes: 16 additions & 7 deletions src/ServiceMethod/ServiceMethodRunner.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,31 @@

use Psr\Container\ContainerInterface;
use Rekalogika\Mapper\Context\Context;
use Rekalogika\Mapper\Exception\LogicException;
use Rekalogika\Mapper\MainTransformer\MainTransformerInterface;
use Rekalogika\Mapper\SubMapper\SubMapperFactoryInterface;
use Symfony\Component\PropertyInfo\Type;

class ServiceMethodRunner
{
public static function create(
ContainerInterface $serviceLocator,
MainTransformerInterface $mainTransformer
MainTransformerInterface $mainTransformer,
SubMapperFactoryInterface $subMapperFactory,
): self {
return new self($serviceLocator, $mainTransformer);
return new self($serviceLocator, $mainTransformer, $subMapperFactory);
}

private function __construct(
private ContainerInterface $serviceLocator,
private MainTransformerInterface $mainTransformer
private MainTransformerInterface $mainTransformer,
private SubMapperFactoryInterface $subMapperFactory,
) {
}

public function run(
ServiceMethodSpecification $serviceMethodSpecification,
mixed $input,
mixed $source,
?Type $targetType,
Context $context,
): mixed {
/** @var object */
Expand All @@ -49,11 +53,16 @@ public function run(
$arguments[] = match ($extraArgument) {
ServiceMethodSpecification::ARGUMENT_CONTEXT => $context,
ServiceMethodSpecification::ARGUMENT_MAIN_TRANSFORMER => $this->mainTransformer,
default => throw new LogicException('Unknown extra argument: ' . $extraArgument, context: $context),
ServiceMethodSpecification::ARGUMENT_SUB_MAPPER => $this->subMapperFactory->createSubMapper(
mainTransformer: $this->mainTransformer,
source: $source,
targetType: $targetType,
context: $context
),
};
}

/** @psalm-suppress MixedMethodCall */
return $service->{$method}($input, ...$arguments);
return $service->{$method}($source, ...$arguments);
}
}
2 changes: 1 addition & 1 deletion src/ServiceMethod/ServiceMethodSpecification.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
{
public const ARGUMENT_CONTEXT = 'context';
public const ARGUMENT_MAIN_TRANSFORMER = 'main_transformer';
public const ARGUMENT_NONE = 'none'; // should not be used
public const ARGUMENT_SUB_MAPPER = 'sub_mapper';

/**
* @param array<int,self::ARGUMENT_*> $extraArguments
Expand Down
25 changes: 25 additions & 0 deletions src/SubMapper/Exception/CacheNotSupportedException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

declare(strict_types=1);

/*
* This file is part of rekalogika/mapper package.
*
* (c) Priyadi Iman Nurcahyo <https://rekalogika.dev>
*
* For the full copyright and license information, please view the LICENSE file
* that was distributed with this source code.
*/

namespace Rekalogika\Mapper\SubMapper\Exception;

use Rekalogika\Mapper\Context\Context;
use Rekalogika\Mapper\Exception\RuntimeException;

class CacheNotSupportedException extends RuntimeException
{
public function __construct(Context $context)
{
parent::__construct('The "cache()" method is not supported, and should be unnecessary in a sub-mapper under a property mapper.', context: $context);
}
}
7 changes: 6 additions & 1 deletion src/SubMapper/Implementation/SubMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use Rekalogika\Mapper\Context\Context;
use Rekalogika\Mapper\Exception\UnexpectedValueException;
use Rekalogika\Mapper\ObjectCache\ObjectCache;
use Rekalogika\Mapper\SubMapper\Exception\CacheNotSupportedException;
use Rekalogika\Mapper\SubMapper\SubMapperInterface;
use Rekalogika\Mapper\Transformer\Contracts\MainTransformerAwareInterface;
use Rekalogika\Mapper\Transformer\Contracts\MainTransformerAwareTrait;
Expand All @@ -36,7 +37,7 @@ public function __construct(
private PropertyTypeExtractorInterface $propertyTypeExtractor,
private PropertyAccessorInterface $propertyAccessor,
private mixed $source,
private Type $targetType,
private ?Type $targetType,
private Context $context,
) {
}
Expand Down Expand Up @@ -122,6 +123,10 @@ public function mapForProperty(

public function cache(mixed $target): void
{
if ($this->targetType === null) {
throw new CacheNotSupportedException($this->context);
}

($this->context)(ObjectCache::class)->saveTarget(
source: $this->source,
targetType: $this->targetType,
Expand Down
2 changes: 1 addition & 1 deletion src/SubMapper/Implementation/SubMapperFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public function __construct(
public function createSubMapper(
MainTransformerInterface $mainTransformer,
mixed $source,
Type $targetType,
?Type $targetType,
Context $context,
): SubMapperInterface {
$subMapper = new SubMapper(
Expand Down
2 changes: 1 addition & 1 deletion src/SubMapper/SubMapperFactoryInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ interface SubMapperFactoryInterface
public function createSubMapper(
MainTransformerInterface $mainTransformer,
mixed $source,
Type $targetType,
?Type $targetType,
Context $context
): SubMapperInterface;
}
15 changes: 4 additions & 11 deletions src/Transformer/ObjectMapperTransformer.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,6 @@ public function transform(
throw new InvalidArgumentException('Target type must not be null.', context: $context);
}

// prepare subMapper

$subMapper = $this->subMapperFactory->createSubMapper(
mainTransformer: $this->getMainTransformer(),
source: $source,
targetType: $targetType,
context: $context
);

// target class must be valid

$targetClass = $targetType->getClassName();
Expand Down Expand Up @@ -97,12 +88,14 @@ public function transform(

$serviceMethodRunner = ServiceMethodRunner::create(
serviceLocator: $this->serviceLocator,
mainTransformer: $this->getMainTransformer()
mainTransformer: $this->getMainTransformer(),
subMapperFactory: $this->subMapperFactory
);

return $serviceMethodRunner->run(
serviceMethodSpecification: $serviceMethodSpecification,
input: $source,
source: $source,
targetType: $targetType,
context: $context
);
}
Expand Down
8 changes: 6 additions & 2 deletions src/Transformer/ObjectToObjectTransformer.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use Rekalogika\Mapper\Exception\InvalidArgumentException;
use Rekalogika\Mapper\ObjectCache\ObjectCache;
use Rekalogika\Mapper\ServiceMethod\ServiceMethodRunner;
use Rekalogika\Mapper\SubMapper\SubMapperFactoryInterface;
use Rekalogika\Mapper\Transformer\Contracts\MainTransformerAwareInterface;
use Rekalogika\Mapper\Transformer\Contracts\MainTransformerAwareTrait;
use Rekalogika\Mapper\Transformer\Contracts\TransformerInterface;
Expand Down Expand Up @@ -48,6 +49,7 @@ final class ObjectToObjectTransformer implements TransformerInterface, MainTrans
public function __construct(
private ObjectToObjectMetadataFactoryInterface $objectToObjectMetadataFactory,
private ContainerInterface $propertyMapperLocator,
private SubMapperFactoryInterface $subMapperFactory,
ReaderWriter $readerWriter = null,
) {
$this->readerWriter = $readerWriter ?? new ReaderWriter();
Expand Down Expand Up @@ -257,12 +259,14 @@ private function transformValue(
if ($serviceMethodSpecification = $propertyMapping->getPropertyMapper()) {
$serviceMethodRunner = ServiceMethodRunner::create(
serviceLocator: $this->propertyMapperLocator,
mainTransformer: $this->getMainTransformer()
mainTransformer: $this->getMainTransformer(),
subMapperFactory: $this->subMapperFactory
);

return $serviceMethodRunner->run(
serviceMethodSpecification: $serviceMethodSpecification,
input: $source,
source: $source,
targetType: null,
context: $context
);
}
Expand Down

0 comments on commit abe8450

Please sign in to comment.