Enhancing Enum Constants in Laravel with Description and Label Attributes
Tags: laravel, php, enum, attributes
Published: 2024-06-19 09:40:15

PHP attributes provide a powerful way to add metadata to classes and constants, enhancing readability and organization in frameworks like Laravel. Let's explore how to use `Description` and `Label` attributes to annotate enum constants in Laravel, specifically with an `OrderStatus` example.

### Understanding PHP Attributes in Enums

PHP attributes allow us to attach metadata to classes, methods, properties, and constants. In Laravel, this feature can streamline the management of descriptive metadata for enum constants such as status codes or types.

### Implementing Description and Label Attributes

#### Step 1: Define Attribute Classes

Create attribute classes that extend a base `AttributeProperty` class to encapsulate metadata values:

```php
<?php

namespace App\Attributes;

use Attribute;

/* Base class for attribute properties */
#[Attribute(Attribute::TARGET_CLASS_CONSTANT)]
class AttributeProperty
{
    public const ATTRIBUTE_PATH = 'App\Attributes\\';

    public function __construct(
        protected mixed $value,
    ) {
    }

    public function get(): mixed
    {
        return $this->value;
    }
}

/* Attribute for describing enum constants */
#[Attribute(Attribute::TARGET_CLASS_CONSTANT)]
class Description extends AttributeProperty
{
}

/* Attribute for labeling enum constants */
#[Attribute(Attribute::TARGET_CLASS_CONSTANT)]
class Label extends AttributeProperty
{
}

<?php

namespace App\Traits;

use App\Attributes\AttributeProperty;
use BadMethodCallException;
use Illuminate\Support\Str;
use ReflectionAttribute;
use ReflectionEnum;

trait AttributableEnum
{
    /**
     * Call the given method on the enum case
     *
     */
    public function __call(string $method, array $arguments): mixed
    {
        // Get attributes of the enum case with reflection API
        $reflection = new ReflectionEnum(static::class);
        $attributes = $reflection->getCase($this->name)->getAttributes();

        // Check if attribute exists in our attributes list
        $filtered_attributes = array_filter($attributes, fn (ReflectionAttribute $attribute) => $attribute->getName() === AttributeProperty::ATTRIBUTE_PATH . Str::ucfirst($method));

        // If not, throw an exception
        if (empty($filtered_attributes)) {
            throw new BadMethodCallException(sprintf('Call to undefined method %s::%s()', static::class, $method));
        }

        return array_shift($filtered_attributes)->newInstance()->get();
    }
}
```

#### Step 2: Create the Enum Using Attributes

Define an enum `OrderStatus` that uses `Label` and `Description` attributes to annotate its constants:

```php
<?php

namespace App\Enums;

use App\Attributes\Label;
use App\Attributes\Description;
use App\Attributes\AttributeProperty;
use App\Traits\AttributableEnum;

enum OrderStatus: string
{
    use AttributableEnum;

    #[Label('Pending')]
    #[Description('Order is pending')]
    case Pending = 'pending';

    #[Label('Confirmed')]
    #[Description('Order is confirmed')]
    case Confirmed = 'confirmed';

    #[Label('Canceled')]
    #[Description('Order has been canceled')]
    case Canceled = 'canceled';

    #[Label('Completed')]
    #[Description('Order has been completed')]
    case Completed = 'completed';
}
```

#### Step 3: Accessing Enum Attributes

With the defined `Description` and `Label` attributes, you can access their values through methods defined in `AttributeProperty` or directly within your Laravel application's logic. For example, to retrieve the description of an enum constant:

```php
<?php

$statusDescription = OrderStatus::Pending()->getDescription();
// Output: 'Order is pending'
```

### Conclusion

Using PHP attributes such as `Label` and `Description` with enums in Laravel enables you to centralize and manage descriptive metadata for enum constants effectively. This approach improves code clarity, simplifies maintenance, and enhances the readability of your Laravel applications.

By leveraging attributes in enums, you can streamline how you define and use status codes, types, or any other constant values that require additional descriptive information.

Start using PHP attributes in enums today to enhance your Laravel projects and maintain a clean, organized codebase!