Skip to content

Commit

Permalink
Fix populating readonly properties from parent classes (#95)
Browse files Browse the repository at this point in the history
  • Loading branch information
vjik authored Sep 17, 2024
1 parent eacc3b4 commit 494a7e4
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 2 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## 1.4.1 under development

- no changes in this release.
- Bug #95: Fix populating readonly properties from parent classes (@vjik)

## 1.4.0 August 23, 2024

Expand Down
21 changes: 20 additions & 1 deletion src/Hydrator.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ public function hydrate(object $object, array|DataInterface $data = []): void

$this->hydrateInternal(
$object,
$reflectionClass,
ReflectionFilter::filterProperties($object, $reflectionClass),
$data
);
Expand Down Expand Up @@ -108,6 +109,7 @@ public function create(string $class, array|DataInterface $data = []): object

$this->hydrateInternal(
$object,
$reflectionClass,
ReflectionFilter::filterProperties($object, $reflectionClass, $excludeProperties),
$data
);
Expand All @@ -120,6 +122,7 @@ public function create(string $class, array|DataInterface $data = []): object
*/
private function hydrateInternal(
object $object,
ReflectionClass $reflectionClass,
array $reflectionProperties,
DataInterface $data,
): void {
Expand All @@ -141,9 +144,25 @@ private function hydrateInternal(
new TypeCastContext($this, $property),
);
if ($result->isResolved()) {
$property->setValue($object, $result->getValue());
$this
->preparePropertyToSetValue($reflectionClass, $property, $propertyName)
->setValue($object, $result->getValue());
}
}
}
}

private function preparePropertyToSetValue(
ReflectionClass $class,
ReflectionProperty $property,
string $propertyName,
): ReflectionProperty {
if ($property->isReadOnly()) {
$declaringClass = $property->getDeclaringClass();
if ($declaringClass !== $class) {
return $declaringClass->getProperty($propertyName);
}
}
return $property;
}
}
40 changes: 40 additions & 0 deletions tests/HydratorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
use Yiisoft\Hydrator\Tests\Support\Classes\ConstructorTypeClass;
use Yiisoft\Hydrator\Tests\Support\Classes\CounterClass;
use Yiisoft\Hydrator\Tests\Support\Classes\FromPredefinedArrayClass;
use Yiisoft\Hydrator\Tests\Support\Classes\Inheritance\ReadOnly\ImageSlideDto;
use Yiisoft\Hydrator\Tests\Support\Classes\Inheritance\Figure\Circle;
use Yiisoft\Hydrator\Tests\Support\Classes\InvalidDataResolverClass;
use Yiisoft\Hydrator\Tests\Support\Classes\NestedModel\UserModel;
use Yiisoft\Hydrator\Tests\Support\Classes\NonInitializedReadonlyProperties;
Expand Down Expand Up @@ -769,4 +771,42 @@ public function testHydrateNonInitializedReadonlyProperties(): void
$this->assertSame('1', $object->a);
$this->assertSame('3', $object->b);
}

public function testBaseInheritance(): void
{
$hydrator = new Hydrator();

$object = $hydrator->create(
Circle::class,
[
'name' => 'Wheel',
'color' => 'Red',
'id' => 'x7',
'radius' => 17,
]
);

$this->assertSame(17, $object->radius);
$this->assertSame('Wheel', $object->name);
$this->assertSame('Red', $object->getColor());
$this->assertNull($object->getId());
}

public function testReadOnlyInheritance(): void
{
$hydrator = new Hydrator();

$object = $hydrator->create(
ImageSlideDto::class,
[
'src' => '/images/slide.jpg',
'width' => 200,
'height' => 300,
]
);

$this->assertSame('/images/slide.jpg', $object->src);
$this->assertSame(200, $object->width);
$this->assertSame(300, $object->height);
}
}
10 changes: 10 additions & 0 deletions tests/Support/Classes/Inheritance/Figure/Circle.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Hydrator\Tests\Support\Classes\Inheritance\Figure;

final class Circle extends Figure
{
public ?int $radius = null;
}
22 changes: 22 additions & 0 deletions tests/Support/Classes/Inheritance/Figure/Figure.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Hydrator\Tests\Support\Classes\Inheritance\Figure;

class Figure
{
public ?string $name = null;
protected ?string $color = null;
private ?int $id = null;

public function getColor(): ?string
{
return $this->color;
}

public function getId(): ?int
{
return $this->id;
}
}
10 changes: 10 additions & 0 deletions tests/Support/Classes/Inheritance/ReadOnly/ImageSlideDto.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Hydrator\Tests\Support\Classes\Inheritance\ReadOnly;

final class ImageSlideDto extends SlideDto
{
public readonly string $src;
}
11 changes: 11 additions & 0 deletions tests/Support/Classes/Inheritance/ReadOnly/SlideDto.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Hydrator\Tests\Support\Classes\Inheritance\ReadOnly;

class SlideDto
{
public readonly ?int $width;
public readonly ?int $height;
}

0 comments on commit 494a7e4

Please sign in to comment.