Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Enumerator Laravel Package

laranail/enumerator

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require laranail/enumerator
    

    No manual service provider registration needed (auto-discovered).

  2. Define an Enum: Create a class extending Laranail\Enumerator\Enum:

    use Laranail\Enumerator\Enum;
    
    enum UserRole: string
    {
        use HasEnumerator;
    
        case ADMIN = 'admin';
        case EDITOR = 'editor';
        case VIEWER = 'viewer';
    
        public function label(): string
        {
            return match($this) {
                self::ADMIN => 'Administrator',
                self::EDITOR => 'Content Editor',
                self::VIEWER => 'Read-only User',
            };
        }
    }
    
  3. First Use Case: Use the enum in a model with HasEnumerator:

    use Laranail\Enumerator\HasEnumerator;
    
    class User extends Model
    {
        use HasEnumerator;
    
        protected $casts = [
            'role' => UserRole::class,
        ];
    }
    

    Now User::first()->role returns a typed UserRole enum with built-in label access ($user->role->label()).


Implementation Patterns

Core Workflows

  1. Declarative Attributes: Define metadata directly in the enum:

    enum Status: string
    {
        case DRAFT = 'draft';
        case PUBLISHED = 'published';
        case ARCHIVED = 'archived';
    
        public function attributes(): array
        {
            return [
                self::PUBLISHED => [
                    'color' => 'green',
                    'icon' => 'check-circle',
                ],
                self::ARCHIVED => [
                    'color' => 'gray',
                    'icon' => 'archive',
                ],
            ];
        }
    }
    

    Access via $status->attributes['color'].

  2. State Machines: Define transitions with guards:

    enum OrderStatus: string
    {
        case PENDING = 'pending';
        case PROCESSING = 'processing';
        case SHIPPED = 'shipped';
        case CANCELLED = 'cancelled';
    
        public function transitions(): array
        {
            return [
                self::PENDING => [
                    self::PROCESSING => fn($order) => $order->isPaid(),
                ],
                self::PROCESSING => [
                    self::SHIPPED => fn() => true,
                    self::CANCELLED => fn() => true,
                ],
            ];
        }
    }
    

    Use OrderStatus::transition($from, $to, $context) to validate transitions.

  3. Bitmask Support: Combine flags:

    enum Permissions: int
    {
        case READ = 1 << 0;
        case WRITE = 1 << 1;
        case DELETE = 1 << 2;
    
        public function is(Permissions $mask): bool
        {
            return ($this->value & $mask->value) === $mask->value;
        }
    }
    

    Usage: $user->permissions->is(Permissions::READ | Permissions::WRITE).

  4. Validation: Use built-in rules:

    use Laranail\Enumerator\Rules\EnumValue;
    
    $request->validate([
        'role' => ['required', new EnumValue(UserRole::class)],
    ]);
    

Integration Patterns

  1. Eloquent: Cast enums directly in $casts and use HasEnumerator for dynamic behavior.

  2. Blade Components: Render enums with labels/icons:

    @enum(UserRole::class, $user->role)
    

    Customize via @enum('UserRole', $role, ['template' => 'custom-template']).

  3. Filament/Livewire: Use EnumField or EnumSelect components:

    use Laranail\Enumerator\Filament\Fields\EnumSelect;
    
    EnumSelect::make('role')
        ->enum(UserRole::class)
        ->required(),
    
  4. Translations: Localize labels dynamically:

    public function label(): string
    {
        return __("enums.user_role.{$this->value}");
    }
    

    Or use the HasTranslations trait for bulk localization.

  5. Dynamic Enums: Store enum values in the database:

    enum DynamicStatus: string
    {
        use HasDynamicEnumerator;
    
        protected static string $table = 'dynamic_statuses';
    }
    

Gotchas and Tips

Common Pitfalls

  1. Enum Value Conflicts: Ensure enum values are unique. The package validates this during runtime but may throw EnumValueConflictException if duplicates exist.

  2. Case Sensitivity: Enum values are case-sensitive. Use strtolower() or strtoupper() in comparisons if needed:

    if ($enum->value === strtolower($input)) { ... }
    
  3. State Machine Circular References: Avoid infinite loops in transitions. Use explicit guards:

    self::PROCESSING => [
        self::SHIPPED => fn() => false, // Disallow self-transitions
    ]
    
  4. Bitmask Overlaps: Ensure bitmask flags don’t overlap unintentionally. Test with:

    assert((Permissions::READ->value & Permissions::WRITE->value) === 0);
    
  5. Database Backed Enums: For HasDynamicEnumerator, ensure the database table exists and has the correct schema:

    php artisan enumerator:table dynamic_statuses
    

Debugging Tips

  1. Enum Dump: Use the dump() helper for enums:

    \Laranail\Enumerator\Support\dump($enum);
    

    Shows all metadata (labels, attributes, transitions).

  2. Validation Errors: Check enum validation messages:

    $validator->errors()->getMessages();
    

    Customize messages in app/Providers/AppServiceProvider:

    Validator::extend('enum_value', function ($attribute, $value, $parameters) {
        return EnumValue::validate($value, $parameters[0]);
    });
    
  3. State Machine Debugging: Log transitions:

    OrderStatus::transition($from, $to, $order)
        ->whenFailed(fn($errors) => \Log::error($errors));
    

Performance Tips

  1. Cache Transitions: Precompute transition rules if the enum is static:

    public function transitions(): array
    {
        return cache()->remember('enum.transitions.OrderStatus', now()->addHours(1), fn() => [
            // ...
        ]);
    }
    
  2. Batch Operations: Use Enum::hydrate() for bulk creation:

    $roles = UserRole::hydrate(['ADMIN', 'EDITOR']);
    
  3. Avoid Reflection Overhead: For large enums, preload attributes:

    $enum->loadAttributes();
    

Extension Points

  1. Custom Attributes: Extend HasEnumAttributes to add logic:

    trait CustomAttributes
    {
        public function isActive(): bool
        {
            return $this->attributes['active'] ?? false;
        }
    }
    
  2. Artisan Commands: Generate enums from migrations:

    php artisan enumerator:make UserRole --values="ADMIN,EDITOR,VIEWER"
    
  3. Rector Rules: Use Rector to migrate legacy string constants to enums:

    vendor/bin/rector process src --dry-run
    
  4. Testing: Use EnumTestCase for assertions:

    $this->assertEnumEquals(UserRole::ADMIN, $user->role);
    $this->assertEnumTransitionAllowed(OrderStatus::PENDING, OrderStatus::PROCESSING, $order);
    
  5. GraphQL/OpenAPI: Enable modules in config/enumerator.php:

    'modules' => [
        'graphql' => true,
        'openapi' => true,
    ],
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
andydefer/laravel-notification
adachsoft/cli-process-tester
jhaskell13/laraflow
sebastienheyd/boilerplate-media-manager
ccast/tagixo-primix
pretendtrue/laravel-builder
sawmainek/laravel-scout-tntsearch-driver
tomshaw/laravel-calendar-table
dibakar/laravel-ownership
steadrun/laravel-monitor
labyrinthe/connect-laravel
elmogy/layan
drewdan/sentinel-client
dskripchenko/laravel-llm
fatryst/nuonuo
stevenay/myanfont
gmostafa/php-graphql-client
xeviant/paystack
snowsoft/faker
meditationsteps/blogetc