From b093e152960093b3baf8fd3f1aed095e8be9bc05 Mon Sep 17 00:00:00 2001 From: Adrien Crivelli Date: Mon, 8 Jul 2024 17:37:28 +0900 Subject: [PATCH] PHP enums support receiving the enum value to convert to DB Because Doctrine ORM might implicitly convert an enum object to its value, it might happen that our type receives the enum value, instead of the object. In that case, our type should do nothing and return the given value (as long as it is a valid value). --- src/DBAL/Types/PhpEnumType.php | 4 ++ tests/DBAL/Types/PhpEnumTypeTest.php | 62 ++++++++++++++++++---------- 2 files changed, 44 insertions(+), 22 deletions(-) diff --git a/src/DBAL/Types/PhpEnumType.php b/src/DBAL/Types/PhpEnumType.php index 6051ce2..d6ae541 100644 --- a/src/DBAL/Types/PhpEnumType.php +++ b/src/DBAL/Types/PhpEnumType.php @@ -48,6 +48,10 @@ public function convertToDatabaseValue(mixed $value, AbstractPlatform $platform) return null; } + if (is_string($value) && $this->getEnumType()::tryFrom($value)) { + return $value; + } + if (!is_object($value) || !is_a($value, $this->getEnumType())) { throw new InvalidArgumentException("Invalid '" . Utils::printSafe($value) . "' value to be stored in database for enum " . $this->getName()); } diff --git a/tests/DBAL/Types/PhpEnumTypeTest.php b/tests/DBAL/Types/PhpEnumTypeTest.php index 24248dc..ecf5b0c 100644 --- a/tests/DBAL/Types/PhpEnumTypeTest.php +++ b/tests/DBAL/Types/PhpEnumTypeTest.php @@ -34,50 +34,68 @@ protected function getEnumType(): string public function testEnum(): void { self::assertSame("ENUM('value1', 'value2')", $this->type->getSqlDeclaration(['foo'], $this->platform)); - - // Should always return string - self::assertSame(TestEnum::key1, $this->type->convertToPHPValue('value1', $this->platform)); - - // Should support null values or empty string - self::assertNull($this->type->convertToPHPValue(null, $this->platform)); - self::assertNull($this->type->convertToPHPValue('', $this->platform)); - self::assertNull($this->type->convertToDatabaseValue(null, $this->platform)); - self::assertTrue($this->type->requiresSQLCommentHint($this->platform)); } - public function testConvertToPHPValueThrowsWithInvalidValue(): void + /** + * @dataProvider providerConvertToPHPValue + */ + public function testConvertToPHPValue(?string $input, ?TestEnum $expected): void { - $this->expectException(ValueError::class); + self::assertSame($expected, $this->type->convertToPHPValue($input, $this->platform)); + } - $this->type->convertToPHPValue('foo', $this->platform); + public function providerConvertToPHPValue(): iterable + { + yield ['value1', TestEnum::key1]; + yield [null, null]; + yield ['', null]; } - public function testConvertToDatabaseValueThrowsWithInvalidValue(): void + /** + * @dataProvider providerConvertToDatabaseValue + */ + public function testConvertToDatabaseValue(mixed $input, ?string $expected): void { - $this->expectException(InvalidArgumentException::class); + self::assertSame($expected, $this->type->convertToDatabaseValue($input, $this->platform)); + } - $this->type->convertToDatabaseValue('foo', $this->platform); + public function providerConvertToDatabaseValue(): iterable + { + yield [null, null]; + yield [TestEnum::key1, 'value1']; + yield ['value1', 'value1']; } - public function testConvertToDatabaseValueThrowsWithInvalidEnum(): void + /** + * @dataProvider providerInvalidConvertToDatabaseValue + */ + public function testInvalidConvertToDatabaseValue(mixed $input): void { $this->expectException(InvalidArgumentException::class); - $this->type->convertToDatabaseValue(OtherTestEnum::key1, $this->platform); + $this->type->convertToDatabaseValue($input, $this->platform); } - public function testConvertToPHPValueThrowsWithZero(): void + public function providerInvalidConvertToDatabaseValue(): iterable { - $this->expectException(InvalidArgumentException::class); + yield ['foo']; + yield ['key1']; + yield [OtherTestEnum::key1]; + yield [0]; + } - $this->type->convertToPHPValue(0, $this->platform); + public function testConvertToPHPValueThrowsWithInvalidValue(): void + { + $this->expectException(ValueError::class); + + $this->type->convertToPHPValue('foo', $this->platform); } - public function testConvertToDatabaseValueThrowsWithZero(): void + public function testConvertToPHPValueThrowsWithZero(): void { $this->expectException(InvalidArgumentException::class); - $this->type->convertToDatabaseValue(0, $this->platform); + $this->type->convertToPHPValue(0, $this->platform); } }