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

Enums For Laravel Laravel Package

roundly-consulting/enums-for-laravel

Enums for Laravel brings first-class PHP enum support to Laravel applications. Cast enum attributes in Eloquent models, validate enum input, and work with backed values across requests and APIs. It keeps code type-safe, readable, and easy to integrate without extra boilerplate.

View on GitHub
Deep Wiki
Context7

Getting Started

Install

composer require roundly-consulting/enums-for-laravel

Requires PHP 8.1+ and a Laravel version with package auto-discovery (9+). No manual provider registration is typically needed; if you're on an older skeleton, check the package's composer.json extra.laravel block for the provider/alias names rather than guessing.

Look here first (in this order)

  1. README.md — the package is young and thinly documented, so the README is short; read it fully.
  2. src/ — find the three things you actually care about: the Eloquent cast, the validation rule, and the Artisan generator command.
  3. config/ (if present) — check for a publishable config before you start writing lang files.

First use case: a status enum on a model

Define a backed enum:

namespace App\Enums;

enum OrderStatus: string
{
    case Pending = 'pending';
    case Paid    = 'paid';
    case Shipped = 'shipped';
}

Add the column ($table->string('status')->default('pending')->index();), then cast it and validate it in one request:

// app/Models/Order.php
protected $casts = ['status' => OrderStatus::class];

// app/Http/Requests/StoreOrderRequest.php
public function rules(): array
{
    return [
        'status' => ['required', OrderStatus::rule()], // or the package's rule class
    ];
}

If your only goal is casting, stop and check: Laravel has cast backed enums natively since 9.x. This package earns its keep on validation + labels/serialization, so evaluate it against that, not against the cast alone.

Implementation Patterns

1. Cast + validate + serialize as one pipeline The natural workflow is: enum class → migration column → $casts entry → FormRequest rule → API Resource. Keep all five steps for every enum-backed attribute so you never scatter in_array($value, [...]) checks through controllers.

2. Centralize output shape in an API Resource Don't hand-roll ['value' => $this->status->value, 'label' => ...] in every resource. Either wrap it once:

// app/Http/Resources/EnumResource.php
return [
    'value' => $this->value,
    'label' => $this->label(), // package localization helper
];

or add a toArray() / trait on the enum itself so json_encode produces the same shape everywhere.

3. Localization driven by case name Put translations in lang/{locale}/enums.php keyed by enum class + case (verify the exact key convention in the package source). A missing key should fall back to the case name, not throw — assert this in a test when you first wire it up, because a silent fallback will hide typos in your lang files for months.

4. Generators for consistency Use the provided make-style command for every new enum instead of hand-creating files. This keeps the namespace, string|int backing, and any package trait consistent. Publish the stubs if the package allows it so your team adds the same docblock/cases by default.

5. FormRequest + query filtering Validation covers input; filtering still needs care. For ?status=paid, validate first, then compare against the backed value:

Order::when($request->validated('status'),
    fn ($q, $s) => $q->where('status', $s));

Passing an enum instance into where() works, but passing an array of enums (multi-select filters) does not — map to ->value explicitly.

6. Factories and seeders Order::factory()->create(['status' => OrderStatus::Paid]) is the clean path. For random data, fake()->randomElement(OrderStatus::cases()) keeps seeded data inside the enum's domain automatically.

7. Integration with policies/gates Because enums are backed by scalar values, $order->status === OrderStatus::Paid is strict-safe, while $order->status == 'paid' silently compares string to enum and fails in some PHP versions. Standardize on enum-to-enum comparison in domain code and ->value only at the DB/serialization boundary.

Gotchas and Tips

  • Significant native overlap. Eloquent enum casting and Rule::enum() are both core Laravel now. Before adopting, diff the package's rule against Rule::enum() — the only defensible reasons to add this dependency are the label/localization helpers and the generators. With 5 stars and 0 dependents, every feature you use must justify its maintenance risk.
  • Tiny community, thin answers. Zero dependents means no Stack Overflow trail. When something breaks, you are reading src/ directly. If you ship this to production, pin the version in composer.json and treat an upgrade as a code review, not a composer update.
  • Backed vs pure enums. Persistence, validation, and JSON serialization all require a backed enum. A pure (unit) enum will cast in memory but fail on save/validate — decide early and enforce it.
  • String vs int backing. String-backed enums are far easier to debug in the DB and safer for ALTER TABLE migrations. Int-backed enums save bytes but make logs and ad-hoc queries painful. Pick strings unless you have a measured reason.
  • Localization key drift. Labels keyed by case name are case-sensitive. A renamed case (Pending → PENDING) silently drops to the fallback. Add a test that iterates Enum::cases() and asserts a translated label exists for each.
  • Serialization surprises. Raw json_encode($model) on a cast enum emits the value, which is usually what you want — but nested enums in arrays and toArray() on resources can differ. Snapshot one API response per enum in a test so the contract is pinned.
  • Nullable enums. A nullable column with a non-nullable cast returns null; guard ?->label() everywhere or you'll get "call to member function on null" in Blade.
  • Validation edge cases. Combine the package rule with ['sometimes', 'nullable'] explicitly. A rule that rejects null combined with sometimes on a PATCH endpoint is a classic 422 you'll chase for an hour.
  • Debugging: dd(OrderStatus::from($model->getRawOriginal('status'))) separates cast problems from persisted value problems faster than dumping the model.
  • Extension point: the enum class itself. Adding label(), color(), or isTerminal() methods to your enums keeps package-specific helpers out of your domain classes and makes it trivial to drop the dependency later if it stalls.
  • Migration path: because the value-add is thin, isolate your usage behind one or two app-level helpers (e.g. a HasEnumLabels trait). If the package goes unmaintained, swapping in native Laravel + your trait should be a one-file change.
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.
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib