Skip to content

Metadata

Add custom properties and behaviors to enum cases using attributes.

The Metadata trait allows you to:

  • Attach custom properties to enum cases
  • Access properties via dynamic methods
  • Find cases by metadata values
  • Transform property values automatically
use Cline\Enums\Concerns\Metadata;
use Cline\Enums\Meta\Meta;
use Cline\Enums\Meta\MetaProperty;
// Define your meta properties
#[Attribute]
class Description extends MetaProperty {}
#[Attribute]
class Color extends MetaProperty {}
// Apply to your enum
#[Meta(Description::class, Color::class)]
enum TaskStatus: int
{
use Metadata;
#[Description('Incomplete Task')] #[Color('red')]
case Incomplete = 0;
#[Description('Completed Task')] #[Color('green')]
case Completed = 1;
#[Description('Canceled Task')] #[Color('gray')]
case Canceled = 2;
}
TaskStatus::Incomplete->description(); // 'Incomplete Task'
TaskStatus::Completed->color(); // 'green'

Each meta property is a class extending MetaProperty:

#[Attribute]
class Color extends MetaProperty {}
#[Attribute]
class Description extends MetaProperty {}
#[Attribute]
class Icon extends MetaProperty {}

Override the default method name:

#[Attribute]
class Description extends MetaProperty
{
public static function method(): string
{
return 'note'; // Use ->note() instead of ->description()
}
}

Transform values before they’re returned:

#[Attribute]
class Color extends MetaProperty
{
protected function transform(mixed $value): mixed
{
return "text-{$value}-500"; // 'green' becomes 'text-green-500'
}
}

Provide defaults for cases without the attribute:

#[Attribute]
class Priority extends MetaProperty
{
public function defaultValue(): mixed
{
return 'normal'; // Cases without Priority attribute return 'normal'
}
}

Find a case by its metadata value (throws ValueError if not found):

TaskStatus::fromMeta(Color::make('green')); // TaskStatus::COMPLETED
TaskStatus::fromMeta(Color::make('blue')); // Error: ValueError

Find a case by its metadata value (returns null if not found):

TaskStatus::tryFromMeta(Color::make('green')); // TaskStatus::COMPLETED
TaskStatus::tryFromMeta(Color::make('blue')); // null
#[Attribute]
class Color extends MetaProperty {}
#[Attribute]
class Icon extends MetaProperty {}
#[Attribute]
class Label extends MetaProperty {}
#[Meta(Color::class, Icon::class, Label::class)]
enum OrderStatus: string
{
use Metadata;
#[Color('yellow')] #[Icon('clock')] #[Label('Pending')]
case Pending = 'pending';
#[Color('blue')] #[Icon('truck')] #[Label('Shipped')]
case Shipped = 'shipped';
#[Color('green')] #[Icon('check')] #[Label('Delivered')]
case Delivered = 'delivered';
}
// In your view
<span class="text-<?= $order->status->color() ?>-500">
<i class="icon-<?= $order->status->icon() ?>"></i>
<?= $order->status->label() ?>
</span>
#[Attribute]
class Permissions extends MetaProperty
{
protected function transform(mixed $value): array
{
return is_string($value) ? explode(',', $value) : $value;
}
}
#[Meta(Permissions::class)]
enum Role: string
{
use Metadata;
#[Permissions('read')]
case GUEST = 'guest';
#[Permissions('read,write')]
case USER = 'user';
#[Permissions('read,write,delete,admin')]
case ADMIN = 'admin';
}
if (in_array('write', $user->role->permissions())) {
// User can write
}
#[Attribute]
class AllowedTransitions extends MetaProperty {}
#[Meta(AllowedTransitions::class)]
enum OrderStatus: string
{
use Metadata;
#[AllowedTransitions(['shipped', 'canceled'])]
case Pending = 'pending';
#[AllowedTransitions(['delivered', 'returned'])]
case Shipped = 'shipped';
#[AllowedTransitions(['returned'])]
case Delivered = 'delivered';
}
$canTransitionTo = in_array(
$newStatus->value,
$currentStatus->allowedTransitions()
);

Add @method annotations for better IDE support:

/**
* @method string description()
* @method string color()
* @method string icon()
*/
#[Meta(Description::class, Color::class, Icon::class)]
enum TaskStatus: int
{
use Metadata;
// ...
}

Or create a trait for reusable metadata:

/**
* @method string color()
* @method string icon()
*/
trait HasUIMetadata
{
use Metadata;
}
#[Meta(Color::class, Icon::class)]
enum TaskStatus: int
{
use HasUIMetadata;
// ...
}