archtechx/enums

repository·master·Indexed 20 days ago

https://github.com/archtechx/enums

A collection of PHP 8.1+ helpers designed to extend native Enums. Provides traits for retrieving primitives via InvokableCases, extracting names, values, and options, enhancing instantiation with the From trait, adding custom attributes via the Metadata trait, and performing semantic comparisons with the Comparable trait.

Tokens
2.5K
Snippets
10
Records
11
Agent score
19%

What's inside archtechx/enums

  1. Add metadata to enum cases with Metadata trait

    master

    The Metadata trait allows you to attach custom attributes (meta properties) to enum cases and access them via methods on the enum instance.

    Implementation Steps

    1. Define meta property classes extending MetaProperty.
    2. Use the #[Meta(...)] attribute on the enum to register the properties.
    3. Apply attributes to specific cases.

    Customizing Meta Properties

    • method(): Override to change the name of the generated getter method (e.g., Description becomes note() instead of description()).
    • transform(mixed $value): Override to modify the value returned by the getter.
    • defaultValue(): Specify a value to return if a case does not have the attribute applied.

    Accessing Metadata

    • TaskStatus::CASE->propertyName()
    • TaskStatus::fromMeta(MetaPropertyInstance): Returns the enum case matching the metadata.
    • TaskStatus::tryFromMeta(MetaPropertyInstance): Returns the enum case or null.
    use ArchTech\Enums\Metadata;
    use ArchTech\Enums\Meta\Meta;
    use ArchTech\Enums\Meta\MetaProperty;
    
    #[Attribute]
    class Color extends MetaProperty
    {
        protected function transform(mixed $value): mixed
        {
            return "text-{$value}-500";
        }
    }
    
    #[Meta(Color::class)]
    enum TaskStatus: int
    {
        use Metadata;
    
        #[Color('red')]
        case INCOMPLETE = 0;
    
        #[Color('green')]
        case COMPLETED = 1;
    }
    
    TaskStatus::COMPLETED->color(); // 'text-green-500'
    
    // Finding case by metadata
    TaskStatus::fromMeta(Color::make('green')); // TaskStatus::COMPLETED
  2. Configure PHPStan for InvokableCases

    master

    To ensure PHPStan understands the InvokableCases trait (which allows calling enum cases as functions), include the provided extension in your phpstan.neon file.

    If you use phpstan/extension-installer, this is handled automatically.

    includes:
      - ./vendor/archtechx/enums/extension.neon
  3. Compare enums with Comparable trait

    master

    The Comparable trait adds semantic comparison methods to your enums:

    • is(mixed $case): Returns true if the instance matches the provided case.
    • isNot(mixed $case): Returns true if the instance does not match.
    • in(array $cases): Returns true if the instance is present in the array.
    • notIn(array $cases): Returns true if the instance is not in the array.
    use ArchTech\Enums\Comparable;
    
    enum TaskStatus: int
    {
        use Comparable;
        case INCOMPLETE = 0;
        case COMPLETED = 1;
    }
    
    TaskStatus::INCOMPLETE->is(TaskStatus::INCOMPLETE); // true
    TaskStatus::INCOMPLETE->isNot(TaskStatus::COMPLETED); // true
    TaskStatus::INCOMPLETE->in([TaskStatus::INCOMPLETE, TaskStatus::COMPLETED]); // true
    TaskStatus::INCOMPLETE->notIn([TaskStatus::COMPLETED]); // true
  4. Get enum values with Values trait

    master

    Apply the Values trait to an enum to retrieve an array of case values (for backed enums) or case names (for pure enums).

    use ArchTech\Enums\Values;
    
    enum TaskStatus: int
    {
        use Values;
    
        case INCOMPLETE = 0;
        case COMPLETED = 1;
        case CANCELED = 2;
    }
    
    TaskStatus::values(); // [0, 1, 2]
  5. Use InvokableCases to get enum primitives

    master

    The InvokableCases trait allows you to retrieve the underlying value of a backed enum or the name of a pure enum by "invoking" the case as a function. This avoids manually appending ->value and allows enums to be used easily as array keys.

    • Static call: MyEnum::CASE() returns the primitive.
    • Instance call: $enumInstance() returns the primitive.

    This provides good IDE support with autosuggestions.

    use ArchTech\Enums\InvokableCases;
    
    enum TaskStatus: int
    {
        use InvokableCases;
    
        case INCOMPLETE = 0;
        case COMPLETED = 1;
        case CANCELED = 2;
    }
    
    // Usage
    TaskStatus::INCOMPLETE(); // 0
    
    $status = TaskStatus::COMPLETED;
    $status(); // 1
    
    'statuses' => [
        TaskStatus::INCOMPLETE() => ['some configuration'],
        TaskStatus::COMPLETED() => ['some configuration'],
    ];
  6. Instantiate enums from names or values with From trait

    master

    The From trait enhances enum instantiation:

    • Pure Enums: Adds from() and tryFrom() (which behave like fromName() and tryFromName()).
    • All Enums: Adds fromName() and tryFromName().

    Note: For BackedEnum instances, the standard from() and tryFrom() methods are not overridden to avoid fatal errors.

    use ArchTech\Enums\From;
    
    enum Role
    {
        use From;
    
        case ADMINISTRATOR;
        case SUBSCRIBER;
        case GUEST;
    }
    
    Role::from('ADMINISTRATOR'); // Role::ADMINISTRATOR
    Role::tryFrom('GUEST');      // Role::GUEST
    Role::tryFrom('NEVER');     // null
    
    // Using name-based methods
    enum TaskStatus: int
    {
        use From;
        case INCOMPLETE = 0;
    }
    
    TaskStatus::fromName('INCOMPLETE'); // TaskStatus::INCOMPLETE
    TaskStatus::tryFromName('MISSING'); // null
  7. Get enum names with Names trait

    master

    Apply the Names trait to an enum to retrieve an array of all case names.

    use ArchTech\Enums\Names;
    
    enum Role
    {
        use Names;
    
        case ADMINISTRATOR;
        case SUBSCRIBER;
        case GUEST;
    }
    
    Role::names(); // ['ADMINISTRATOR', 'SUBSCRIBER', 'GUEST']
  8. Get enum options with Options trait

    master

    Apply the Options trait to an enum to retrieve an associative array of name => value for backed enums, or a list of names for pure enums.

    stringOptions()

    This method generates string representations of your enum options.

    • Arguments: callback(string $name, mixed $value) and string $glue.
    • Defaults: Glue defaults to \n and the callback defaults to generating HTML <option> tags.
    • Pure Enums: For non-backed enums, the name is used for both $name and $value.
    use ArchTech\Enums\Options;
    
    enum TaskStatus: int
    {
        use Options;
    
        case INCOMPLETE = 0;
        case COMPLETED = 1;
        case CANCELED = 2;
    }
    
    TaskStatus::options(); // ['INCOMPLETE' => 0, 'COMPLETED' => 1, 'CANCELED' => 2]
    
    // Custom string representation
    TaskStatus::stringOptions(fn ($name, $value) => "$name => $value", ', '); 
    // returns "INCOMPLETE => 0, COMPLETED => 1, CANCELED => 2"
    
    // Default HTML options
    TaskStatus::stringOptions(); 
    // <option value="0">Incomplete</option>
    // <option value="1">Completed</option>
    // <option value="2">Canceled</option>
  9. Handle UndefinedCaseError

    master
    The ArchTech\Enums\Exceptions\UndefinedCaseError is thrown when attempting to access an enum case that does not exist within the specified enum. This error mimics the standard PHP error message for invalid constant access: Undefined constant EnumName::CaseName. You can catch this exception to handle scenarios where dynamic case resolution fails.
  10. Attach metadata to enums using the Meta attribute

    master

    The Meta attribute allows you to attach custom metadata to an Enum class. You can pass a list of property names or class strings representing MetaProperty objects to the constructor. This metadata can then be used by the library to extend the capabilities of the Enum.

    You can pass properties as a list of arguments or as a single array.

    use ArchTech\Enums\Meta\Meta;
    
    #[Meta('some_property', AnotherMetaProperty::class)]
    enum MyEnum: string
    {
        case A = 'a';
    }
    
    // Or passing an array
    #[Meta(['prop1', 'prop2'])]
    enum MyEnum:
    {
        case A = 'a';
    }