Skip to content

Commit 5f78b33

Browse files
committed
Fix: cast nullable property
1 parent b12ba5c commit 5f78b33

File tree

7 files changed

+73
-25
lines changed

7 files changed

+73
-25
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "yzen.dev/plain-to-class",
3-
"version": "3.0.1",
3+
"version": "3.0.2",
44
"description": "Class-transformer to transform your dataset into a structured object",
55
"minimum-stability": "dev",
66
"prefer-stable": true,

composer.lock

Lines changed: 19 additions & 19 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Reflection/Types/PropertyType.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,12 @@ class PropertyType
1414
/**
1515
* @param string $name Name of type
1616
* @param bool $isScalar
17+
* @param bool $isNullable
1718
*/
1819
public function __construct(
1920
public string $name,
20-
public bool $isScalar
21+
public bool $isScalar,
22+
public bool $isNullable
2123
) {
2224
}
2325
}

src/Reflection/Types/PropertyTypeFactory.php

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,16 @@ public static function create(RuntimeReflectionProperty $property)
2929

3030
$type = TypeEnums::TYPE_MIXED;
3131
$isScalar = true;
32+
$isNullable = true;
3233

3334
if ($reflectionType instanceof ReflectionType) {
3435
$type = $reflectionType;
36+
$isNullable = $reflectionType->allowsNull();
3537
}
3638
if ($reflectionType instanceof ReflectionNamedType) {
3739
$type = $reflectionType->getName();
3840
$isScalar = $reflectionType->isBuiltin();
41+
$isNullable = $reflectionType->allowsNull();
3942
}
4043

4144
if ($type === TypeEnums::TYPE_ARRAY) {
@@ -49,7 +52,8 @@ public static function create(RuntimeReflectionProperty $property)
4952
$arrayType ??= TypeEnums::TYPE_MIXED;
5053
$type = new ArrayType(
5154
$type,
52-
$isScalar
55+
$isScalar,
56+
$isNullable
5357
);
5458
$type->itemsType = $arrayType ?? TypeEnums::TYPE_MIXED;
5559
$type->isScalarItems = in_array($arrayType, [TypeEnums::TYPE_INTEGER, TypeEnums::TYPE_FLOAT, TypeEnums::TYPE_STRING, TypeEnums::TYPE_BOOLEAN, TypeEnums::TYPE_MIXED]);
@@ -60,20 +64,23 @@ public static function create(RuntimeReflectionProperty $property)
6064
if ($isScalar || $property->notTransform()) {
6165
return new ScalarType(
6266
$type,
63-
$isScalar
67+
$isScalar,
68+
$isNullable
6469
);
6570
}
6671

6772
if (function_exists('enum_exists') && enum_exists($type)) {
6873
return new EnumType(
6974
$type,
70-
$isScalar
75+
$isScalar,
76+
$isNullable
7177
);
7278
}
7379

7480
return new TransformableType(
7581
$type,
76-
$isScalar
82+
$isScalar,
83+
$isNullable
7784
);
7885
}
7986
}

src/ValueCasting.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ public function __construct(ReflectionProperty $property, HydratorConfig $config
4747
*/
4848
public function castAttribute(mixed $value): mixed
4949
{
50+
if ($this->property->type->isNullable && empty($value)) {
51+
return null;
52+
}
53+
5054
if (($this->property->type->isScalar && !$this->property->type instanceof ArrayType) || $this->property->notTransform()) {
5155
return $this->castScalar($this->property->type->name, $value);
5256
}

tests/Units/DTO/TypesDto.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tests\Units\DTO;
6+
7+
use ClassTransformer\Attributes\WritingStyle;
8+
9+
class TypesDto
10+
{
11+
public ?int $nullableInt;
12+
13+
public ?string $nullableString;
14+
public ?float $nullableFloat;
15+
public ?bool $nullableBool;
16+
17+
}

tests/Units/ValueCastingTest.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use PHPUnit\Framework\TestCase;
77
use Tests\Units\DTO\ExtendedDto;
88
use ClassTransformer\Reflection\RuntimeReflectionProperty;
9+
use Tests\Units\DTO\TypesDto;
910

1011
class ValueCastingTest extends TestCase
1112
{
@@ -46,6 +47,23 @@ public function testCreateProperty(): void
4647
$value = $caster->castAttribute('1');
4748
$this->assertIsInt($value);
4849
$this->assertEquals(1, $value);
50+
51+
52+
$caster = new ValueCasting(new RuntimeReflectionProperty(new \ReflectionProperty(TypesDto::class, 'nullableInt')));
53+
$value = $caster->castAttribute('');
54+
$this->assertNull($value);
55+
56+
$caster = new ValueCasting(new RuntimeReflectionProperty(new \ReflectionProperty(TypesDto::class, 'nullableString')));
57+
$value = $caster->castAttribute('');
58+
$this->assertNull($value);
59+
60+
$caster = new ValueCasting(new RuntimeReflectionProperty(new \ReflectionProperty(TypesDto::class, 'nullableFloat')));
61+
$value = $caster->castAttribute('');
62+
$this->assertNull($value);
63+
64+
$caster = new ValueCasting(new RuntimeReflectionProperty(new \ReflectionProperty(TypesDto::class, 'nullableBool')));
65+
$value = $caster->castAttribute('');
66+
$this->assertNull($value);
4967
}
5068

5169
public function testCreateArrayProperty(): void

0 commit comments

Comments
 (0)