Skip to content

Commit

Permalink
Merge pull request #59 from driehle/enum-support
Browse files Browse the repository at this point in the history
Add basic support for enums via use of strategies
  • Loading branch information
driehle authored Jun 10, 2022
2 parents 8f11965 + 5f79685 commit b325ac2
Show file tree
Hide file tree
Showing 5 changed files with 194 additions and 0 deletions.
6 changes: 6 additions & 0 deletions src/DoctrineObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Doctrine\Laminas\Hydrator;

use BackedEnum;
use DateTime;
use DateTimeImmutable;
use Doctrine\Inflector\Inflector;
Expand Down Expand Up @@ -314,6 +315,11 @@ public function hydrateValue(string $name, $value, ?array $data = null)
return null;
}

// BackedEnum is available from PHP 8.1 on
if ($value instanceof BackedEnum) {
return $value;
}

return $this->handleTypeConversions($value, $this->getClassMetadata()->getTypeOfField($name));
}

Expand Down
32 changes: 32 additions & 0 deletions tests/Assets/SimpleEntityWithEnumPhp81.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 SimpleEntityWithEnumPhp81
{
protected int $id;

protected ?SimpleEnumPhp81 $enum = null;

public function setId(int $id): void
{
$this->id = $id;
}

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

public function setEnum(?SimpleEnumPhp81 $enum = null): void
{
$this->enum = $enum;
}

public function getEnum(): ?SimpleEnumPhp81
{
return $this->enum;
}
}
11 changes: 11 additions & 0 deletions tests/Assets/SimpleEnumPhp81.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

namespace DoctrineTest\Laminas\Hydrator\Assets;

enum SimpleEnumPhp81: int
{
case One = 1;
case Two = 2;
}
35 changes: 35 additions & 0 deletions tests/Assets/SimpleEnumStrategyPhp81.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

declare(strict_types=1);

namespace DoctrineTest\Laminas\Hydrator\Assets;

use Laminas\Hydrator\Strategy\StrategyInterface;

class SimpleEnumStrategyPhp81 implements StrategyInterface
{
/**
* @param mixed $value
*/
public function extract($value, ?object $object = null): ?int
{
if ($value === null) {
return null;
}

return SimpleEnumPhp81::tryFrom($value)->value;
}

/**
* @param mixed $value
* @param array<array-key, mixed>|null $data
*/
public function hydrate($value, ?array $data): ?SimpleEnumPhp81
{
if ($value === null) {
return null;
}

return SimpleEnumPhp81::tryFrom($value);
}
}
110 changes: 110 additions & 0 deletions tests/DoctrineObjectTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Doctrine\Laminas\Hydrator\Strategy;
use Doctrine\Persistence\Mapping\ClassMetadata;
use Doctrine\Persistence\ObjectManager;
use DoctrineTest\Laminas\Hydrator\Assets\SimpleEnumPhp81;
use InvalidArgumentException;
use Laminas\Hydrator\NamingStrategy\UnderscoreNamingStrategy;
use Laminas\Hydrator\Strategy\StrategyInterface;
Expand All @@ -20,6 +21,7 @@
use Prophecy\PhpUnit\ProphecyTrait;
use ReflectionClass;
use stdClass;
use TypeError;

use function array_keys;
use function assert;
Expand Down Expand Up @@ -848,6 +850,63 @@ static function ($arg) {
);
}

public function configureObjectManagerForSimpleEntityWithEnum(): void
{
$refl = new ReflectionClass(Assets\SimpleEntityWithEnumPhp81::class);

$this
->metadata
->method('getAssociationNames')
->will($this->returnValue([]));

$this
->metadata
->method('getFieldNames')
->will($this->returnValue(['id', 'enum']));

$this
->metadata
->method('getTypeOfField')
->with($this->logicalOr($this->equalTo('id'), $this->equalTo('enum')))
->willReturnCallback(
static function ($arg) {
if ($arg === 'id') {
return 'integer';
}

if ($arg === 'enum') {
return 'enum';
}

throw new InvalidArgumentException();
}
);

$this
->metadata
->method('hasAssociation')
->will($this->returnValue(false));

$this
->metadata
->method('getIdentifierFieldNames')
->will($this->returnValue(['id']));

$this
->metadata
->method('getReflectionClass')
->will($this->returnValue($refl));

$this->hydratorByValue = new DoctrineObjectHydrator(
$this->objectManager,
true
);
$this->hydratorByReference = new DoctrineObjectHydrator(
$this->objectManager,
false
);
}

public function testObjectIsPassedForContextToStrategies(): void
{
$entity = new Assets\SimpleEntity();
Expand Down Expand Up @@ -2866,4 +2925,55 @@ public function testNestedHydrationByReference(): void
$this->assertSame('value', $entity->getToOne(false)->getField(false));
$this->assertSame('2019-01-24 12:00:00', $entity->getCreatedAt()->format('Y-m-d H:i:s'));
}

/**
* @requires PHP 8.1
*/
public function testHandleEnumConversionUsingByValue(): void
{
// When using hydration by value, it will use the public API of the entity to set values (setters)
$entity = new Assets\SimpleEntityWithEnumPhp81();
$this->configureObjectManagerForSimpleEntityWithEnum();

$value = 1;
$data = ['enum' => $value];

$this->hydratorByValue->addStrategy('enum', new Assets\SimpleEnumStrategyPhp81());
$entity = $this->hydratorByValue->hydrate($data, $entity);

$this->assertInstanceOf(SimpleEnumPhp81::class, $entity->getEnum());
$this->assertEquals(SimpleEnumPhp81::tryFrom($value), $entity->getEnum());
}

/**
* @requires PHP 8.1
*/
public function testNullValueIsNotConvertedToEnum(): void
{
$entity = new Assets\SimpleEntityWithEnumPhp81();
$this->configureObjectManagerForSimpleEntityWithEnum();

$data = ['enum' => null];

$this->hydratorByValue->addStrategy('enum', new Assets\SimpleEnumStrategyPhp81());
$entity = $this->hydratorByValue->hydrate($data, $entity);

$this->assertNull($entity->getEnum());
}

/**
* @requires PHP 8.1
*/
public function testWrongEnumBackedValueThrowsException(): void
{
$entity = new Assets\SimpleEntityWithEnumPhp81();
$this->configureObjectManagerForSimpleEntityWithEnum();

$data = ['enum' => 'string'];

$this->expectException(TypeError::class);

$this->hydratorByValue->addStrategy('enum', new Assets\SimpleEnumStrategyPhp81());
$this->hydratorByValue->hydrate($data, $entity);
}
}

0 comments on commit b325ac2

Please sign in to comment.