From c57b5241330e25a50aa71d7cf981e734b513e4d4 Mon Sep 17 00:00:00 2001 From: Adam Dyson Date: Tue, 4 Nov 2025 18:40:41 +1100 Subject: [PATCH 1/5] Allows defining enum values in various ways --- src/Annotation/Column.php | 40 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/src/Annotation/Column.php b/src/Annotation/Column.php index cf5aad86..37d54caf 100644 --- a/src/Annotation/Column.php +++ b/src/Annotation/Column.php @@ -73,7 +73,7 @@ public function __construct( if ($default !== null) { $this->hasDefault = true; } - $this->attributes = $attributes; + $this->setAttributes($attributes); } /** @@ -142,4 +142,42 @@ public function getAttributes(): array { return $this->attributes; } + + /** + * @param array $attributes + */ + protected function setAttributes(array $attributes): void + { + if ($this->type === 'enum' && isset($attributes['values'])) { + /** @var mixed $values */ + $values = $attributes['values']; + /** @var list $array */ + $array = []; + + if (is_string($values) && enum_exists($values) && method_exists($values, 'cases')) { + /** @var class-string<\BackedEnum> $values */ + $array = array_column($values::cases(), 'value'); + } elseif ($values instanceof \BackedEnum) { + $array = array_column($values::cases(), 'value'); + } elseif (is_array($values)) { + $array = array_map(function ($value) { + if ($value instanceof \BackedEnum) { + return $value->value; + } + if (is_object($value) && property_exists($value, 'value')) { + return $value->value; + } + return $value; + }, $values); + } + + $this->type = 'enum(' . implode(',', array_map(function ($item) { + return is_scalar($item) ? strval($item) : ''; + }, $array)) . ')'; + + unset($attributes['values']); + } + + $this->attributes = $attributes; + } } From ddb744b69249662dec0423dbfdc708f064f6142d Mon Sep 17 00:00:00 2001 From: Adam Dyson Date: Tue, 4 Nov 2025 18:40:49 +1100 Subject: [PATCH 2/5] Tests defining enum values in various ways --- tests/Annotated/Unit/Attribute/ColumnTest.php | 69 ++++++++++++++++--- 1 file changed, 58 insertions(+), 11 deletions(-) diff --git a/tests/Annotated/Unit/Attribute/ColumnTest.php b/tests/Annotated/Unit/Attribute/ColumnTest.php index 613742be..34b20727 100644 --- a/tests/Annotated/Unit/Attribute/ColumnTest.php +++ b/tests/Annotated/Unit/Attribute/ColumnTest.php @@ -5,10 +5,14 @@ namespace Cycle\Annotated\Tests\Unit\Attribute; use Cycle\Annotated\Annotation\Column; +use Cycle\Annotated\Tests\Unit\Attribute\SingleTable\StringEnum; use PHPUnit\Framework\TestCase; class ColumnTest extends TestCase { + public const ENUM_VALUE_A = 'a'; + public const ENUM_VALUE_B = 'b'; + #[Column('integer', nullable: true, unsigned: true)] private $column1; @@ -21,42 +25,85 @@ class ColumnTest extends TestCase #[Column('string(32)', readonlySchema: true)] private mixed $column4; + #[Column(type: 'enum(a,b)')] + private string $column5; + + #[Column( + type: 'enum', + default: self::ENUM_VALUE_A, + values: [self::ENUM_VALUE_A, self::ENUM_VALUE_B], + )] + private string $column6 = self::ENUM_VALUE_A; + + #[Column( + type: 'enum', + default: 'a', + typecast: StringEnum::class, + values: StringEnum::class, + )] + private StringEnum $column7 = StringEnum::A; + public function testOneAttribute(): void { - $attr = $this->getAttribute('column1'); + $column = $this->getColumn('column1'); - $this->assertSame(['unsigned' => true], $attr->getAttributes()); + $this->assertSame(['unsigned' => true], $column->getAttributes()); } public function testTwoAttributes(): void { - $attr = $this->getAttribute('column2'); + $column = $this->getColumn('column2'); - $this->assertSame(['unsigned' => true, 'zerofill' => true], $attr->getAttributes()); + $this->assertSame(['unsigned' => true, 'zerofill' => true], $column->getAttributes()); } public function testCustomSizeAttribute(): void { - $attr = $this->getAttribute('column3'); + $column = $this->getColumn('column3'); - $this->assertSame(['size' => 128], $attr->getAttributes()); + $this->assertSame(['size' => 128], $column->getAttributes()); } public function testDefaultReadonlySchema(): void { - $attr = $this->getAttribute('column1'); + $column = $this->getColumn('column1'); - $this->assertFalse($attr->isReadonlySchema()); + $this->assertFalse($column->isReadonlySchema()); } public function testReadonlySchema(): void { - $attr = $this->getAttribute('column4'); + $column = $this->getColumn('column4'); + + $this->assertTrue($column->isReadonlySchema()); + } + + public function testEnumTypeString(): void + { + $column = $this->getColumn('column5'); + + $this->assertSame('enum(a,b)', $column->getType()); + } + + public function testEnumTypeArray(): void + { + $column = $this->getColumn('column6'); + + $this->assertSame('enum(a,b)', $column->getType()); + $this->assertSame('a', $column->getDefault()); + $this->assertArrayNotHasKey('values', $column->getAttributes()); + } + + public function testEnumTypeBackedEnum(): void + { + $column = $this->getColumn('column7'); - $this->assertTrue($attr->isReadonlySchema()); + $this->assertSame('enum(a,b)', $column->getType()); + $this->assertSame('a', $column->getDefault()); + $this->assertArrayNotHasKey('values', $column->getAttributes()); } - private function getAttribute(string $field): Column + private function getColumn(string $field): Column { $ref = new \ReflectionClass(static::class); return $ref->getProperty($field)->getAttributes(Column::class)[0]->newInstance(); From 5f910a7c8620e08d770314f6b4407d7c8b032c83 Mon Sep 17 00:00:00 2001 From: Adam Dyson Date: Tue, 4 Nov 2025 18:51:27 +1100 Subject: [PATCH 3/5] Removed return type hint --- src/Annotation/Column.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Annotation/Column.php b/src/Annotation/Column.php index 37d54caf..b6eee0bc 100644 --- a/src/Annotation/Column.php +++ b/src/Annotation/Column.php @@ -143,9 +143,6 @@ public function getAttributes(): array return $this->attributes; } - /** - * @param array $attributes - */ protected function setAttributes(array $attributes): void { if ($this->type === 'enum' && isset($attributes['values'])) { From ed1a4555f761f6526b2ac309a21b43740e66f853 Mon Sep 17 00:00:00 2001 From: Adam Dyson Date: Tue, 4 Nov 2025 19:12:34 +1100 Subject: [PATCH 4/5] Remove ability to specify array objects as it doesn't make sense from column attribute, as the value must be static --- src/Annotation/Column.php | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/Annotation/Column.php b/src/Annotation/Column.php index b6eee0bc..6e25c45f 100644 --- a/src/Annotation/Column.php +++ b/src/Annotation/Column.php @@ -158,13 +158,7 @@ protected function setAttributes(array $attributes): void $array = array_column($values::cases(), 'value'); } elseif (is_array($values)) { $array = array_map(function ($value) { - if ($value instanceof \BackedEnum) { - return $value->value; - } - if (is_object($value) && property_exists($value, 'value')) { - return $value->value; - } - return $value; + return $value instanceof \BackedEnum ? $value->value : $value; }, $values); } From 93d64d72047cff4c9affc207673390d966585e93 Mon Sep 17 00:00:00 2001 From: Adam Dyson Date: Tue, 4 Nov 2025 19:12:43 +1100 Subject: [PATCH 5/5] Further test coverage --- tests/Annotated/Unit/Attribute/ColumnTest.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/Annotated/Unit/Attribute/ColumnTest.php b/tests/Annotated/Unit/Attribute/ColumnTest.php index 34b20727..3cd18048 100644 --- a/tests/Annotated/Unit/Attribute/ColumnTest.php +++ b/tests/Annotated/Unit/Attribute/ColumnTest.php @@ -43,6 +43,13 @@ class ColumnTest extends TestCase )] private StringEnum $column7 = StringEnum::A; + #[Column( + type: 'enum', + default: 'a', + values: [StringEnum::A, StringEnum::B], + )] + private string $column8 = 'a'; + public function testOneAttribute(): void { $column = $this->getColumn('column1'); @@ -103,6 +110,15 @@ public function testEnumTypeBackedEnum(): void $this->assertArrayNotHasKey('values', $column->getAttributes()); } + public function testEnumTypeArrayBackedEnum(): void + { + $column = $this->getColumn('column8'); + + $this->assertSame('enum(a,b)', $column->getType()); + $this->assertSame('a', $column->getDefault()); + $this->assertArrayNotHasKey('values', $column->getAttributes()); + } + private function getColumn(string $field): Column { $ref = new \ReflectionClass(static::class);