Skip to content

Commit

Permalink
feat: extra target values
Browse files Browse the repository at this point in the history
  • Loading branch information
priyadi committed Oct 12, 2024
1 parent feed0d4 commit 2a9c2a7
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
* perf: `ObjectToObjectTransformer` optimization
* perf: move `TypeResolver` outside of the hot path
* perf(`ObjectCache`): use sentinel value instead of exception
* feat: extra target values

## 1.10.0

Expand Down
44 changes: 44 additions & 0 deletions src/Context/ExtraTargetValues.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?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\Context;

/**
* Adds additional values to the target object
*/
final readonly class ExtraTargetValues
{
/**
* @param array<class-string,array<string,mixed>> $arguments
*/
public function __construct(
private array $arguments = [],
) {}

/**
* @param list<class-string> $classes The class and its parent classes and interfaces.
* @return array<string,mixed>
*/
public function getArgumentsForClass(array $classes): array
{
$arguments = [];

foreach ($classes as $class) {
if (isset($this->arguments[$class])) {
$arguments = array_merge($arguments, $this->arguments[$class]);
}
}

return $arguments;
}
}
12 changes: 12 additions & 0 deletions src/Transformer/Implementation/ObjectToObjectTransformer.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use Rekalogika\Mapper\CacheWarmer\WarmableObjectToObjectMetadataFactoryInterface;
use Rekalogika\Mapper\CacheWarmer\WarmableTransformerInterface;
use Rekalogika\Mapper\Context\Context;
use Rekalogika\Mapper\Context\ExtraTargetValues;
use Rekalogika\Mapper\Context\MapperOptions;
use Rekalogika\Mapper\Exception\InvalidArgumentException;
use Rekalogika\Mapper\ObjectCache\ObjectCache;
Expand All @@ -42,6 +43,7 @@
use Rekalogika\Mapper\Transformer\TransformerInterface;
use Rekalogika\Mapper\Transformer\TypeMapping;
use Rekalogika\Mapper\Transformer\Util\ReaderWriter;
use Rekalogika\Mapper\Util\ClassUtil;
use Rekalogika\Mapper\Util\TypeFactory;
use Rekalogika\Mapper\Util\TypeGuesser;
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
Expand Down Expand Up @@ -379,6 +381,16 @@ private function generateConstructorArguments(
}
}

if (($extraTargetValues = $context(ExtraTargetValues::class)) !== null) {
$targetValues = $extraTargetValues
->getArgumentsForClass(ClassUtil::getAllClassesFromObject($objectToObjectMetadata->getTargetClass()));

/** @var mixed $value */
foreach ($targetValues as $property => $value) {
$constructorArguments->addArgument($property, $value);
}
}

return $constructorArguments;
}

Expand Down
2 changes: 1 addition & 1 deletion src/Util/ClassUtil.php
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ public static function getSkippedProperties(

/**
* @param object|class-string $objectOrClass
* @return array<int,class-string>
* @return list<class-string>
*/
public static function getAllClassesFromObject(
object|string $objectOrClass,
Expand Down
6 changes: 6 additions & 0 deletions tests/config/rekalogika-mapper/generated-mappings.php
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,12 @@
target: \Rekalogika\Mapper\Tests\Fixtures\EnumAndStringableDto\ObjectWithStringPropertyDto::class
);

$mappingCollection->addObjectMapping(
// tests/src/IntegrationTest/ExtraTargetValuesTest.php on line 26
source: \Rekalogika\Mapper\Tests\Fixtures\ExtraTargetValues\SomeObject::class,
target: \Rekalogika\Mapper\Tests\Fixtures\ExtraTargetValues\SomeObjectWithConstructorDto::class
);

$mappingCollection->addObjectMapping(
// tests/src/IntegrationTest/InheritanceReversedTest.php on line 29
source: \Rekalogika\Mapper\Tests\Fixtures\InheritanceDto\ConcreteClassADto::class,
Expand Down
19 changes: 19 additions & 0 deletions tests/src/Fixtures/ExtraTargetValues/SomeObject.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?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\Tests\Fixtures\ExtraTargetValues;

class SomeObject
{
public string $property = 'someProperty';
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?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\Tests\Fixtures\ExtraTargetValues;

final readonly class SomeObjectWithConstructorDto
{
public function __construct(
public string $property,
public ?\DateTimeInterface $date,
) {}
}
42 changes: 42 additions & 0 deletions tests/src/IntegrationTest/ExtraTargetValuesTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?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\Tests\IntegrationTest;

use Rekalogika\Mapper\Context\Context;
use Rekalogika\Mapper\Context\ExtraTargetValues;
use Rekalogika\Mapper\Tests\Common\FrameworkTestCase;
use Rekalogika\Mapper\Tests\Fixtures\ExtraTargetValues\SomeObject;
use Rekalogika\Mapper\Tests\Fixtures\ExtraTargetValues\SomeObjectWithConstructorDto;

class ExtraTargetValuesTest extends FrameworkTestCase
{
public function testExtraArgumentsOnTargetConstructor(): void
{
$target = $this->mapper->map(
source: new SomeObject(),
target: SomeObjectWithConstructorDto::class,
context: Context::create(
new ExtraTargetValues([
SomeObjectWithConstructorDto::class => [
'date' => new \DateTimeImmutable('2021-01-01'),
],
]),
),
);

$this->assertSame('someProperty', $target->property);
$this->assertInstanceOf(\DateTimeImmutable::class, $target->date);
$this->assertSame('2021-01-01', $target->date->format('Y-m-d'));
}
}

0 comments on commit 2a9c2a7

Please sign in to comment.