kumaravelk011/model-validation
A Laravel package for validating Eloquent models with rules defined alongside the model. Keep validation close to your data layer, reuse Laravel’s validator, and catch invalid attributes before saving or updating records.
Baseline assessment for theriddleofenigma/laravel-model-validation at v2.0.0. The package supplies a ValidatorTrait that runs model-defined validation rules (validationRules, validationMessages, validationAttributes) automatically on the Eloquent saving/creating/updating events, throwing ValidationException on failure. v2.0.0 is a modernization/breaking release, not a feature-only bump.
Architecture fit — Strong fit for apps that want validation enforced at the persistence boundary rather than (or in addition to) Form Requests. It keeps models as the source of truth for invariants, which suits domain-heavy Laravel codebases, queue workers, console commands, and seeders where no HTTP request exists. It is a thin trait with no service provider, config file, or facade to own, so architectural coupling is low and reversible.
Integration feasibility — High. Public API is unchanged for existing users: same trait, same validate(), same validateOnSaving()/validateOnCreating(), same config properties and hooks. Migration for a conforming app is a Composer bump plus a platform check (PHP ≥ 8.2, Laravel ≥ 12). The new escape hatches (skipValidation(), saveWithoutValidation(), withoutValidation()) directly resolve the long-standing pain point of bulk imports and fixtures fighting the trait.
Technical risk
validate(). It now returns the validated data array rather than a prior boolean/void shape. Any caller doing if ($model->validate()) or asserting on the result can change behavior silently, since a non-empty array is truthy and an empty one is not. This is the single highest-probability breakage and is not surfaced by any test the consuming app already has.illuminate/* dependencies instead of laravel/framework is the right call for conflict surface, but it must be validated in a real skeleton app to confirm Composer resolves cleanly against an app pinned to the full framework.updateOrCreate, upsert, relationships, saveQuietly, exception paths in withoutValidation()).Key questions
withoutValidation() hold its disabled flag in static/class-level state? If so, what is the behavior under Laravel Octane, where static state persists across requests in a worker? The try/finally restores on exception, but that does not prove request isolation.unique rules automatically scoped to ignore the current model's own key on update? This is the classic failure mode for validating traits and is not addressed in the notes.updateOrCreate, firstOrCreate, upsert, saveMany, and relationship create()/save() — validated or bypassed?Stack fit — Any Laravel 12+ app on PHP 8.2+ using Eloquent. Best value where writes happen outside HTTP controllers (jobs, imports, scheduled commands), which is exactly where Form Request validation cannot reach.
Migration path
use ValidatorTrait. This is a fast codebase grep and should be done first, because it determines blast radius.->validate( within model/domain code and classify each call site by whether it consumes the return value. This is the only breaking change with real silent-breakage potential.updateOrCreate, and a job/command that saves a model.Model::withoutValidation(fn () => ...) form over the per-instance toggle for imports and seeders, since the callback guarantees restoration and is greppable in review.Compatibility — No changes required to model configuration or hooks. validateOnUpdating() is additive and only needed if you previously validated on updating by hand. The strict-typed rewrite affects subclassing or any code that extended ModelValidator directly — check for that before upgrading.
Sequencing — Do the return-value audit and platform check first (cheap, parallel). Upgrade and validate in one low-traffic service to confirm no behavioral drift in real traffic. Then roll out per service, pinning exact minor versions in composer.json rather than using floating constraints, so a patch release from a single-maintainer project cannot land unreviewed.
Maintenance — Minimal ongoing cost: no config, no migrations, no service provider. The upgrade treadmill is tied to Laravel major releases, and the maintainer has now established a CI matrix and community health files, which are positive signals for a single-maintainer package. The counter-risk is that the maintainer's release cadence is the project's cadence — the Laravel ≤11 drop was aggressive, and the next such cutoff will recur on the same schedule.
Support — Failure surfaces are well understood by any Laravel developer: a ValidationException propagating out of a save. Support burden concentrates in one place — ensuring the exception handler maps to a 422 in API contexts and to a redirect-with-errors in web contexts, uniformly, across every service. Codify that once centrally rather than per service.
Scaling — Cost is one validator instantiation per save, which is negligible for single-record writes and worth benchmarking only for high-volume import loops that save thousands of models individually. Those loops are better served by withoutValidation() plus an explicit bulk-validate pass, which is now supported.
Failure modes — The material ones are quiet, not loud:
update(), upsert, raw DB inserts, saveQuietly()) skip validation. This is inherent to the approach, not a defect, but it must be documented in the team's conventions or it will be rediscovered in production.saveWithoutValidation/skipValidation in non-import code.withoutValidation() is implemented with class-level state — confirm before running this package under Octane.ValidationException is a non-retryable failure whose message may not reach an operator without explicit handling.Ramp-up — Low. The API is small and the concepts are standard Laravel validation semantics. A developer new to the package needs to learn three things: the config property names, the three skip mechanisms and when each is appropriate, and the event-bypass boundary. Budget roughly a half-day of onboarding per developer, plus one to three engineer-days per service for the v2.0.0 upgrade including the return-value audit and added tests.
How can I help you explore Laravel packages today?