maskow/livewire-combined-request
Laravel FormRequest base class that works in HTTP controllers, APIs, and Livewire 3/4 components. Write validation rules, authorization, required parameters, and file upload handling once, then reuse them everywhere. Zero configuration, Laravel 10/11/12 ready.
Verdict: A narrow, well-scoped utility that solves a real duplication problem, but with adoption signals (1 star, 0 dependents, single maintainer) that make it a pilot-and-contain candidate rather than an org-wide standard.
Architecture fit. The package is a thin extension of Illuminate\Foundation\Http\FormRequest plus a static bridge (validateLivewire) that hydrates a request instance from Livewire component state. That is architecturally sound: it reuses Laravel's own authorization, validation, and hook lifecycle rather than reimplementing it. It fits best in a Laravel monolith where the same domain entity is edited through both an API/controller path and a Livewire path — the "write rules once" claim is genuinely satisfied there. It is a poor fit for API-only or Livewire-only codebases (zero benefit) and irrelevant for Inertia/SPA stacks. Two design choices deserve scrutiny: the optional camelCase↔snake_case translator and the notifyAuthorizationUsing callback are both configured via global static methods on the base class, which is a mutable-global-state pattern rather than per-request configuration. Also note that App\Http\Requests is now effectively a UI-layer namespace, which slightly muddies layering.
Integration feasibility. Low friction: composer require, no service provider, no config file, PHP 8.1+ / Laravel 10–12 / Livewire 3–4. The integration tripwires are behavioral, not installational. The $requiredParameters contract must match route segment names exactly in HTTP, and must be supplied by hand in Livewire — drift between the two is the most likely source of runtime failure. FormRequest's semantics assume one instantiation per HTTP request lifecycle; a Livewire component may invoke validation repeatedly, so anything relying on framework-wired state (redirector, session, named error bags) needs explicit verification.
Technical risk. Medium, concentrated in three areas. (1) Bus factor / supply chain: one maintainer, one star, zero dependents, no visible security policy; you will be the first to hit edge cases and the only one to fix them. (2) Abstraction thinness cuts both ways: the core value is maybe 100–150 lines of glue, meaning the cost of in-housing the same base class (or wrapping the package behind an internal trait) is comparable to the cost of dependency management — the lock-in is low, which lowers risk but also lowers the justification to depend on it. (3) Version-matrix exposure: claiming Laravel 10–12 × Livewire 3–4 × PHP 8.1+ in one package means several internal API surfaces to track; the advertised floor (PHP 8.1, Laravel 10) is past or near end-of-life, which reads as compatibility breadth rather than a maintenance recommendation.
Key questions (resolve before adoption — these are behavior questions, not feature questions):
validateLivewire() throw ValidationException on failure (matching Livewire's $this->validate()) or return falsy? Component code written against the wrong assumption will silently persist bad data.notifyAuthorizationUsing fires, does execution abort? If the callback only notifies, an authorize() === false could still be followed by a $team->update() — the highest-severity ambiguity in the README.TemporaryUploadedFile instances handled against image, mimes, dimensions, and max: rules, and against Livewire 4 if its upload class changed?$requiredParameters validated at class-definition or invocation time, and what happens with scoped bindings, custom route keys, or parameter-name overrides?Stack fit. Recommended target: Laravel 10/11/12 monolith, Livewire 3 (mature) with Livewire 4 pending verification, PHP 8.2+. Best entry points are domains with a genuinely shared form — profile settings, team/workspace editing, resource creation wizards — where an HTTP endpoint and a Livewire form edit the same model. Skip for read-only domains and for anything where the HTTP path is a webhook/integration endpoint with no matching UI.
Migration path. Do not mass-convert. Convert per domain, and place a seam between your code and the package:
App\Support\Concerns\UsesCombinedValidation) that delegates to CombinedFormRequest::validateLivewire(). Every component calls the trait, never the vendor static directly.$requiredParameters must mirror route segment names verbatim; each Livewire component exposes a single validationParameters(): array method so the shape passed to validateLivewire() lives in one place; persistence always reads the returned $validated array, never component properties (because prepareForValidation() mutations do not write back to the component).Compatibility. Validate with composer why-not against your actual Laravel/Livewire/PHP combination before committing. Run the full existing suite plus at least one browser-level test per converted domain. Because the trait seam exists, a broken release can be absorbed by swapping the trait's internals to a vendored copy without touching call sites. Treat the package's version constraint as a lockfile-pinned dependency with a scheduled review, not a floating ^ you forget about.
Sequencing.
Maintenance. Assume you own this dependency. Apache-2.0 is commercially clean (permissive, includes a patent grant); keep attribution if you redistribute. The presence of README, CHANGELOG, and tagged releases is a positive hygiene signal, but with zero dependents there is no community pressure to fix bugs you surface. Budget a small recurring cost: watch releases, re-run the matrix on each Laravel/Livewire minor bump, and keep the trait seam healthy enough that replacement is a half-day job.
Support. No commercial support path; issue-tracker responsiveness is unproven — test it with one substantive question before committing. Internal support is a documentation problem: parameter() and validateLivewire() are new concepts the team must learn, and the developer-facing exceptions (e.g., "Missing required parameters for …") need a documented remedy. The notifyAuthorizationUsing hook is the only user-facing seam, so instrument it once, centrally, in AppServiceProvider.
Scaling. Runtime cost is negligible — validation delegation, one object per call. The scaling risks are state-related, not throughput-related: static configuration must be set only in AppServiceProvider::boot() and never mutated per-request, otherwise Octane workers will leak flags across requests and parallel test suites will fail nondeterministically. Provide a reset helper or a @beforeEach reset if the package exposes one; if it does not, that is a testability tax you are accepting. Multi-tenant setups are fine because parameters are injected explicitly, but confirm authorize() always evaluates against the tenant resolved for the current Livewire interaction.
Failure modes (ranked by severity):
validateLivewire() continues, a failed gate check could still be followed by a write. Mitigation: verify semantics; if ambiguous, add an explicit abort_if/guard in the component after the call.InvalidArgumentException → 500. Mitigation: per-request test asserting parameter names match route definitions; catch at the call site and map to a generic error with alerting.prepareForValidation() mutations are invisible to the component. Normalized values (slugs, lowercased emails) never update Livewire properties, so a failed save re-renders stale inputs. Mitigation: enforce "persist from $validated, never from properties."assertHasErrors('firstName')-style test on day one.Ramp-up. Low for a Laravel-fluent engineer: roughly one to two days to internalize the parameter contract, the return-value semantics, and the "persist from $validated" rule. Add about half a day of TPM/lead time to establish governance — version pinning policy, fork-readiness checkpoint, conventions doc, and the ownership name for the trait seam. Time-to-first-value is one sprint for the pilot domain; org-wide benefit only materializes if the convention is enforced mechanically rather than by review discipline.
How can I help you explore Laravel packages today?