chaim-chv/filament-enum-plural-label
A small Filament plugin that adds plural labels to PHP enums, so enum-backed options read naturally across forms, tables, and filters. Define singular and plural labels once and let Filament display the right form wherever your enum is used.
This release is a compatibility release (Filament v5 / PHP 8.2+), so treat v2.0.0 as the baseline for any new work and as a coordinated upgrade if you are already on v1.x.
v1.x and pin it explicitly ("vendor/package": "^1.0") so a composer update doesn't drag you across the break.composer require vendor/package:^2.0 — if Composer refuses, it is almost always the new explicit illuminate/contracts constraint (^11.28|^12.0|^13.0) rejecting an older Laravel 11 patch release. Bump laravel/framework to at least 11.28 rather than trying to fight the constraint.Htmlable and null returns, and Filament resource integration. That suite is the most reliable specification of the contract's accepted return types — read it first, then skim the README for the interface name you need to implement.Select in a form and a badge-style TextColumn in the table. One enum then feeds filter options, form choices and table rendering from a single source of truth — which is the whole reason to reach for this package over an inline options() array.Contract-on-the-enum. The idiomatic pattern is to implement the interface directly on a backed enum and let the enum own its own presentation: label, and (depending on which methods the contract exposes in your version) colour/icon. This keeps Status::Active->label() available everywhere — Filament resources, notifications, Blade, API serialisation — instead of duplicating a match expression in three places.
Backed enums for persisted state, unit enums for fixed sets. The test suite explicitly covers string, int and unit enums, so both are supported. Use backed enums where the value hits the database; use unit enums for things like a fixed set of display filters where there is no column value.
null means "fall back", not "empty". Returning null from the contract hands control back to Filament's default behaviour (e.g. humanising the case name). Use it deliberately on enum cases where the default is already correct, and return an explicit '' only when you genuinely want a blank label — the two are not interchangeable.
Htmlable for rich output. Returning an Htmlable (the reason illuminate/contracts is now a hard dependency) lets a label carry markup — a coloured dot, an icon span. Wrap this in a small dedicated value object or a HtmlString factory rather than building strings inline, so escaping decisions live in one auditable place.
Reuse one enum across the whole resource. A single enum typically drives the form Select (options(Status::class) or a mapped array), the table column badge, the table filter, and any infolist entry. When you add a case, all four update together — that consistency is the payoff and worth designing around from the start.
Mirror the package's test style. If you wrap or extend this package, copy its approach: one test per return-type variant (string / int / unit / Htmlable / null) plus a Livewire-level Filament resource test that actually renders the component. The Htmlable and null paths are the ones that regress silently.
illuminate/contracts constraint is the sharp edge. ^11.28 is a floor on the whole Laravel 11 line. Projects pinned to 11.0–11.27 will fail to install with no obvious error message; run composer update laravel/framework first.Htmlable output is not automatically safe. If a label interpolates user-controlled data (a name, a note), sanitise before wrapping — Filament will render the markup as-is.cases() will do it for you.dd(MyEnum::Case->label()) in tinker isolates package vs. Filament-configuration issues in seconds.Htmlable dependency suggests the contract's surface is stable and intended to be implemented, not wrapped. Where a config file or publishable stub exists, publish it and keep overrides in config/ rather than editing vendor code, so the next major bump stays a composer update.How can I help you explore Laravel packages today?