Skip to content

Commit ea046a5

Browse files
authored
fix(constructor): reuse old behavior with isset where it make sense (#236)
2 parents 7747e2b + f769328 commit ea046a5

File tree

4 files changed

+71
-8
lines changed

4 files changed

+71
-8
lines changed

src/Extractor/ReadAccessor.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,59 @@ public function getExpression(Expr\Variable $input): Expr
154154
throw new CompileException('Invalid accessor for read expression');
155155
}
156156

157+
public function getIsDefinedExpression(Expr\Variable $input, bool $nullable = false): ?Expr
158+
{
159+
// It is not possible to check if the underlying data is defined, assumes it is, php will throw an error if it is not
160+
if (!$nullable && \in_array($this->type, [self::TYPE_METHOD, self::TYPE_SOURCE])) {
161+
return null;
162+
}
163+
164+
if (self::TYPE_PROPERTY === $this->type) {
165+
if ($this->private) {
166+
/*
167+
* When the property is private we use the extract callback that can read this value
168+
*
169+
* @see \AutoMapper\Extractor\ReadAccessor::getExtractIsUndefinedCallback()
170+
*
171+
* !$this->extractIsUndefinedCallbacks['property_name']($input)
172+
*/
173+
return new Expr\BooleanNot(new Expr\FuncCall(
174+
new Expr\ArrayDimFetch(new Expr\PropertyFetch(new Expr\Variable('this'), 'extractIsUndefinedCallbacks'), new Scalar\String_($this->accessor)),
175+
[
176+
new Arg($input),
177+
]
178+
));
179+
}
180+
181+
/*
182+
* Use the property fetch to read the value
183+
*
184+
* return isset($input->property_name);
185+
*/
186+
if (!$nullable) {
187+
return new Expr\Isset_([new Expr\PropertyFetch($input, $this->accessor)]);
188+
}
189+
190+
// return property_exists($input, $this->accessor);
191+
return new Expr\FuncCall(new Name('property_exists'), [new Arg($input), new Arg(new Scalar\String_($this->accessor))]);
192+
}
193+
194+
if (self::TYPE_ARRAY_DIMENSION === $this->type) {
195+
/*
196+
* Use the array dim fetch to read the value
197+
*
198+
* isset($input['property_name'])
199+
*/
200+
if (!$nullable) {
201+
return new Expr\Isset_([new Expr\ArrayDimFetch($input, new Scalar\String_($this->accessor))]);
202+
}
203+
204+
return new Expr\FuncCall(new Name('array_key_exists'), [new Arg(new Scalar\String_($this->accessor)), new Arg($input)]);
205+
}
206+
207+
return null;
208+
}
209+
157210
public function getIsNullExpression(Expr\Variable $input): Expr
158211
{
159212
if (self::TYPE_METHOD === $this->type) {

src/Generator/CreateTargetStatementsGenerator.php

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ public function __construct(
2929
private DiscriminatorStatementsGenerator $discriminatorStatementsGeneratorSource,
3030
private DiscriminatorStatementsGenerator $discriminatorStatementsGeneratorTarget,
3131
private CachedReflectionStatementsGenerator $cachedReflectionStatementsGenerator,
32-
private PropertyConditionsGenerator $propertyConditionsGenerator,
3332
) {
3433
}
3534

@@ -177,12 +176,7 @@ private function constructorArgument(Expr\ArrayDimFetch $assignVar, GeneratorMet
177176
{
178177
$variableRegistry = $metadata->variableRegistry;
179178
$fieldValueExpr = $propertyMetadata->source->accessor?->getExpression($variableRegistry->getSourceInput());
180-
181-
$conditionDefined = $this->propertyConditionsGenerator->generate(
182-
$metadata,
183-
$propertyMetadata,
184-
true
185-
);
179+
$conditionDefined = $propertyMetadata->source->accessor?->getIsDefinedExpression($variableRegistry->getSourceInput(), $parameter->allowsNull());
186180

187181
if (null === $fieldValueExpr) {
188182
if (!($propertyMetadata->transformer instanceof AllowNullValueTransformerInterface)) {

src/Generator/MapMethodStatementsGenerator.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ public function __construct(
3838
$discriminatorStatementsGeneratorSource,
3939
$discriminatorStatementsGeneratorTarget,
4040
$cachedReflectionStatementsGenerator,
41-
$propertyConditionGenerator
4241
);
4342

4443
$this->propertyStatementsGenerator = new PropertyStatementsGenerator($propertyConditionGenerator);

tests/AutoMapperTest.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,23 @@ public function testConstructor(): void
481481
self::assertTrue($userDto->getConstructor());
482482
}
483483

484+
public function testConstructorWithNullSource(): void
485+
{
486+
$user = new Fixtures\UserDTO();
487+
$user->id = 10;
488+
$user->setName('foo');
489+
$user->age = null;
490+
/** @var Fixtures\UserConstructorDTO $userDto */
491+
$userDto = $this->autoMapper->map($user, Fixtures\UserConstructorDTO::class);
492+
493+
self::assertInstanceOf(Fixtures\UserConstructorDTO::class, $userDto);
494+
self::assertSame('10', $userDto->getId());
495+
self::assertSame('foo', $userDto->getName());
496+
// since age is null we take default value from constructor
497+
self::assertSame(30, $userDto->getAge());
498+
self::assertTrue($userDto->getConstructor());
499+
}
500+
484501
public function testConstructorAndRelationMissing(): void
485502
{
486503
$user = ['name' => 'foo'];

0 commit comments

Comments
 (0)