Skip to content

Commit

Permalink
Merge pull request #62 from fezfez/php8.2
Browse files Browse the repository at this point in the history
Add PHP 8.2 support
  • Loading branch information
driehle authored Nov 18, 2022
2 parents 4d7efca + 56583f8 commit b76cfa7
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 6 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/continuous-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ jobs:
name: "PHPUnit"
uses: "doctrine/.github/.github/workflows/[email protected]"
with:
php-versions: '["7.4", "8.0", "8.1"]'
php-versions: '["7.4", "8.0", "8.1", "8.2"]'
10 changes: 5 additions & 5 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"rss": "https://github.com/doctrine/doctrine-laminas-hydrator/releases.atom"
},
"require": {
"php": "^7.4 || ~8.0.0 || ~8.1.0",
"php": "^7.4 || ~8.0.0 || ~8.1.0 || ~8.2.0",
"ext-ctype": "*",
"doctrine/collections": "^1.6.8",
"doctrine/inflector": "^2.0.4",
Expand All @@ -22,10 +22,10 @@
"laminas/laminas-stdlib": "^3.6.1"
},
"require-dev": {
"doctrine/coding-standard": "^9.0.0",
"phpstan/phpstan": "^1.1.2",
"phpunit/phpunit": "^9.5.10",
"vimeo/psalm": "^4.15.0"
"doctrine/coding-standard": "^9.0.2",
"phpstan/phpstan": "^1.9.2",
"phpunit/phpunit": "^9.5.26",
"vimeo/psalm": "^4.30"
},
"autoload": {
"psr-4": {
Expand Down
27 changes: 27 additions & 0 deletions src/DoctrineObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,17 @@ protected function extractByReference(object $object): array
: $this->filterComposite;

$data = [];

// fail for readonly classes (PHP 8.2)
if (method_exists($refl, 'isReadOnly') && $refl->isReadOnly()) {
throw new LogicException(
sprintf(
'this class "%s" is readonly, data can\'t be extracted',
get_class($object)
)
);
}

foreach ($this->getFieldNames() as $fieldName) {
if ($filter && ! $filter->filter($fieldName)) {
continue;
Expand All @@ -285,6 +296,10 @@ protected function extractByReference(object $object): array
$reflProperty = $refl->getProperty($fieldName);
$reflProperty->setAccessible(true);

if (method_exists($reflProperty, 'isReadOnly') && $reflProperty->isReadOnly()) {
continue;
}

// skip uninitialized properties (available from PHP 7.4)
if (! $reflProperty->isInitialized($object)) {
continue;
Expand Down Expand Up @@ -420,6 +435,18 @@ protected function hydrateByReference(array $data, ?object $object): object
}

$reflProperty = $refl->getProperty($field);

// fail for readonly property (PHP 8.1)
if (method_exists($reflProperty, 'isReadOnly') && $reflProperty->isReadOnly()) {
throw new LogicException(
sprintf(
'Cannot hydrate class "%s" by reference. Property "%s" is readonly. To fix this error, remove readonly.',
get_class($object),
$field
)
);
}

$reflProperty->setAccessible(true);

if ($metadata->hasAssociation($field)) {
Expand Down
18 changes: 18 additions & 0 deletions tests/Assets/SimpleEntityReadonlyPhp82.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

declare(strict_types=1);

namespace DoctrineTest\Laminas\Hydrator\Assets;

readonly class SimpleEntityReadonlyPhp82
{
protected ?int $id;

protected ?string $field;

public function __construct(?int $id, ?string $field)
{
$this->id = $id;
$this->field = $field;
}
}
32 changes: 32 additions & 0 deletions tests/Assets/SimpleEntityWithReadonlyPropsPhp81.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

namespace DoctrineTest\Laminas\Hydrator\Assets;

class SimpleEntityWithReadonlyPropsPhp81
{
protected readonly ?int $id;

protected ?string $field;

public function __construct(?int $id)
{
$this->id = $id;
}

public function getId(): int
{
return $this->id;
}

public function setField(string $field): void
{
$this->field = $field;
}

public function getField(): string
{
return $this->field;
}
}
66 changes: 66 additions & 0 deletions tests/DoctrineObjectTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use InvalidArgumentException;
use Laminas\Hydrator\NamingStrategy\UnderscoreNamingStrategy;
use Laminas\Hydrator\Strategy\StrategyInterface;
use LogicException;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use ReflectionClass;
Expand All @@ -25,6 +26,7 @@
use function assert;
use function explode;
use function implode;
use function sprintf;
use function time;

class DoctrineObjectTest extends TestCase
Expand Down Expand Up @@ -2978,4 +2980,68 @@ public function testWrongEnumBackedValueThrowsException(): void
$this->hydratorByValue->addStrategy('enum', new Assets\SimpleEnumStrategyPhp81());
$this->hydratorByValue->hydrate($data, $entity);
}

/**
* @requires PHP 8.1
*/
public function testExtractReadonlyPropsByReference(): void
{
$entity = new Assets\SimpleEntityWithReadonlyPropsPhp81(2);

$this->configureObjectManagerForSimpleEntity(Assets\SimpleEntityWithReadonlyPropsPhp81::class);

$data = $this->hydratorByReference->extract($entity);
$this->assertEquals([], $data);

$entity->setField('value');
$data = $this->hydratorByReference->extract($entity);
$this->assertEquals(['field' => 'value'], $data);
}

/**
* @requires PHP 8.2
*/
public function testExtractReadonlyClassByReference(): void
{
$entity = new Assets\SimpleEntityReadonlyPhp82(2, null);

$this->configureObjectManagerForSimpleEntity(Assets\SimpleEntityReadonlyPhp82::class);

$this->expectExceptionMessage(sprintf(
'this class "%s" is readonly, data can\'t be extracted',
Assets\SimpleEntityReadonlyPhp82::class
));
$this->expectException(LogicException::class);

$this->hydratorByReference->extract($entity);
}

/**
* @requires PHP 8.1
*/
public function testHydrateReadonlyPropsByValue(): void
{
$this->configureObjectManagerForSimpleEntity(Assets\SimpleEntityWithReadonlyPropsPhp81::class);

$entity = $this->hydratorByValue->hydrate(['field' => 'toto', 'id' => 15], new Assets\SimpleEntityWithReadonlyPropsPhp81(3));

$this->assertEquals(3, $entity->getId());
$this->assertEquals('toto', $entity->getField());
}

/**
* @requires PHP 8.1
*/
public function testHydrateReadonlyPropsByReference(): void
{
$this->configureObjectManagerForSimpleEntity(Assets\SimpleEntityWithReadonlyPropsPhp81::class);

self::expectExceptionMessage(sprintf(
'Cannot hydrate class "%s" by reference. Property "id" is readonly. To fix this error, remove readonly',
Assets\SimpleEntityWithReadonlyPropsPhp81::class
));
self::expectException(LogicException::class);

$this->hydratorByReference->hydrate(['field' => 'toto', 'id' => 15], new Assets\SimpleEntityWithReadonlyPropsPhp81(3));
}
}

0 comments on commit b76cfa7

Please sign in to comment.