Skip to content

Commit

Permalink
perf: Use our PropertyAccessLite instead of Symfony's.
Browse files Browse the repository at this point in the history
  • Loading branch information
priyadi committed Jan 17, 2024
1 parent 9f85c41 commit 186885d
Show file tree
Hide file tree
Showing 8 changed files with 391 additions and 11 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* perf: Optimize `guessTypeFromVariable`
* perf: Optimize `Context` & `ObjectCache`
* perf: Change 'simpletypes' cache to array.
* perf: Use our `PropertyAccessLite` instead of Symfony's.

## 0.5.14

Expand Down
8 changes: 7 additions & 1 deletion config/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
use Rekalogika\Mapper\MethodMapper\ClassMethodTransformer;
use Rekalogika\Mapper\MethodMapper\SubMapper;
use Rekalogika\Mapper\ObjectCache\ObjectCacheFactory;
use Rekalogika\Mapper\PropertyAccessLite\PropertyAccessLite;
use Rekalogika\Mapper\Transformer\ArrayToObjectTransformer;
use Rekalogika\Mapper\Transformer\CopyTransformer;
use Rekalogika\Mapper\Transformer\DateTimeTransformer;
Expand Down Expand Up @@ -138,7 +139,7 @@
$services
->set(ObjectToObjectTransformer::class)
->args([
'$propertyAccessor' => service('property_accessor'),
'$propertyAccessor' => service('rekalogika.mapper.property_access_lite'),
'$typeResolver' => service('rekalogika.mapper.type_resolver'),
'$objectMappingResolver' => service('rekalogika.mapper.object_mapping_resolver'),
])
Expand Down Expand Up @@ -174,6 +175,11 @@
])
->tag('kernel.cache_warmer');

# propertyaccess lite

$services
->set('rekalogika.mapper.property_access_lite', PropertyAccessLite::class);

# type resolver

$services
Expand Down
5 changes: 5 additions & 0 deletions psalm.xml
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,10 @@
<file name="src/Context/Context.php" />
</errorLevel>
</InvalidReturnType>
<MissingConstructor>
<errorLevel type="suppress">
<file name="tests/Fixtures/AccessMethods/ObjectWithVariousAccessMethods.php" />
</errorLevel>
</MissingConstructor>
</issueHandlers>
</psalm>
27 changes: 20 additions & 7 deletions src/MapperFactory/MapperFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
use Rekalogika\Mapper\MethodMapper\SubMapper;
use Rekalogika\Mapper\ObjectCache\ObjectCacheFactory;
use Rekalogika\Mapper\ObjectCache\ObjectCacheFactoryInterface;
use Rekalogika\Mapper\PropertyAccessLite\PropertyAccessLite;
use Rekalogika\Mapper\Transformer\ArrayToObjectTransformer;
use Rekalogika\Mapper\Transformer\Contracts\TransformerInterface;
use Rekalogika\Mapper\Transformer\CopyTransformer;
Expand All @@ -49,16 +50,16 @@
use Rekalogika\Mapper\TypeResolver\TypeResolverInterface;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use Symfony\Component\Console\Application;
use Symfony\Component\PropertyAccess\PropertyAccess;
use Symfony\Component\PropertyAccess\PropertyAccessor;
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
use Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor;
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
use Symfony\Component\PropertyInfo\PropertyInfoCacheExtractor;
use Symfony\Component\PropertyInfo\PropertyInfoExtractor;
use Symfony\Component\PropertyInfo\PropertyInfoExtractorInterface;
use Symfony\Component\PropertyInfo\PropertyInitializableExtractorInterface;
use Symfony\Component\PropertyInfo\PropertyReadInfoExtractorInterface;
use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface;
use Symfony\Component\PropertyInfo\PropertyWriteInfoExtractorInterface;
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
use Symfony\Component\Serializer\Mapping\Loader\AttributeLoader;
use Symfony\Component\Serializer\Normalizer\BackedEnumNormalizer;
Expand Down Expand Up @@ -114,7 +115,7 @@ public function __construct(
private array $additionalTransformers = [],
private ?ReflectionExtractor $reflectionExtractor = null,
private ?PhpStanExtractor $phpStanExtractor = null,
private ?PropertyAccessor $propertyAccessor = null,
private ?PropertyAccessorInterface $propertyAccessor = null,
private ?NormalizerInterface $normalizer = null,
private ?DenormalizerInterface $denormalizer = null,
?CacheItemPoolInterface $propertyInfoExtractorCache = null,
Expand Down Expand Up @@ -153,6 +154,16 @@ private function getPhpStanExtractor(): PropertyTypeExtractorInterface
return $this->phpStanExtractor;
}

