Implicit binding resolution isn't working the same way in 2 almost identical scenarios (see the steps to reproduce).
I understand that the resolution shouldn't consider the URL itself but only the type-hinted method parameter.
First, create a new Laravel app and 2 very similar tables:
laravel new app
php artisan make:migration create_grupocategoria_table --create=grupocategorias
php artisan make:migration create_funcionario_table --create=funcionarios
php artisan migrate
Then, insert 1 row in each table manually. And yes, to be simple, the tables have only id, created_at and updated_at columns.
Now, create 2 controllers and say 'yes' to create the related model.
php artisan make:controller GrupocategoriaController --resource --model=Grupocategoria
php artisan make:controller FuncionarioController --resource --model=Funcionario
In GrupocategoriaController.php, add 'return $grupocategoria;' in 'show' method (line 49).
In FuncionarioController.php, add 'return $funcionario;' in 'show' method (line 49).
In web.php, add:
Route::resource('funcionarios', 'FuncionarioController');
Route::resource('funcionario', 'FuncionarioController');
Route::resource('grupocategorias', 'GrupocategoriaController');
Route::resource('grupocategoria', 'GrupocategoriaController');
Route::resource('aaaaaaaaaaa', 'FuncionarioController');
Now try to access the following URLs:
You'll notice that the last 2 URL return an empty array but all the 3 others return the right model.
Why it is doing the implicit binding or not depending on the URL?
How are you accepting the parameter in the controller?
The same way Laravel generated it....
public function show(Grupocategoria $grupocategoria)
{
return $grupocategoria;
}
I followed the steps with a brand new 5.5 install and am able to reproduce the issue.
Route::resource('funcionario', 'FuncionarioController'); and Route::resource('aaaaaaaaaaa', 'FuncionarioController'); are the only ones working as intended. The former should match (and does) because the route segment is the same as the type-hinted variable. The latter shouldn't match (and doesn't) because the route segment doesn't match.
Route::resource('funcionarios', 'FuncionarioController'); and Route::resource('grupocategorias', 'GrupocategoriaController'); shouldn't work (but they do) because the route segment is plural but the type-hinted variable is singular.
Route::resource('grupocategoria', 'GrupocategoriaController'); should be working (but isn't).
Good! Thanks for your reply!
Why it does need to match the route segment? Shouldn't it be more flexible if it needs to match only the type-hinted variable?
I'm guessing that the order route segments does not have to match the order of the action parameters, and they are instead matched by name. It makes sense that I could move things around in my routes without having to rewrite controller code. Or I could be guessing wrong.
@rodrigopedra It needs to match the variable name because the controllers have automatic resolution. which means laravel needs to know which model to bind. :)
The need to match the variable name is ok, it makes all the sense. What I couldn't understand is why it also needs to match the route segment.
Because it doesn't have to match the Type hint
for instance:
public function show(NewsArticle $article) {
The only thing that matters is that it matches the route segment.
Please tag the correct rodrigo when answering to this thread. The opener was @rodrigoroma not me.
I just ran into I think the same issue, I have a controller route that has a three different routes
Route::get('admin/event_type/{event_type}/event/{event}', 'EventController@show')->name('show_event_from_event_type');
Route::get('admin/event/{event}', 'EventController@show')->name('show_event');
Route::get('admin/event_template/{event_template}/event/{event}', 'EventController@show')->name('show_event_from_event_template');
The controller's signature is
public function show(Event $event, EventType $event_type = NULL, EventTemplate $event_template = NULL)
The project was Laravel 5.4.28, and when trying to upgrade to 5.5 I am getting parameters passed in the wrong order. I code-dived and found the behavior was changed in this commit: https://github.com/laravel/framework/commit/6553e3371d228da5c6f1c0422327ffd19ffa183b
Not sure the best way to work around it other than to build new controller methods with the three different signatures.
My bad, that was not the commit that broke this, and I am not having this issue in 5.4.35 as the OP describes, so my issue is different.
Found my issue, at least, it was because I had a default value in my controller signature.
This is because of the way the ResourceRegistrar will singularize the parameter names: https://github.com/laravel/framework/blob/e294f05894610d5c5451db56aff37dfa371789bd/src/Illuminate/Routing/ResourceRegistrar.php#L345
You can disable this by setting the $singularParameters static parameter but it's undocumented I believe.
If you btw do a php artisan route:list you can see all the routes and their parameter names.