Framework: Artisan generated resource controller vars don't match resource route params when model has multiple words.

Created on 1 Mar 2017  路  15Comments  路  Source: laravel/framework

  • Laravel Version: 5.4.13

Description:

When using Artisan to generate a model (and resource controller) with multiple words, the route param doesn't match the var names used in the controller.

The route param ends up snake case, while the var names are camel case.

Steps To Reproduce:

artisan make:model -mcr ProductionOrder
// routes/web.php
Route::resource('production-orders', 'ProductionOrderController');

// app/ProductionOrder.php (generated by Artisan)
public function show(ProductionOrder $productionOrder) {};

// wherever.php
dd(Route::getRoutes());
// #allRoutes: array:8 [
//   "HEADapi/user" => Illuminate\Routing\Route {#250}
//   "HEADproduction-orders" => Illuminate\Routing\Route {#240}
//   "HEADproduction-orders/create" => Illuminate\Routing\Route {#239}
//   "POSTproduction-orders" => Illuminate\Routing\Route {#238}
//   "HEADproduction-orders/{production_order}" => Illuminate\Routing\Route {#237}
//   "HEADproduction-orders/{production_order}/edit" => Illuminate\Routing\Route {#236}
//   "PATCHproduction-orders/{production_order}" => Illuminate\Routing\Route {#235}
//   "DELETEproduction-orders/{production_order}" => Illuminate\Routing\Route {#234}
// ]

Most helpful comment

In addition to snapey's answer, you can also use dashes in the resource method and it'll work just as usual.

Route::resource('my-route'), 'RouteController');

Route will expect {my_route} and controller will expect (MyRoute $myRoute) but it'll work as usual. Seems like this is a new fix, since it didnt use to work.

All 15 comments

Yes i have this problem too, this issue is valid.

Is there a problem with it not working or is it just the url formatting thats not fitting you? :)

URL formatting has nothing to do with it. It's the param being passed as {production_order} while the controller expects productionController.

I did learn a workaround:

Route::resource('production-orders', 'ProductionOrderController', [
     'parameters' => ['production-orders' => 'productionOrder']
]);

However, this is still a :bug:.

Why not

Route::resource('productionOrders', 'ProductionOrderController');

and everything just works as it should

if i remember correctly you should be able to name the variable anything you want you dont have to keep the snakeCase version, you should be able to name it foo and still have the same value

@stefanoruth I think the same, but it's failing when you 'bind' it to the model.
just try it,

php artisan make:model ProductOrder -m -c -r

boom, it generate method like

public function show(ProductOrder $productOrder)

there where it goes failing the argument is just null value.
but if I change it to

publiic function show(ProductOrder $product_order)

It works. of course if I change it without bind it like

public function show($a)

, it also works, but $a is string not a model.

I think the problem is in artisan generation. (not only show method).
And this problem only if you generate model with -m -c -r flag. If you do it separately it works fine.

@curtisblackwell Btw, i prefer underscore instead of dash. Seems like underscore is Laravel default. :smile_cat:

@devcircus 鈥ecause it doesn't work as it should. See the first post.

artisan_generated_resource_controller_vars_don_t_match_resource_route_params_when_model_has_multiple_words__ _issue__18167_ _laravel_framework

@stefanoruth Yes, you can rename it, but the point of Artisan is to make things more convenient. It doesn't just work when model names are multi-word in camel case.

As someone new to building Laravel apps, this is pretty confusing. It took me a long time to track down the problem, and even asking a more experienced Laravel dev was no help. Should be an easily-prevented problem. It's obviously a simple mistake made when writing the code. No way whomever wrote it intentionally set something to send snake case but receive camel case.

I understand the issue, I guess I've just never thought of snake casing my resource routes. So for me, it's always worked perfectly, as I use:

Route::resource('productionOrders', 'ProductionOrderController');

Maybe dig into the source and submit a PR to make it work the way you use it.

The first argument is used for the slug, though. Odd to use camel case there.

I do plan to submit a PR at some point, but I don't have the time to figure everything out now. Given I'll likely encounter this on every app, I'm sure I won't forget.

Laravel magically will inject a initiated ProductOrder model with the id given in the url at the placeholder:
{production_order} .

https://laravel.com/docs/5.4/controllers#resource-controllers

Naming Resource Route Parameters
By default, Route::resource will create the route parameters for your resource routes based on the "singularized" version of the resource name. You can easily override this on a per resource basis by passing parameters in the options array. The parameters array should be an associative array of resource names and parameter names:

Route::resource('user', 'AdminUserController', ['parameters' => [
    'user' => 'admin_user'
]]);
The example above generates the following URIs for the resource's show route:

/user/{admin_user}

Has this been fixed? I was just looking at some loosely related bugs and tried to reproduce this but (with Laravel 5.5.2) it seems to work as expected. Can anyone else confirm?

I'm seeing no change. Resource route still passes snake-cased variable name, and Artisan-generated controller still expects camelcase.

Just tried this in response to a Laracasts thread.

Making model and controller as php artisan make:model -mcr WorkRequest creates controller methods expecting to be passed $workRequest

The fix appears to be to specify the route with snake case

Route::resource('work_requests', 'WorkRequestController');

This causes the route to expect {work_request} which gets passed to the controller as $workRequest and matches the variables in the artisan generated resource controller

In addition to snapey's answer, you can also use dashes in the resource method and it'll work just as usual.

Route::resource('my-route'), 'RouteController');

Route will expect {my_route} and controller will expect (MyRoute $myRoute) but it'll work as usual. Seems like this is a new fix, since it didnt use to work.

Was this page helpful?
0 / 5 - 0 ratings