private function getPropertyReadInfoExtractor(): PropertyReadInfoExtractorInterface
{
return $this->getReflectionExtractor();
}

private function getPropertyWriteInfoExtractor(): PropertyWriteInfoExtractorInterface
{
return $this->getReflectionExtractor();
}

private function getPropertyInfoExtractor(): PropertyInfoExtractorInterface&PropertyInitializableExtractorInterface
{
if ($this->propertyInfoExtractor === null) {
Expand Down Expand Up @@ -188,7 +199,7 @@ private function getPropertyInfoExtractor(): PropertyInfoExtractorInterface&Prop
private function getConcretePropertyAccessor(): PropertyAccessorInterface
{
if (null === $this->propertyAccessor) {
$this->propertyAccessor = PropertyAccess::createPropertyAccessor();
$this->propertyAccessor = new PropertyAccessLite();
}

return $this->propertyAccessor;
Expand Down Expand Up @@ -258,9 +269,9 @@ protected function getObjectToObjectTransformer(): TransformerInterface
{
if (null === $this->objectToObjectTransformer) {
$this->objectToObjectTransformer = new ObjectToObjectTransformer(
$this->getPropertyAccessor(),
$this->getTypeResolver(),
$this->getObjectMappingResolver(),
propertyAccessor: $this->getPropertyAccessor(),
typeResolver: $this->getTypeResolver(),
objectMappingResolver: $this->getObjectMappingResolver(),
);
}

Expand Down Expand Up @@ -395,6 +406,8 @@ protected function getObjectMappingResolver(): ObjectMappingResolverInterface
$this->getPropertyInfoExtractor(),
$this->getPropertyInfoExtractor(),
$this->getPropertyInfoExtractor(),
$this->getPropertyReadInfoExtractor(),
$this->getPropertyWriteInfoExtractor(),
);
}

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

use Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException;
use Symfony\Component\PropertyAccess\Exception\UninitializedPropertyException;
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
use Symfony\Component\PropertyAccess\PropertyPathInterface;

final class PropertyAccessLite implements PropertyAccessorInterface
{
/**
* @param object|array<array-key,mixed> $objectOrArray
*/
public function getValue(
object|array $objectOrArray,
string|PropertyPathInterface $propertyPath,
): mixed {
assert(is_string($propertyPath));
assert(\is_object($objectOrArray));

$getter = 'get' . ucfirst($propertyPath);

try {
/** @psalm-suppress MixedMethodCall */
return $objectOrArray->{$getter}();
} catch (\Throwable $e) {
if (!\str_starts_with($e->getMessage(), 'Call to undefined method')) {
if (\str_starts_with($e->getMessage(), 'Typed property')) {
throw new UninitializedPropertyException(\sprintf(
'Property "%s" is not initialized in object "%s"',
$propertyPath,
\get_class($objectOrArray),
), 0, $e);
}

throw $e;
}
}

try {
return $objectOrArray->{$propertyPath};
// @phpstan-ignore-next-line
} catch (\Throwable $e) {
if (\str_starts_with($e->getMessage(), 'Typed property')) {
throw new UninitializedPropertyException(\sprintf(
'Property "%s" is not initialized in object "%s"',
$propertyPath,
\get_class($objectOrArray),
), 0, $e);
} elseif (\str_starts_with($e->getMessage(), 'Cannot access private property')) {
throw new NoSuchPropertyException(\sprintf(
'Property "%s" is not public in object "%s"',
$propertyPath,
\get_class($objectOrArray),
), 0, $e);
} elseif (\str_starts_with($e->getMessage(), 'Undefined property')) {
throw new NoSuchPropertyException(\sprintf(
'Property "%s" is not defined in object "%s"',
$propertyPath,
\get_class($objectOrArray),
), 0, $e);
}

throw $e;
}
}

/**
* @param object|array<array-key,mixed> $objectOrArray
*/
public function setValue(
object|array &$objectOrArray,
string|PropertyPathInterface $propertyPath,
mixed $value
): void {
assert(is_string($propertyPath));
assert(\is_object($objectOrArray));

$setter = 'set' . ucfirst($propertyPath);

try {
/** @psalm-suppress MixedMethodCall */
$objectOrArray->{$setter}($value);
return;
} catch (\Throwable $e) {
if (!\str_starts_with($e->getMessage(), 'Call to undefined method')) {
throw $e;
}
}

try {
if (!\property_exists($objectOrArray, $propertyPath)) {
throw new NoSuchPropertyException(\sprintf(
'Property "%s" is not defined in object "%s"',
$propertyPath,
\get_class($objectOrArray),
));
}
$objectOrArray->{$propertyPath} = $value;
} catch (NoSuchPropertyException $e) {
throw $e;
} catch (\Throwable $e) {
if (\str_starts_with($e->getMessage(), 'Cannot access private property')) {
throw new NoSuchPropertyException(\sprintf(
'Property "%s" is not public in object "%s"',
$propertyPath,
\get_class($objectOrArray),
), 0, $e);
}

throw $e;
}
}

/**
* @param object|array<array-key,mixed> $objectOrArray
*/
public function isWritable(
object|array $objectOrArray,
string|PropertyPathInterface $propertyPath
): bool {
throw new \RuntimeException('Not implemented');
}

/**
* @param object|array<array-key,mixed> $objectOrArray
*/
public function isReadable(
object|array $objectOrArray,
string|PropertyPathInterface $propertyPath
): bool {
throw new \RuntimeException('Not implemented');
}
}
55 changes: 52 additions & 3 deletions src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
use Symfony\Component\PropertyInfo\PropertyAccessExtractorInterface;
use Symfony\Component\PropertyInfo\PropertyInitializableExtractorInterface;
use Symfony\Component\PropertyInfo\PropertyListExtractorInterface;
use Symfony\Component\PropertyInfo\PropertyReadInfoExtractorInterface;
use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface;
use Symfony\Component\PropertyInfo\PropertyWriteInfoExtractorInterface;

final class ObjectMappingResolver implements ObjectMappingResolverInterface
{
Expand All @@ -31,6 +33,8 @@ public function __construct(
private PropertyListExtractorInterface $propertyListExtractor,
private PropertyInitializableExtractorInterface $propertyInitializableExtractor,
private PropertyTypeExtractorInterface $propertyTypeExtractor,
private PropertyReadInfoExtractorInterface $propertyReadInfoExtractor,
private PropertyWriteInfoExtractorInterface $propertyWriteInfoExtractor,
) {
}

Expand Down Expand Up @@ -75,10 +79,55 @@ public function resolveObjectMapping(
);
}

$sourcePropertyReadInfo = $this->propertyReadInfoExtractor
->getReadInfo($sourceClass, $sourceProperty);

if (null === $sourcePropertyReadInfo) {
throw new InvalidArgumentException(
sprintf(
'Cannot get read info of source property "%s::$%s".',
$sourceClass,
$sourceProperty
),
context: $context
);
}

$targetPropertyReadInfo = $this->propertyReadInfoExtractor
->getReadInfo($targetClass, $targetProperty);

if (null === $targetPropertyReadInfo) {
throw new InvalidArgumentException(
sprintf(
'Cannot get read info of target property "%s::$%s".',
$targetClass,
$targetProperty
),
context: $context
);
}

$targetPropertyWriteInfo = $this->propertyWriteInfoExtractor
->getWriteInfo($targetClass, $targetProperty);

if (null === $targetPropertyWriteInfo) {
throw new InvalidArgumentException(
sprintf(
'Cannot get write info of target property "%s::$%s".',
$targetClass,
$targetProperty
),
context: $context
);
}

$propertyResults[] = new PropertyMapping(

Check failure on line 124 in src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php

View workflow job for this annotation

GitHub Actions / Symfony 6.4.*, highest deps, PHP 8.2, ubuntu-latest

TooManyArguments

src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php:124:34: TooManyArguments: Too many arguments for Rekalogika\Mapper\Transformer\ObjectMappingResolver\Contracts\PropertyMapping::__construct - expecting 3 but saw 6 (see https://psalm.dev/026)

Check failure on line 124 in src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php

View workflow job for this annotation

GitHub Actions / Symfony 7.*, highest deps, PHP 8.2, ubuntu-latest

TooManyArguments

src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php:124:34: TooManyArguments: Too many arguments for Rekalogika\Mapper\Transformer\ObjectMappingResolver\Contracts\PropertyMapping::__construct - expecting 3 but saw 6 (see https://psalm.dev/026)

Check failure on line 124 in src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php

View workflow job for this annotation

GitHub Actions / Symfony 7.*, lowest deps, PHP 8.2, ubuntu-latest

TooManyArguments

src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php:124:34: TooManyArguments: Too many arguments for Rekalogika\Mapper\Transformer\ObjectMappingResolver\Contracts\PropertyMapping::__construct - expecting 3 but saw 6 (see https://psalm.dev/026)

Check failure on line 124 in src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php

View workflow job for this annotation

GitHub Actions / Symfony 6.4.*, highest deps, PHP 8.3, ubuntu-latest

TooManyArguments

src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php:124:34: TooManyArguments: Too many arguments for Rekalogika\Mapper\Transformer\ObjectMappingResolver\Contracts\PropertyMapping::__construct - expecting 3 but saw 6 (see https://psalm.dev/026)

Check failure on line 124 in src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php

View workflow job for this annotation

GitHub Actions / Symfony 6.4.*, lowest deps, PHP 8.3, ubuntu-latest

TooManyArguments

src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php:124:34: TooManyArguments: Too many arguments for Rekalogika\Mapper\Transformer\ObjectMappingResolver\Contracts\PropertyMapping::__construct - expecting 3 but saw 6 (see https://psalm.dev/026)
$sourceProperty,
$targetProperty,
$targetPropertyTypes,
sourceProperty: $sourceProperty,
targetProperty: $targetProperty,
targetTypes: $targetPropertyTypes,
sourcePropertyReadInfo: $sourcePropertyReadInfo,

Check failure on line 128 in src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php

View workflow job for this annotation

GitHub Actions / Symfony 6.4.*, highest deps, PHP 8.2, ubuntu-latest

InvalidNamedArgument

src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php:128:17: InvalidNamedArgument: Parameter $sourcePropertyReadInfo does not exist on function Rekalogika\Mapper\Transformer\ObjectMappingResolver\Contracts\PropertyMapping::__construct (see https://psalm.dev/238)

Check failure on line 128 in src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php

View workflow job for this annotation

GitHub Actions / Symfony 7.*, highest deps, PHP 8.2, ubuntu-latest

InvalidNamedArgument

src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php:128:17: InvalidNamedArgument: Parameter $sourcePropertyReadInfo does not exist on function Rekalogika\Mapper\Transformer\ObjectMappingResolver\Contracts\PropertyMapping::__construct (see https://psalm.dev/238)

Check failure on line 128 in src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php

View workflow job for this annotation

GitHub Actions / Symfony 7.*, lowest deps, PHP 8.2, ubuntu-latest

InvalidNamedArgument

src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php:128:17: InvalidNamedArgument: Parameter $sourcePropertyReadInfo does not exist on function Rekalogika\Mapper\Transformer\ObjectMappingResolver\Contracts\PropertyMapping::__construct (see https://psalm.dev/238)

Check failure on line 128 in src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php

View workflow job for this annotation

GitHub Actions / Symfony 6.4.*, highest deps, PHP 8.3, ubuntu-latest

InvalidNamedArgument

src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php:128:17: InvalidNamedArgument: Parameter $sourcePropertyReadInfo does not exist on function Rekalogika\Mapper\Transformer\ObjectMappingResolver\Contracts\PropertyMapping::__construct (see https://psalm.dev/238)

Check failure on line 128 in src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php

View workflow job for this annotation

GitHub Actions / Symfony 6.4.*, lowest deps, PHP 8.3, ubuntu-latest

InvalidNamedArgument

src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php:128:17: InvalidNamedArgument: Parameter $sourcePropertyReadInfo does not exist on function Rekalogika\Mapper\Transformer\ObjectMappingResolver\Contracts\PropertyMapping::__construct (see https://psalm.dev/238)
targetPropertyReadInfo: $targetPropertyReadInfo,

Check failure on line 129 in src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php

View workflow job for this annotation

GitHub Actions / Symfony 6.4.*, highest deps, PHP 8.2, ubuntu-latest

InvalidNamedArgument

src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php:129:17: InvalidNamedArgument: Parameter $targetPropertyReadInfo does not exist on function Rekalogika\Mapper\Transformer\ObjectMappingResolver\Contracts\PropertyMapping::__construct (see https://psalm.dev/238)

Check failure on line 129 in src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php

View workflow job for this annotation

GitHub Actions / Symfony 7.*, highest deps, PHP 8.2, ubuntu-latest

InvalidNamedArgument

src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php:129:17: InvalidNamedArgument: Parameter $targetPropertyReadInfo does not exist on function Rekalogika\Mapper\Transformer\ObjectMappingResolver\Contracts\PropertyMapping::__construct (see https://psalm.dev/238)

Check failure on line 129 in src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php

View workflow job for this annotation

GitHub Actions / Symfony 7.*, lowest deps, PHP 8.2, ubuntu-latest

InvalidNamedArgument

src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php:129:17: InvalidNamedArgument: Parameter $targetPropertyReadInfo does not exist on function Rekalogika\Mapper\Transformer\ObjectMappingResolver\Contracts\PropertyMapping::__construct (see https://psalm.dev/238)

Check failure on line 129 in src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php

View workflow job for this annotation

GitHub Actions / Symfony 6.4.*, highest deps, PHP 8.3, ubuntu-latest

InvalidNamedArgument

src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php:129:17: InvalidNamedArgument: Parameter $targetPropertyReadInfo does not exist on function Rekalogika\Mapper\Transformer\ObjectMappingResolver\Contracts\PropertyMapping::__construct (see https://psalm.dev/238)

Check failure on line 129 in src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php

View workflow job for this annotation

GitHub Actions / Symfony 6.4.*, lowest deps, PHP 8.3, ubuntu-latest

InvalidNamedArgument

src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php:129:17: InvalidNamedArgument: Parameter $targetPropertyReadInfo does not exist on function Rekalogika\Mapper\Transformer\ObjectMappingResolver\Contracts\PropertyMapping::__construct (see https://psalm.dev/238)
targetPropertyWriteInfo: $targetPropertyWriteInfo,

Check failure on line 130 in src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php

View workflow job for this annotation

GitHub Actions / Symfony 6.4.*, highest deps, PHP 8.2, ubuntu-latest

InvalidNamedArgument

src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php:130:17: InvalidNamedArgument: Parameter $targetPropertyWriteInfo does not exist on function Rekalogika\Mapper\Transformer\ObjectMappingResolver\Contracts\PropertyMapping::__construct (see https://psalm.dev/238)

Check failure on line 130 in src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php

View workflow job for this annotation

GitHub Actions / Symfony 7.*, highest deps, PHP 8.2, ubuntu-latest

InvalidNamedArgument

src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php:130:17: InvalidNamedArgument: Parameter $targetPropertyWriteInfo does not exist on function Rekalogika\Mapper\Transformer\ObjectMappingResolver\Contracts\PropertyMapping::__construct (see https://psalm.dev/238)

Check failure on line 130 in src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php

View workflow job for this annotation

GitHub Actions / Symfony 7.*, lowest deps, PHP 8.2, ubuntu-latest

InvalidNamedArgument

src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php:130:17: InvalidNamedArgument: Parameter $targetPropertyWriteInfo does not exist on function Rekalogika\Mapper\Transformer\ObjectMappingResolver\Contracts\PropertyMapping::__construct (see https://psalm.dev/238)

Check failure on line 130 in src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php

View workflow job for this annotation

GitHub Actions / Symfony 6.4.*, highest deps, PHP 8.3, ubuntu-latest

InvalidNamedArgument

src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php:130:17: InvalidNamedArgument: Parameter $targetPropertyWriteInfo does not exist on function Rekalogika\Mapper\Transformer\ObjectMappingResolver\Contracts\PropertyMapping::__construct (see https://psalm.dev/238)

Check failure on line 130 in src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php

View workflow job for this annotation

GitHub Actions / Symfony 6.4.*, lowest deps, PHP 8.3, ubuntu-latest

InvalidNamedArgument

src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php:130:17: InvalidNamedArgument: Parameter $targetPropertyWriteInfo does not exist on function Rekalogika\Mapper\Transformer\ObjectMappingResolver\Contracts\PropertyMapping::__construct (see https://psalm.dev/238)
);
}

Expand Down
Loading

0 comments on commit 186885d

Please sign in to comment.