annotated
annotated copied to clipboard
💡 Specify enum values in different ways
I have an idea!
When defining enum values, currently you must define the Column type with parenthesis, wrapping the set of values. Having to manually type these values isn't great from a maintenance perspective, also code editors will flag this as an issue because type does not match ExpectedValues having enum(one,two) instead of expected enum.
public const string STATUS_ACTIVE = 'active';
public const string STATUS_PENDING = 'pending';
public const string STATUS_SUSPENDED = 'suspended';
#[Column(
type: 'enum(active,pending,suspended)',
name: 'status',
default: self::STATUS_ACTIVE,
)]
private string $status = self::STATUS_ACTIVE;
It would be nice to have the ability to specify enum values using code, an array of constants, array of enum cases, a backed enum class name etc. Below are a few modifications to the Column annotation class providing such behavior, just as an example.
class Column
{
public function __construct(
protected string $type,
protected ?string $name = null,
protected ?string $property = null,
protected bool $primary = false,
protected bool $nullable = false,
protected mixed $default = null,
protected mixed $typecast = null,
protected bool $castDefault = false,
protected bool $readonlySchema = false,
mixed ...$attributes,
) {
if ($type === 'enum' && isset($attributes['values'])) {
$values = $attributes['values'];
if (is_string($values) && enum_exists($values)) {
$values = array_column($values::cases(), 'value');
} elseif ($values instanceof BackedEnum) {
$values = array_column($values::cases(), 'value');
} elseif (is_array($values)) {
$values = 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('strval', (array) $values)) . ')';
unset($attributes['values']);
}
if ($default !== null) {
$this->hasDefault = true;
}
$this->attributes = $attributes;
}
}
Giving developers more options.
public const string STATUS_ACTIVE = 'active';
public const string STATUS_PENDING = 'pending';
public const string STATUS_SUSPENDED = 'suspended';
#[Column(
type: 'enum',
name: 'status',
default: self::STATUS_ACTIVE,
values: [self::STATUS_ACTIVE, self::STATUS_PENDING, self::STATUS_SUSPENDED],
)]
private string $status = self::STATUS_ACTIVE;
#[Column(
type: 'enum',
name: 'status',
default: AccountStatus::ACTIVE->value,
values: AccountStatus::class,
)]
private string $status = AccountStatus::ACTIVE->value;
#[Column(
type: 'enum',
name: 'status',
default: AccountStatus::ACTIVE->value,
typecast: AccountStatus::class,
values: AccountStatus::class,
)]
private AccountStatus $status = AccountStatus::ACTIVE;
Related
- https://github.com/cycle/orm/issues/484