From 52dc2383ae65e98a224999cc2b3747d608ba63da Mon Sep 17 00:00:00 2001 From: Ilya Orlov Date: Thu, 12 Sep 2024 21:26:09 +0500 Subject: [PATCH] fix: constructor with default parameter array does not work with context --- CHANGELOG.md | 1 + .../CreateTargetStatementsGenerator.php | 18 +++++++++++------- tests/AutoMapperTest.php | 13 +++++++++++++ 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 302b4b3..27144d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - [GH#184](https://github.com/jolicode/automapper/pull/184) Fix error when mapping from stdClass to constructor with nullable/optional arguments +- [GH#185](https://github.com/jolicode/automapper/pull/185) Fix constructor with default parameter array does not work with constructor_arguments context ## [9.1.2] - 2024-09-03 ### Fixed diff --git a/src/Generator/CreateTargetStatementsGenerator.php b/src/Generator/CreateTargetStatementsGenerator.php index 3a04dad..be8fa27 100644 --- a/src/Generator/CreateTargetStatementsGenerator.php +++ b/src/Generator/CreateTargetStatementsGenerator.php @@ -206,11 +206,15 @@ private function constructorArgument(GeneratorMetadata $metadata, PropertyMetada } if ($defaultValueExpr instanceof Expr\Array_) { - // $constructarg_3 = count($values) > 0 ? $values : array(); - $argumentAssignedValue = new Expr\Ternary(new Expr\BinaryOp\Greater(new Expr\FuncCall(new Name('count'), [new Arg($output)]), create_scalar_int(0)), $output, $defaultValueExpr); + // $constructarg = count($values) > 0 ? $values : {expression}; + $argumentAssignClosure = static fn (Expr $expr) => new Expr\Assign($constructVar, new Expr\Ternary( + new Expr\BinaryOp\Greater(new Expr\FuncCall(new Name('count'), [new Arg($output)]), create_scalar_int(0)), + $output, + $expr, + )); } else { - // $constructarg_0 = $values ?? array(); - $argumentAssignedValue = new Expr\BinaryOp\Coalesce($output, $defaultValueExpr); + // $constructarg = $values ?? {expression}; + $argumentAssignClosure = static fn (Expr $expr) => new Expr\Assign($constructVar, new Expr\BinaryOp\Coalesce($output, $expr)); } return [ @@ -221,15 +225,15 @@ private function constructorArgument(GeneratorMetadata $metadata, PropertyMetada ]), [ 'stmts' => [ ...$propStatements, - new Stmt\Expression(new Expr\Assign($constructVar, new Expr\BinaryOp\Coalesce($output, new Expr\StaticCall(new Name\FullyQualified(MapperContext::class), 'getConstructorArgument', [ + new Stmt\Expression($argumentAssignClosure(new Expr\StaticCall(new Name\FullyQualified(MapperContext::class), 'getConstructorArgument', [ new Arg($variableRegistry->getContext()), new Arg(new Scalar\String_($metadata->mapperMetadata->target)), new Arg(new Scalar\String_($propertyMetadata->target->property)), - ])))), + ]))), ], 'else' => new Stmt\Else_([ ...$propStatements, - new Stmt\Expression(new Expr\Assign($constructVar, $argumentAssignedValue)), + new Stmt\Expression($argumentAssignClosure($defaultValueExpr)), ]), ]), new Arg($constructVar, name: new Identifier($parameter->getName())), diff --git a/tests/AutoMapperTest.php b/tests/AutoMapperTest.php index 2b30c20..fc79223 100644 --- a/tests/AutoMapperTest.php +++ b/tests/AutoMapperTest.php @@ -469,6 +469,19 @@ public function testConstructor(): void self::assertTrue($userDto->getConstructor()); } + public function testConstructorArrayArgumentFromContext(): void + { + $data = ['baz' => 'baz']; + /** @var ConstructorWithDefaultValues $userDto */ + $object = $this->autoMapper->map($data, ConstructorWithDefaultValues::class, [MapperContext::CONSTRUCTOR_ARGUMENTS => [ + ConstructorWithDefaultValues::class => ['someOtters' => [1]], + ]]); + + self::assertInstanceOf(ConstructorWithDefaultValues::class, $object); + self::assertSame('baz', $object->baz); + self::assertSame([1], $object->someOtters); + } + public function testConstructorNotAllowed(): void { $this->buildAutoMapper(mapPrivatePropertiesAndMethod: true, constructorStrategy: ConstructorStrategy::NEVER, classPrefix: 'NotAllowedMapper_');