diff --git a/src/Types/EnumType.php b/src/Types/EnumType.php new file mode 100644 index 00000000000..7b3d579a7d3 --- /dev/null +++ b/src/Types/EnumType.php @@ -0,0 +1,65 @@ +getVarcharTypeDeclarationSQL($column); + } + + /** + * {@inheritdoc} + */ + public function convertToDatabaseValue($value, AbstractPlatform $platform) + { + if ($value === null) { + return null; + } + + if ($value instanceof \UnitEnum) { + return serialize($value); + } + + throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', 'UnitEnum']); + } + + /** + * {@inheritdoc} + */ + public function convertToPHPValue($value, AbstractPlatform $platform) + { + if ($value === null) { + return null; + } + + set_error_handler(function (int $code, string $message): bool { + throw ConversionException::conversionFailedUnserialization($this->getName(), $message); + }); + + try { + return unserialize($value); + } finally { + restore_error_handler(); + } + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return Types::ENUM; + } + + /** + * {@inheritdoc} + */ + public function requiresSQLCommentHint(AbstractPlatform $platform) + { + return true; + } +} diff --git a/src/Types/Type.php b/src/Types/Type.php index 03e5b824851..0487452dea8 100644 --- a/src/Types/Type.php +++ b/src/Types/Type.php @@ -34,6 +34,7 @@ abstract class Type Types::DATETIMETZ_MUTABLE => DateTimeTzType::class, Types::DATETIMETZ_IMMUTABLE => DateTimeTzImmutableType::class, Types::DECIMAL => DecimalType::class, + Types::ENUM => EnumType::class, Types::FLOAT => FloatType::class, Types::GUID => GuidType::class, Types::INTEGER => IntegerType::class, diff --git a/src/Types/Types.php b/src/Types/Types.php index 56bf3f51cf0..03c49f772ec 100644 --- a/src/Types/Types.php +++ b/src/Types/Types.php @@ -23,6 +23,7 @@ final class Types public const DATETIMETZ_MUTABLE = 'datetimetz'; public const DATETIMETZ_IMMUTABLE = 'datetimetz_immutable'; public const DECIMAL = 'decimal'; + public const ENUM = 'enum'; public const FLOAT = 'float'; public const GUID = 'guid'; public const INTEGER = 'integer'; diff --git a/tests/Functional/Types/EnumTest.php b/tests/Functional/Types/EnumTest.php new file mode 100644 index 00000000000..ab6d3dd3a1c --- /dev/null +++ b/tests/Functional/Types/EnumTest.php @@ -0,0 +1,34 @@ += 8.1 + */ +class EnumTest extends FunctionalTestCase +{ + protected function setUp(): void + { + $table = new Table('enum_table'); + $table->addColumn('enum', 'enum'); + + $this->connection->createSchemaManager()->dropAndCreateTable($table); + } + + public function testInsertAndSelect(): void + { + $draft = SimpleEnum::DRAFT; + + $result = $this->connection->insert('enum_table', ['enum' => $draft], [Types::ENUM]); + self::assertSame(1, $result); + + $value = $this->connection->fetchOne('SELECT enum FROM enum_table'); + + self::assertSame($draft, $this->connection->convertToPHPValue($value, Types::ENUM)); + } +} diff --git a/tests/Tools/TestAsset/SimpleEnum.php b/tests/Tools/TestAsset/SimpleEnum.php new file mode 100644 index 00000000000..74eec8cd791 --- /dev/null +++ b/tests/Tools/TestAsset/SimpleEnum.php @@ -0,0 +1,10 @@ += 8.1 + */ +class EnumTest extends TestCase +{ + /** @var AbstractPlatform&MockObject */ + private $platform; + + /** @var EnumType */ + private $type; + + protected function setUp(): void + { + $this->platform = $this->createMock(AbstractPlatform::class); + $this->type = new EnumType(); + } + + public function testObjectConvertsToDatabaseValue(): void + { + self::assertIsString($this->type->convertToDatabaseValue(SimpleEnum::DRAFT, $this->platform)); + } + + public function testObjectConvertsToPHPValue(): void + { + self::assertTrue(is_a($this->type->convertToPHPValue(serialize(SimpleEnum::DRAFT), $this->platform), SimpleEnum::class)); + } + + public function testConversionToDatabaseValueFailure(): void + { + $this->expectException(ConversionException::class); + $this->expectExceptionMessage( + "Could not convert PHP value 'abcdefg' to type enum. Expected one of the following types: null, UnitEnum" + ); + $this->type->convertToDatabaseValue('abcdefg', $this->platform); + } + + public function testConversionToPHPValueFailure(): void + { + $this->expectException(ConversionException::class); + $this->expectExceptionMessage( + "Could not convert database value to 'enum' as an error was triggered by the unserialization:" + . " 'unserialize(): Error at offset 0 of 7 bytes'" + ); + $this->type->convertToPHPValue('abcdefg', $this->platform); + } + + public function testNullConversion(): void + { + self::assertNull($this->type->convertToPHPValue(null, $this->platform)); + } +}