osama-98/laravel-enum-translatable
A Laravel package for adding translations to PHP enums. Define localized labels and descriptions for enum cases using Laravel’s translation system, making it easy to display human-readable enum values across multiple languages.
wrap() is the single funnel where untrusted input (HTTP payloads, CSV imports, legacy DB columns, queue messages) becomes a domain enum. 2.4 makes that funnel closed: the result is always an instance of the calling enum or null, never a foreign enum passed through. That is the invariant product code actually wants at a controller or import boundary.ValueError on no match) vs. non-strict (null) maps cleanly onto a product decision: hard-fail with a 422 on write paths, degrade gracefully on read/display paths (unknown legacy status renders as "Unknown" rather than a 500).?static removes instanceof guards and inline @var docblocks from every call site. This is a small per-call saving multiplied across the codebase, and it makes IDE/static-analysis feedback trustworthy enough to gate CI on.'0'-backed case previously returned null because the emptiness check used empty(). Any domain where '0' is a legitimate value — zero-indexed tiers, '0'-coded statuses from a legacy system, boolean-ish flags stored as '0'/'1' — was silently misclassifying valid records. Worth a data audit: query for rows whose stored value is '0' and confirm they were rendering correctly before this upgrade.tryFrom/from handling), and safely tightening type hints under PHPStan/Psalm at a chosen level.Adopt when:
Enum::tryFrom($x) ?? Default patterns and want the fallback policy to be explicit per call site.'0'-valued cases in production — 2.4 fixes a silent null.Look elsewhere / don't adopt when:
Role → Status via a declared table). 2.4 resolves foreign enums by value re-lookup, not by an authored mapping. If two enums share a backing value but the semantic mapping differs, you'll get a plausible-but-wrong match — model that explicitly instead.wrap() returning a foreign enum, it now gets a re-resolved case, a ValueError, or null. Treat 2.4 as a migration, not a patch: grep for wrap( calls whose argument could be an enum instance rather than a scalar.For executives (one paragraph): We're standardizing how the application converts raw input — form submissions, API calls, imported spreadsheets, legacy database columns — into the typed status and role values our business rules depend on. Today that conversion is handled inconsistently across the codebase, and the failure mode is familiar: an unrecognized or malformed value slips through and surfaces later as a wrong-state record or a 500. This release of our enum library closes the two remaining holes we knew about: it stops returning a different type than the caller asked for, and it fixes a bug where the legitimate value '0' was silently treated as "no value." Adoption is a small, contained code change with no new infrastructure, no vendor contract, and no runtime cost. The payoff is fewer production incidents traced to bad enum handling and less engineer time spent writing defensive checks at every call site.
For engineering leads: 2.4 narrows EnumWrappable::wrap() from ?BackedEnum to ?static, which makes static analysis and IDE completion match the README's long-standing promise and removes the need for instanceof guards at call sites. It also changes behavior: foreign backed enums are no longer passed through — they're unwrapped to their backing value and re-resolved against the calling enum, so Status::wrap(Role::ADMIN) yields a Status case, ValueError in strict mode, or null in non-strict mode. Plan the upgrade accordingly: audit every wrap() call site where the argument may already be an enum instance, and be aware that value-collision between enums now produces a value-based match rather than a type-preserving pass-through. Separately, wrap() no longer short-circuits on empty(), so '0'-backed cases resolve correctly; check any dashboards or exports that may have been quietly dropping those records. Coverage and README were extended for both the foreign-enum rule and the empty-value contract, so the new semantics are testable rather than tribal knowledge.
How can I help you explore Laravel packages today?