Repository navigation
Replies: 1 comment 1 reply
Route::get('/{tenent}/projects/{slug}', [ProjectController::class, 'all'])->strictBinding(); |
1 reply
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Currently, route model binding resolves models using
first()after building the binding query.For example,
resolveRouteBinding()ultimately resolves the model like this:framework/src/Illuminate/Database/Eloquent/Model.php
Lines 2460 to 2463 in b623055
The same behavior exists for the other route binding methods (including soft-deletable bindings):
framework/src/Illuminate/Database/Eloquent/Model.php
Lines 2472 to 2475 in b623055
Or:
framework/src/Illuminate/Database/Eloquent/Model.php
Lines 2485 to 2488 in b623055
Using
first()means that if the route binding query unexpectedly matches multiple records, Laravel silently returns the first result. While this is the correct behavior for backward compatibility, some applications expect a stronger invariant: a route parameter should resolve to exactly one model.Motivation
Some applications rely on route model binding to uniquely identify a resource. If the underlying query becomes ambiguous because of a bug or inconsistent data, silently returning the first record can hide the problem.
Examples:
Multi-tenant applications
Imagine a model that resolves by
slugtogether with a tenant scope.The expected query is effectively:
If a bug accidentally removes or bypasses the tenant scope, the query may become:
If multiple tenants have the same slug, route model binding will silently return the first matching model.
Using
sole()would immediately detect that the binding query is no longer unique.Custom route binding queries
Applications can customize
resolveRouteBindingQuery().A mistake such as broadening the query (for example, using
LIKEor unintentionally removing constraints) may cause multiple records to match.Today, the first matching record is returned without any indication that the binding has become ambiguous.
Data inconsistencies
Even when uniqueness is expected, mistakes happen.
Examples include:
sole()would fail fast instead of silently returning an arbitrary record.Proposal
Allow models to opt into resolving route bindings using
sole()instead offirst().This would be entirely opt-in and would not change the behavior of existing applications.
Possible API
Option 1: Interface
Internally:
Option 2: Model method
Then Laravel would internally choose between
first()andsole()based on the method's return value.Personally, I think the method-based approach fits Eloquent's existing customization style a little better, but either approach would work.
Concern
One question is how
MultipleRecordsFoundExceptionshould be handled.My expectation is that it should not be converted into a 404.
A route matching multiple models indicates that the application's uniqueness assumption has been violated, which seems more like a server-side error than a missing resource.
Question
Would you consider an opt-in mechanism like this to be a good addition to Laravel?
If so, I'm happy to implement it and open a pull request. I'm also happy to follow whichever API (interface, method, or another approach) you think fits the framework best.
All reactions