Skip to content

Repository files navigation

Backed Enum Helpers

Helpers for PHP backed enums, including BenSampo-style APIs (fromValue, hasValue, getInstances, descriptions, select arrays) and an EnumValue validation rule for Laravel.

Installation

composer require langleyfoxall/backed-enum-helpers

Requires PHP 8.4+ and Laravel 11+.

Usage

BackedEnumHelpers trait

use LangleyFoxall\BackedEnumHelpers\Concerns\BackedEnumHelpers;

enum Status: string
{
    use BackedEnumHelpers;

    case Active = 'active';
    case On_Hold = 'on_hold';
    case Archived = 'archived';
}

Status::Active();                    // Status::Active
Status::hasValue('active');          // true
Status::fromValue('on_hold');        // Status::On_Hold
Status::getDescription('on_hold');   // "On Hold"
Status::getInstances();              // Status::cases()
Status::getValues();                 // ['active', 'on_hold', 'archived']
Status::getKeys();                   // ['Active', 'On_Hold', 'Archived']
Status::asArray();                   // ['Active' => 'active', ...]
Status::asSelectArray();             // ['active' => 'Active', 'on_hold' => 'On Hold', ...]
Status::asSelectOptions();           // [['value' => 'active', 'label' => 'Active'], ...]
Status::fromDescription('On Hold');  // Status::On_Hold (case-insensitive)
Status::asDescriptionMap();          // ['active' => Status::Active, 'on hold' => Status::On_Hold, ...]
Status::getRandomInstance();
Status::getRandomValue(['active']);  // random value excluding 'active'
Status::toLabel('on_hold');          // alias of getDescription()

HasEnumMembers trait

Optional extra helpers for apps that relied on BenSampo instance/key APIs (is, isNot, in, hasKey, fromKey, getValue, getRandomKey). Use alongside BackedEnumHelpersgetValue() needs fromValue() from that trait:

use LangleyFoxall\BackedEnumHelpers\Concerns\BackedEnumHelpers;
use LangleyFoxall\BackedEnumHelpers\Concerns\HasEnumMembers;

enum Status: string
{
    use BackedEnumHelpers;
    use HasEnumMembers;

    case Active = 'active';
    case Archived = 'archived';
}

Status::Active->is('active');     // true
Status::Active->isNot('Archived'); // true
Status::Active->in(['archived']); // false
Status::hasKey('Active');         // true
Status::fromKey('Active');        // Status::Active
Status::getValue('Active');       // 'active'
Status::getRandomKey(['Active']);

Custom labels via a DESCRIPTIONS map (case name → label). Unmapped cases still use the default ucwords fallback. Prefer this over repeating instanceof BackedEnum checks in each enum:

enum QuoteStatuses: string
{
    use BackedEnumHelpers;

    case ReadyToSend = 'ready_to_send';
    case Sent = 'sent';

    private const DESCRIPTIONS = [
        'ReadyToSend' => 'Ready To Send',
        'Sent' => 'Sent',
    ];
}

QuoteStatuses::toLabel('ready_to_send'); // "Ready To Send"
QuoteStatuses::toLabel(QuoteStatuses::Sent); // "Sent"
QuoteStatuses::fromDescription('ready to send'); // QuoteStatuses::ReadyToSend
QuoteStatuses::asDescriptionMap(); // ['ready to send' => QuoteStatuses::ReadyToSend, 'sent' => QuoteStatuses::Sent]

fromDescription() / asDescriptionMap() invert toLabel() / asSelectArray(): CSV cells and other label input resolve to enum instances. Matching is case-insensitive by default (fromDescription('On Hold', caseInsensitive: false) for an exact match). Duplicate descriptions throw rather than silently overwriting.

Or override description() when a map is not enough:

public function description(): string
{
    return match ($this) {
        self::Active => 'Currently active',
        default => ucwords(str_replace('_', ' ', strtolower($this->name))),
    };
}

EnumValue / EnumKey validation rules

Drop-in replacements for BenSampo's EnumValue and EnumKey rules — including the same failure messages (The value you have entered is invalid. / The key you have entered is invalid.):

use LangleyFoxall\BackedEnumHelpers\Rules\EnumKey;
use LangleyFoxall\BackedEnumHelpers\Rules\EnumValue;

$request->validate([
    'status' => ['required', new EnumValue(Status::class)],
    'status_key' => ['required', new EnumKey(Status::class)],
    // or as string rules:
    'status' => ['required', 'enum_value:'.Status::class.',true'],
    'status_key' => ['required', 'enum_key:'.Status::class.',true'],
]);

Override globally by defining enum_value / enum_key in your app's lang/{locale}/validation.php (same as BenSampo). Otherwise the package defaults apply. No app wrapper rule is needed for message parity.

Migrating from BenSampo Enum

  1. Convert enum classes to native PHP backed enums.
  2. Add use LangleyFoxall\BackedEnumHelpers\Concerns\BackedEnumHelpers; on each enum.
  3. Where call sites use is / isNot / in / hasKey / fromKey / getValue / getRandomKey, also use LangleyFoxall\BackedEnumHelpers\Concerns\HasEnumMembers;.
  4. Replace use BenSampo\Enum\Rules\EnumValue; / EnumKey with the package rules (LangleyFoxall\BackedEnumHelpers\Rules\...). Failure messages match BenSampo by default.
  5. Remove bensampo/laravel-enum and any app-level EnumValue / EnumKey shims that only existed to restore the old message text.

Common method names are preserved so most call sites can stay unchanged.

Testing

composer test

Changelog

Please see CHANGELOG for more information on what has changed recently.

Credits

License

The GNU LGPL v3.0. Please see License File for more information.

About

Helpers for PHP backed enums, including BenSampo-style APIs (`fromValue`, `hasValue`, `getInstances`, descriptions, select arrays) and an `EnumValue` validation rule for Laravel.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages