Skip to content

Commit

Permalink
feat: Transformers now have the option to have an invariant target type.
Browse files Browse the repository at this point in the history
  • Loading branch information
priyadi committed Jan 14, 2024
1 parent 79873e6 commit 20f10ce
Show file tree
Hide file tree
Showing 27 changed files with 186 additions and 80 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@
* feat: If a transformer throws `RefuseToHandleException`, the `MainTransformer`
will try the next suitable transformer.
* style: Remove unused vars.
* feat: Transformers now have the option to have an invariant target type.

## 0.5.8

* fix: PropertyAccessor `UninitializedPropertyException` error now is regarded
as null.
as null.****
* fix: Transformer `SearchResult` was not properly ordered.
* feat: `TryProperty` command, or `rekalogika:mapper:tryproperty` in console.

Expand Down
12 changes: 7 additions & 5 deletions src/Command/MappingCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,21 +57,22 @@ protected function execute(InputInterface $input, OutputInterface $output): int

foreach ($mapping as $entry) {
$order = $entry->getOrder();
$sourceType = $entry->getSourceType();
$targetType = $entry->getTargetType();
$sourceType = $entry->getSourceTypeString();
$targetType = $entry->getTargetTypeString();
$class = $entry->getClass();
$id = $entry->getId();
$variantTargetType = $entry->isVariantTargetType();

if ($sourceOption) {
if (preg_match('/' . preg_quote($sourceOption) . '/i', $entry->getSourceType()) === 0) {
if (preg_match('/' . preg_quote($sourceOption) . '/i', $entry->getSourceTypeString()) === 0) {
continue;
}

$sourceType = preg_replace('/(' . preg_quote($sourceOption) . ')/i', '<bg=yellow>$1</>', $sourceType);
}

if ($targetOption) {
if (preg_match('/' . preg_quote($targetOption) . '/i', $entry->getTargetType()) === 0) {
if (preg_match('/' . preg_quote($targetOption) . '/i', $entry->getTargetTypeString()) === 0) {
continue;
}

Expand All @@ -94,14 +95,15 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$order,
$sourceType,
$targetType,
$variantTargetType ? 'variant' : 'invariant',
$id,
$class,
];
}

$io->section($title);
$table = new Table($output);
$table->setHeaders(['Order', 'Source Type', 'Target Type', 'Service ID', 'Class']);
$table->setHeaders(['Ordering', 'Source Type', 'Target Type', 'Target Variance', 'Service ID', 'Class']);
$table->setStyle('box');
$table->setRows($rows);
$table->render();
Expand Down
27 changes: 13 additions & 14 deletions src/Command/TryCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$sourceTypeString = $input->getArgument('source');
$sourceType = TypeFactory::fromString($sourceTypeString);
$sourceTypeStrings = $this->typeResolver
->getApplicableTypeStrings($sourceType);
->getAcceptedTransformerInputTypeStrings($sourceType);

$rows[] = ['Source type', $sourceTypeString];
$rows[] = new TableSeparator();
Expand All @@ -73,7 +73,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$targetTypeString = $input->getArgument('target');
$targetType = TypeFactory::fromString($targetTypeString);
$targetTypeStrings = $this->typeResolver
->getApplicableTypeStrings($targetType);
->getAcceptedTransformerOutputTypeStrings($targetType);

$rows[] = new TableSeparator();
$rows[] = ['Target type', $targetTypeString];
Expand All @@ -100,19 +100,17 @@ protected function execute(InputInterface $input, OutputInterface $output): int

$rows = [];

$transformers = $this->transformerRegistry
->getMappingBySourceAndTargetType(
$sourceType,
$targetType
);
$searchResult = $this->transformerRegistry
->findBySourceAndTargetTypes([$sourceType], [$targetType]);

foreach ($transformers as $entry) {
foreach ($searchResult as $entry) {
$rows[] = [
$entry->getOrder(),
$entry->getId(),
$entry->getClass(),
$entry->getSourceType(),
$entry->getTargetType()
$entry->getMappingOrder(),
$entry->getTransformerServiceId(),
$entry->getTransformer()::class,
$this->typeResolver->getTypeString($entry->getSourceType()),
$this->typeResolver->getTypeString($entry->getTargetType()),
$entry->isVariantTargetType() ? 'variant' : 'invariant',
];
$rows[] = new TableSeparator();
}
Expand All @@ -133,8 +131,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int
}

$table = new Table($output);
$table->setHeaders(['Order', 'Service ID', 'Class', 'Source Type', 'Target Type']);
$table->setHeaders(['Ordering', 'Service ID', 'Class', 'Source Type', 'Target Type', 'Variance']);
$table->setStyle('box');
$table->setVertical();
$table->setRows($rows);
$table->render();

Expand Down
6 changes: 5 additions & 1 deletion src/Exception/ContextAwareExceptionTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@ public function __construct(
}

if ($path !== null) {
parent::__construct(sprintf('%s Mapping path: "%s"', $message, (string) $path), $code, $previous);
$path = (string) $path;
if ($path === '') {
$path = '(root)';
}
parent::__construct(sprintf('%s Mapping path: "%s".', $message, $path), $code, $previous);
} else {
parent::__construct($message, $code, $previous);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public function __construct(array $sourceTypes, array $targetTypes, Context $con
$targetTypes = TypeUtil::getDebugType($targetTypes);

parent::__construct(
sprintf('Cannot find a matching transformer for mapping the source types "%s" to the target types "%s".', $sourceTypes, $sourceTypes),
sprintf('Cannot find a matching transformer for mapping the source types "%s" to the target types "%s".', $sourceTypes, $targetTypes),
context: $context
);
}
Expand Down
8 changes: 4 additions & 4 deletions src/MainTransformer/MainTransformer.php
Original file line number Diff line number Diff line change
Expand Up @@ -111,14 +111,14 @@ public function transform(
$context = $context->with($pathContext->append($path));
}

// gets simple target types from the provided target type

$targetTypes = $this->getSimpleTypes($targetTypes);

// guess the source type

$sourceTypes = [$this->typeResolver->guessTypeFromVariable($source)];

// gets simple target types from the provided target type

$targetTypes = $this->getSimpleTypes($targetTypes);

// search for the matching transformers according to the source and
// target types

Expand Down
26 changes: 13 additions & 13 deletions src/Mapping/Mapping.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@

namespace Rekalogika\Mapper\Mapping;

use Rekalogika\Mapper\Transformer\Contracts\MixedType;
use Symfony\Component\PropertyInfo\Type;

/**
* @implements \IteratorAggregate<int,MappingEntry>
*/
Expand All @@ -36,18 +39,24 @@ public function getIterator(): \Traversable
public function addEntry(
string $id,
string $class,
string $sourceType,
string $targetType
Type|MixedType $sourceType,
Type|MixedType $targetType,
string $sourceTypeString,
string $targetTypeString,
bool $variantTargetType,
): void {
$entry = new MappingEntry(
id: $id,
class: $class,
sourceType: $sourceType,
targetType: $targetType
targetType: $targetType,
sourceTypeString: $sourceTypeString,
targetTypeString: $targetTypeString,
variantTargetType: $variantTargetType,
);

$this->entries[$entry->getOrder()] = $entry;
$this->mappingBySourceAndTarget[$sourceType][$targetType][] = $entry;
$this->mappingBySourceAndTarget[$sourceTypeString][$targetTypeString][] = $entry;
}

/**
Expand All @@ -71,15 +80,6 @@ public function getMappingBySourceAndTarget(
}
}

// sort by order

usort(
$result,
fn (MappingEntry $a, MappingEntry $b)
=>
$a->getOrder() <=> $b->getOrder()
);

return $result;
}
}
29 changes: 25 additions & 4 deletions src/Mapping/MappingEntry.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@

namespace Rekalogika\Mapper\Mapping;

use Rekalogika\Mapper\Transformer\Contracts\MixedType;
use Symfony\Component\PropertyInfo\Type;

final class MappingEntry
{
private static int $counter = 0;
Expand All @@ -21,8 +24,11 @@ final class MappingEntry
public function __construct(
private string $id,
private string $class,
private string $sourceType,
private string $targetType,
private Type|MixedType $sourceType,
private Type|MixedType $targetType,
private string $sourceTypeString,
private string $targetTypeString,
private bool $variantTargetType,
) {
$this->order = ++self::$counter;
}
Expand All @@ -42,13 +48,28 @@ public function getClass(): string
return $this->class;
}

public function getSourceType(): string
public function isVariantTargetType(): bool
{
return $this->variantTargetType;
}

public function getSourceType(): Type|MixedType
{
return $this->sourceType;
}

public function getTargetType(): string
public function getTargetType(): Type|MixedType
{
return $this->targetType;
}

public function getSourceTypeString(): string
{
return $this->sourceTypeString;
}

public function getTargetTypeString(): string
{
return $this->targetTypeString;
}
}
8 changes: 6 additions & 2 deletions src/Mapping/MappingFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ private function addMapping(
foreach ($transformer->getSupportedTransformation() as $typeMapping) {
$sourceTypes = $this->getSimpleTypes($typeMapping->getSourceType());
$targetTypes = $this->getSimpleTypes($typeMapping->getTargetType());
$isVariantTargetType = $typeMapping->isVariantTargetType();

foreach ($sourceTypes as $sourceType) {
foreach ($targetTypes as $targetType) {
Expand All @@ -75,8 +76,11 @@ private function addMapping(
$mapping->addEntry(
id: $id,
class: get_class($transformer),
sourceType: $sourceTypeString,
targetType: $targetTypeString
sourceType: $sourceType,
targetType: $targetType,
sourceTypeString: $sourceTypeString,
targetTypeString: $targetTypeString,
variantTargetType: $isVariantTargetType,
);
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/MethodMapper/ClassMethodTransformer.php
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,13 @@ public function getSupportedTransformation(): iterable
yield new TypeMapping(
TypeFactory::objectOfClass(MapToObjectInterface::class),
TypeFactory::object(),
true,
);

yield new TypeMapping(
TypeFactory::object(),
TypeFactory::objectOfClass(MapFromObjectInterface::class),
true,
);
}
}
2 changes: 1 addition & 1 deletion src/Transformer/ArrayToObjectTransformer.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,6 @@ public function transform(

public function getSupportedTransformation(): iterable
{
yield new TypeMapping(TypeFactory::array(), TypeFactory::object());
yield new TypeMapping(TypeFactory::array(), TypeFactory::object(), true);
}
}
6 changes: 6 additions & 0 deletions src/Transformer/Contracts/TypeMapping.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class TypeMapping
public function __construct(
private Type|MixedType $sourceType,
private Type|MixedType $targetType,
private bool $variantTargetType = false,
) {
}

Expand All @@ -42,4 +43,9 @@ public function getTargetType(): Type|MixedType
{
return $this->targetType;
}

public function isVariantTargetType(): bool
{
return $this->variantTargetType;
}
}
3 changes: 2 additions & 1 deletion src/Transformer/InheritanceMapTransformer.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,8 @@ public function getSupportedTransformation(): iterable
{
yield new TypeMapping(
TypeFactory::object(),
TypeFactory::objectOfClass(InheritanceMap::class)
TypeFactory::objectOfClass(InheritanceMap::class),
true
);
}
}
4 changes: 2 additions & 2 deletions src/Transformer/ObjectToObjectTransformer.php
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ private function resolveTargetPropertyValue(

public function getSupportedTransformation(): iterable
{
yield new TypeMapping(TypeFactory::object(), TypeFactory::object());
yield new TypeMapping(TypeFactory::object(), TypeFactory::object(), true);
}

protected function instantiateTarget(
Expand All @@ -216,7 +216,7 @@ protected function instantiateTarget(
$reflectionClass = new \ReflectionClass($targetClass);

if (!$reflectionClass->isInstantiable()) {
throw new ClassNotInstantiableException($targetClass);
throw new ClassNotInstantiableException($targetClass, context: $context);
}

$initializableTargetProperties = $this
Expand Down
1 change: 1 addition & 0 deletions src/Transformer/StringToBackedEnumTransformer.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ public function getSupportedTransformation(): iterable
yield new TypeMapping(
TypeFactory::string(),
TypeFactory::objectOfClass(\BackedEnum::class),
true,
);
}
}
2 changes: 2 additions & 0 deletions src/Transformer/TraversableToArrayAccessTransformer.php
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,8 @@ public function getSupportedTransformation(): iterable
];

$targetTypes = [
TypeFactory::objectOfClass(Collection::class),
TypeFactory::objectOfClass(\ArrayObject::class),
TypeFactory::objectOfClass(\ArrayAccess::class),
TypeFactory::array(),
];
Expand Down
12 changes: 12 additions & 0 deletions src/TransformerRegistry/SearchResultEntry.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ public function __construct(
private Type|MixedType $sourceType,
private Type|MixedType $targetType,
private TransformerInterface $transformer,
private string $transformerServiceId,
private bool $variantTargetType,
) {
}

Expand All @@ -46,4 +48,14 @@ public function getMappingOrder(): int
{
return $this->mappingOrder;
}

public function isVariantTargetType(): bool
{
return $this->variantTargetType;
}

public function getTransformerServiceId(): string
{
return $this->transformerServiceId;
}
}
Loading

0 comments on commit 20f10ce

Please sign in to comment.