genealabs/laravel-casts
GeneaLabs Laravel Casts adds flexible custom attribute casting to Eloquent models, making it easy to map database columns to value objects, DTOs, and other PHP classes. Keeps model code clean and cast logic reusable, testable, and simple to configure.
Architecture fit. The credible reading of this package is a Blade form-macro layer: it collapses label + input + error + wrapper markup into single Form::tel(...)-style calls, sitting entirely in the presentation layer. That is a thin architectural footprint — it does not touch Eloquent, routing, or domain logic — but it registers onto the Form facade's Macroable surface, which is global mutable state shared with every other provider in the app. The value-object casting story in description.md is a documentation error, not a feature: native CastsAttributes has existed since Laravel 7, so there is nothing to buy there.
Diligence finding: the package cannot describe itself. The repository listing says "form macros for Blade"; the package documentation describes an Eloquent cast layer; the changelog (0.13.3 — a Tel label fix) confirms form macros. When a dependency's own metadata disagrees three ways, the curation surface has already failed — assume the tests, README, and compatibility claims are equally stale. This is a decision input, not a footnote.
Integration feasibility. Installable via Composer with auto-discovered providers and a pinned version. The complication is the tail: the form-macro reading sits on laravelcollective/html, itself archived. That means adopting one unmaintained package to get a second, and inheriting Form::open's CSRF and method-spoofing behaviour along with it. Zero dependents means zero field evidence that it works on your Laravel/PHP version.
Technical risk.
e() is an XSS vector with no security release coming.Key questions to close before any commitment.
composer.json require, and which macros does src/ actually define? Verify in source, not from the listing.laravelcollective/html already pinned in our graph for other reasons, or would this package be what drags it in?grep -rE 'Form::(tel|email|date|...)' resources/views.) Anything we don't call is pure liability.Stack fit. For form markup on Laravel 7+, native Blade components with @props are first-party, dependency-free, and have no laravelcollective/html tail. spatie/laravel-html covers PHP-built markup if that style is genuinely wanted and is maintained. For value objects, use native CastsAttributes plus purpose-built libraries (moneyphp/money, propaganistas/laravel-phone). This package fits only as legacy continuity, not as a forward choice.
Compatibility work. Pin exact 0.13.3 in composer.json — no caret, no tilde. The Tel label fix landed there; anything earlier renders tel fields wrong and will never be fixed again. Immediately verify Form::open's CSRF token and method spoofing against the current Laravel version, plus old() repopulation on a failed validation round-trip and that $errors actually renders beside the field.
Migration path — make it removable on day one. Wrap every macro call in a project-owned partial:
{{-- resources/views/components/field/tel.blade.php --}}
{{ Form::tel($name, old($name, $value ?? null), ['label' => $label] + $attributes) }}
Swapping the macro for <x-input> later then touches one file, not every call site. For broader existing usage, inventory the macros actually invoked, vendor only those into an internal service provider registering identical names, and drop the package in a single commit — each macro is typically tens of lines of string building.
Sequencing.
composer.json, src/Providers/*, and the macro definitions (15 minutes, before anything else).composer why laravelcollective/html and composer depends genealabs/laravel-casts; stop if this package is what introduces the archived dependency.<input type="tel"> replacement. Not customer-facing, not payment, not compliance-adjacent.assertSee('name="phone"', false)).Maintenance. Archived means we own it permanently: compatibility, security review, and every Laravel/PHP bump become our backlog items with no upstream fix path. Budget an annual compatibility review and name a single owning engineer — unowned archived dependencies are how silent drift accumulates.
Support. There is no upstream channel and no security release process. Escalation is entirely internal; the only mitigation is the wrapper boundary that makes replacement mechanical.
Scaling. Rendering cost is negligible; the scaling risk is coordination. Macro registration happens at provider boot onto shared global state, so collision risk grows with team size and package count. Any teammate's AppServiceProvider macro can overwrite ours and last registration silently wins — verify Form::hasMacro('tel') in tinker after any related change.
Failure modes to watch.
" and <script> before shipping.laravelcollective/html breaking CSRF or method spoofing first and quietly.php artisan view:clear; composer dump-autoload if auto-discovery didn't run).Ramp-up. Low for the mechanics — a mid-level developer reproduces a macro in an afternoon, which is precisely the honest comparison point against permanent stewardship. The real cost is the audit (escaping, old(), error rendering) and the wrapper refactor, both of which must be scheduled rather than assumed.
Recommendation for the roadmap. Greenfield: no — an archived dependency duplicating a first-party capability is indefensible. If it is already in the stack, treat it as frozen, schedule wrapper partials plus replacement in the next maintenance window, and hold it away from money, identity, phone, address, or compliance-adjacent data. If the actual need is value-object casting, skip this package entirely and write native CastsAttributes — 20–40 lines each, owned and tested by us.
How can I help you explore Laravel packages today?