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

Enum Bundle Laravel Package

frostiede/enum-bundle

A Symfony bundle that simplifies working with PHP enums, providing integration helpers and utilities to use enum types more cleanly across your application. Ideal for projects adopting PHP 8.1+ enums with Symfony.

View on GitHub
Deep Wiki
Context7

Getting Started

Reality check first: frostiede/enum-bundle is a Symfony bundle, not a Laravel package. There is no ServiceProvider, no Eloquent cast, no Rule::enum integration, and no Flex recipe. For a Laravel developer the day-to-day value is the pattern, not the package — you will almost certainly end up copying 40–60 lines into app/Enums/Concerns/ rather than composer require-ing it into your composer.json.

With that framing, here's the minimal path.

  1. Read the source before installing anything. You don't need it in your tree to evaluate it. Clone or browse the repo and read, in this order:

    • the root *Bundle.php — what it registers;
    • DependencyInjection/*Extension.php — the config tree (and whether options exist at all);
    • Resources/config/services.* — service IDs you'd have to replicate in a Laravel provider;
    • tests/ — often more documentation than the README. If the enums are classes extending an abstract Enum base, stop: that pattern is incompatible with PHP 8.1 native enum and cannot be made to coexist with Laravel's enum casting.
  2. Confirm what native Laravel already gives you. Before porting anything, inventory the gap. Modern Laravel covers the vast majority of what a generic enum helper offers:

    • enum OrderStatus: string casts directly on Eloquent attributes;
    • Rule::enum(OrderStatus::class) validates inbound input;
    • $table->enum() or string columns mirror it at the DB level;
    • ->enum() on AsEnumCollection and enum-aware factories/seeding work out of the box.
  3. Fill the actual gap. The one thing native enums don't ship is a values() / labels() / options() helper. Drop this in app/Enums/Concerns/HasValues.php:

    trait HasValues
    {
        public static function values(): array
        {
            return array_column(self::cases(), 'value');
        }
    
        public static function options(): array
        {
            return array_combine(self::values(), array_map(
                fn (self $c) => $c->label(), self::cases()
            ));
        }
    
        public function label(): string
        {
            return ucfirst(str_replace('_', ' ', $this->value));
        }
    }
    
  4. Pick a first use case — an OrderStatus enum on an orders.status column, cast on the model, validated in a FormRequest with Rule::enum, and rendered via OrderStatus::options() in a Blade <select>. That's the exact surface the bundle advertises, done in ~30 lines you own outright.

Implementation Patterns

The trait pattern (the one you'll actually use). Define every backed enum with use HasValues; and a label() implementation. This keeps the source of truth in the enum case itself, so OrderStatus::Pending->label() and OrderStatus::options() never drift apart — the failure mode you get when labels live in a separate config array.

Validation in FormRequests. Rule::enum(OrderStatus::class) produces a clear error for free. If you want the human label in the message, customize it in the request's messages() and call OrderStatus::label() — don't let the raw 'pending' leak into user-facing copy.

Serialization. Cast enums on the model and let Laravel serialize the backed value in JSON automatically. If you need both the raw value and a label in an API response (common for admin/mobile clients), use an Attribute or JsonResource method that returns ['value' => $this->status->value, 'label' => $this->status->label()]. Never serialize the enum object itself across a queue boundary — jobs holding enum instances break silently after a refactor, and they break post-deploy.

Form and filter options. Model::options() feeds every dropdown in the admin panel. For a status filter on an index page, Rule::enum on the query string plus options() on the view is the whole integration — no extra dependency.

The one place the bundle's idea is genuinely valuable: transitioning between enum states (e.g., approvals, order lifecycle). Write an explicit canTransitionTo() method on the enum itself rather than scattering if chains:

public function canTransitionTo(self $next): bool
{
    return match ($this) {
        self::Pending   => in_array($next, [self::Shipped, self::Cancelled], true),
        self::Shipped   => $next === self::Cancelled,
        self::Cancelled => false,
    };
}

If you're working in a Symfony service (a polyglot codebase, a shared monolith), the honest integration is the same trait above — you don't need the bundle for it there either. Install it only if you've confirmed from the source that the enum implementation is standalone and framework-agnostic, and pin it to an exact tag or commit SHA.

Gotchas and Tips

  • Framework mismatch is the headline. EnumBundle assumes a Symfony kernel and registerBundles(). There is no Laravel service provider, so composer require will pull in transitive symfony/* constraints that frequently collide with Laravel's own (console, http-foundation, routing). Expect a resolution failure before you write code.
  • Check for an abstract Enum base class. If enums extend a base class, that's the pre-8.1 pattern and is architecturally incompatible with PHP 8.1 native enums. Adopting it is a one-way door — you can't incrementally convert class-based enums to native ones.
  • Zero stars, zero dependents, zero downstream users. Treat this as reference code, not a dependency. The decision you're really making is build vs. fork, not adopt vs. ignore.
  • Pin exactly. If you do install: "frostiede/enum-bundle": "dev-master#<sha>" or a fixed tag. ^1.x leaves you exposed to an unpinned push that breaks CI on a fresh clone.
  • Debugging config: if the bundle has an extension, bin/console config:dump-reference <alias> will show the tree — read it before guessing options. Service IDs from Resources/config/services.* are what you'd have to replicate in a Laravel provider.
  • Coercion drift is the silent bug. Backed enums can be int or string. If a column or cache key is on the wrong side of that line, comparisons pass in PHP but fail against the DB. Enforce a rule that only scalar values cross storage, cache, and queue boundaries — never enum instances.
  • Autoload under --optimize. If the bundle's classes assume Symfony kernel registration, composer dump-autoload --optimize on a fresh deploy can surface them as failures. That's the worst time to discover the problem.
  • Extension point if you commit to it: wrap the vendor namespace behind an internal contract — interface HasLabels { public function label(): string; } and interface HasValues { public static function values(): array; }. Call sites reference your interfaces, never FrostieDE\..., so migrating off the vendor is a swap, not a refactor.
  • The exit ramp is cheap. Roughly 50 lines of your own trait covers values(), labels(), options(), and casting — the entire advertised surface. Write that, record the decision in your engineering standards, and skip the dependency entirely.
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.
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource