6

When you define a resource with Route::resource('recipe', 'RecipeController');, among others, the following route is defined: /photo/{photo}/edit, and once you define all your resources you have something like this:

  • /recipes/{recipes}/edit
  • /allergens/{allergens}/edit
  • /ingredients/{ingredients}/edit

Because all my records use id as primary key (MongoDB), I'd like to have {id} instead, like so:

  • /recipes/{id}/edit
  • /allergens/{id}/edit
  • /ingredients/{id}/edit

I dug in the Router class but I don't see how to specify this.

More over when I create a form with Form::model($record) I get actions like /recipes/{recipes} because recipes is a property of $record.

How can I define the name of the key parameter to id instead of recipes, allergens, ingredients?

olvlvl
  • 2,396
  • 1
  • 22
  • 22

3 Answers3

6

I know this is 4 year old question but for anyone who is googling; you can pass a third argument to override key naming:

Route::resource('ingredients', 'IngredientController', ['parameters' => ['ingredients' => 'id']]);

Or

Route::resource('ingredients', 'IngredientController')->parameters(['ingredients' => 'id']);

See Documentation

Yevgeniy Afanasyev
  • 37,872
  • 26
  • 173
  • 191
AmirRezaM75
  • 1,030
  • 14
  • 17
4

In order to change the param name for Route::resource, you need custom ResourceRegistrar implementation.

Here's how you can achieve that in a shortest possible way:

// AppServiceProvider (or anywhere you like)
public function register()
{
  $this->app->bind('Illuminate\Routing\ResourceRegistrar', function ($app) {

    // *php7* anonymous class for brevity,
    // feel free to create ordinary `ResourceRegistrar` class instead
    return new class($app['router']) extends \Illuminate\Routing\ResourceRegistrar 
    {

      public function register($name, $controller, array $options = [])
      {
        if (str_contains($name, '/')) {
          return parent::register($name, $controller, $options);
        }

        // ---------------------------------
        // this is the part that we override
        $base = array_get($options, 'param', $this->getResourceWildcard(last(explode('.', $name))));
        // ---------------------------------

        $defaults = $this->resourceDefaults;

        foreach ($this->getResourceMethods($defaults, $options) as $m) {
          $this->{'addResource'.ucfirst($m)}($name, $base, $controller, $options);
        }
      }
    };
  });
}

Now your routes will look like:

Route::resource('users', 'UsersController', ['param' => 'some_param'])
/users/{some_param}

// default as fallback
Route::resource('users', 'UsersController')
/users/{users}

Mind that this way can't work for nested resources and thus they will be a mix of default and custom behaviour, like this:

Route::resource('users.posts', 'SomeController', ['param' => 'id'])
/users/{users}/posts/{id}
Jarek Tkaczyk
  • 78,987
  • 25
  • 159
  • 157
  • I was hoping for something easier like this: https://github.com/ICanBoogie/Routing#defining-resource-routes-using-routemaker with `OPTION_ID_NAME`, but your code will do just fine. Thanks a lot Jared! – olvlvl Mar 15 '16 at 22:12
0

You can pass your ids to the routes you don't necessary need to change the parameters {recipes} to {id} since the parameters are just a placeholder.

So

 public function edit($recipes){
    // code goes hr
 }

is the same as this

 public function edit($id){
    // code goes hr
 }

for this route /recipes/{recipes}/edit

oseintow
  • 7,221
  • 3
  • 26
  • 31
  • Thanks for your answer, the issue is also with `Form::model`, because the `recipes` property is not available in the record, I end up with `/recipes/{recipes}` routes. I updated my original post. – olvlvl Mar 14 '16 at 14:34
  • Oh ok you are using route model binding i guess. – oseintow Mar 14 '16 at 14:35
  • @olvlvl It doesn't matter what is in route as oseinow says it's just a placeholder. I think the problem is somewhere else. Anyway, what is the error you are having after submitting the form? – smartrahat Mar 14 '16 at 15:56