Skip to content

Commit 7564927

Browse files
Support PHP Enums in Enum Column values (#119)
1 parent f996d3e commit 7564927

File tree

2 files changed

+104
-12
lines changed

2 files changed

+104
-12
lines changed

src/Annotation/Column.php

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ public function __construct(
7373
if ($default !== null) {
7474
$this->hasDefault = true;
7575
}
76-
$this->attributes = $attributes;
76+
$this->setAttributes($attributes);
7777
}
7878

7979
/**
@@ -142,4 +142,33 @@ public function getAttributes(): array
142142
{
143143
return $this->attributes;
144144
}
145+
146+
protected function setAttributes(array $attributes): void
147+
{
148+
if ($this->type === 'enum' && isset($attributes['values'])) {
149+
/** @var mixed $values */
150+
$values = $attributes['values'];
151+
/** @var list<mixed> $array */
152+
$array = [];
153+
154+
if (is_string($values) && enum_exists($values) && method_exists($values, 'cases')) {
155+
/** @var class-string<\BackedEnum> $values */
156+
$array = array_column($values::cases(), 'value');
157+
} elseif ($values instanceof \BackedEnum) {
158+
$array = array_column($values::cases(), 'value');
159+
} elseif (is_array($values)) {
160+
$array = array_map(function ($value) {
161+
return $value instanceof \BackedEnum ? $value->value : $value;
162+
}, $values);
163+
}
164+
165+
$this->type = 'enum(' . implode(',', array_map(function ($item) {
166+
return is_scalar($item) ? strval($item) : '';
167+
}, $array)) . ')';
168+
169+
unset($attributes['values']);
170+
}
171+
172+
$this->attributes = $attributes;
173+
}
145174
}

tests/Annotated/Unit/Attribute/ColumnTest.php

Lines changed: 74 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,14 @@
55
namespace Cycle\Annotated\Tests\Unit\Attribute;
66

77
use Cycle\Annotated\Annotation\Column;
8+
use Cycle\Annotated\Tests\Unit\Attribute\SingleTable\StringEnum;
89
use PHPUnit\Framework\TestCase;
910

1011
class ColumnTest extends TestCase
1112
{
13+
public const ENUM_VALUE_A = 'a';
14+
public const ENUM_VALUE_B = 'b';
15+
1216
#[Column('integer', nullable: true, unsigned: true)]
1317
private $column1;
1418

@@ -21,42 +25,101 @@ class ColumnTest extends TestCase
2125
#[Column('string(32)', readonlySchema: true)]
2226
private mixed $column4;
2327

28+
#[Column(type: 'enum(a,b)')]
29+
private string $column5;
30+
31+
#[Column(
32+
type: 'enum',
33+
default: self::ENUM_VALUE_A,
34+
values: [self::ENUM_VALUE_A, self::ENUM_VALUE_B],
35+
)]
36+
private string $column6 = self::ENUM_VALUE_A;
37+
38+
#[Column(
39+
type: 'enum',
40+
default: 'a',
41+
typecast: StringEnum::class,
42+
values: StringEnum::class,
43+
)]
44+
private StringEnum $column7 = StringEnum::A;
45+
46+
#[Column(
47+
type: 'enum',
48+
default: 'a',
49+
values: [StringEnum::A, StringEnum::B],
50+
)]
51+
private string $column8 = 'a';
52+
2453
public function testOneAttribute(): void
2554
{
26-
$attr = $this->getAttribute('column1');
55+
$column = $this->getColumn('column1');
2756

28-
$this->assertSame(['unsigned' => true], $attr->getAttributes());
57+
$this->assertSame(['unsigned' => true], $column->getAttributes());
2958
}
3059

3160
public function testTwoAttributes(): void
3261
{
33-
$attr = $this->getAttribute('column2');
62+
$column = $this->getColumn('column2');
3463

35-
$this->assertSame(['unsigned' => true, 'zerofill' => true], $attr->getAttributes());
64+
$this->assertSame(['unsigned' => true, 'zerofill' => true], $column->getAttributes());
3665
}
3766

3867
public function testCustomSizeAttribute(): void
3968
{
40-
$attr = $this->getAttribute('column3');
69+
$column = $this->getColumn('column3');
4170

42-
$this->assertSame(['size' => 128], $attr->getAttributes());
71+
$this->assertSame(['size' => 128], $column->getAttributes());
4372
}
4473

4574
public function testDefaultReadonlySchema(): void
4675
{
47-
$attr = $this->getAttribute('column1');
76+
$column = $this->getColumn('column1');
4877

49-
$this->assertFalse($attr->isReadonlySchema());
78+
$this->assertFalse($column->isReadonlySchema());
5079
}
5180

5281
public function testReadonlySchema(): void
5382
{
54-
$attr = $this->getAttribute('column4');
83+
$column = $this->getColumn('column4');
84+
85+
$this->assertTrue($column->isReadonlySchema());
86+
}
87+
88+
public function testEnumTypeString(): void
89+
{
90+
$column = $this->getColumn('column5');
91+
92+
$this->assertSame('enum(a,b)', $column->getType());
93+
}
94+
95+
public function testEnumTypeArray(): void
96+
{
97+
$column = $this->getColumn('column6');
98+
99+
$this->assertSame('enum(a,b)', $column->getType());
100+
$this->assertSame('a', $column->getDefault());
101+
$this->assertArrayNotHasKey('values', $column->getAttributes());
102+
}
103+
104+
public function testEnumTypeBackedEnum(): void
105+
{
106+
$column = $this->getColumn('column7');
107+
108+
$this->assertSame('enum(a,b)', $column->getType());
109+
$this->assertSame('a', $column->getDefault());
110+
$this->assertArrayNotHasKey('values', $column->getAttributes());
111+
}
112+
113+
public function testEnumTypeArrayBackedEnum(): void
114+
{
115+
$column = $this->getColumn('column8');
55116

56-
$this->assertTrue($attr->isReadonlySchema());
117+
$this->assertSame('enum(a,b)', $column->getType());
118+
$this->assertSame('a', $column->getDefault());
119+
$this->assertArrayNotHasKey('values', $column->getAttributes());
57120
}
58121

59-
private function getAttribute(string $field): Column
122+
private function getColumn(string $field): Column
60123
{
61124
$ref = new \ReflectionClass(static::class);
62125
return $ref->getProperty($field)->getAttributes(Column::class)[0]->newInstance();

0 commit comments

Comments
 (0)