laravel-5url-routingnested-resources

Laravel 5.4 route simplification


I've been trying to find some documentation on how to accomplish the following, but it seems like maybe I'm not using the correct search terms.

I would like to implement some simplified routes in Laravel 5.4 by omitting the route name from the path – for example:

  1. /{page} instead of /pages/{page}
  2. /profile instead of /users/{user}/edit
  3. /{exam}/{question} (or even /exams/{exam}/{question}) instead of /exams/{exam}/questions/{question}

Example of current routes

Route::resource('exams.questions', 'ExamQuestionController', ['only' => ['show']]);
// exams/{exam}/question/{question}

I know how to do this with route closures and one-off routes (e.g.: Route::get...) but is there a way to do this using Route::resource?

In rails the above could be accomplished with:

resources :exams, path: '', only: [:index, :show] do
  resources :question, path: '', only: [:show]
end

// /:exam_id/:id

Solution

  • While I haven't yet found a way to accomplish my test cases using strictly Route::resource, here is what I implemented to accomplish what I was trying to do:

    // For: `/{exam}/{question}`
    Route::group(['as' => 'exams.', 'prefix' => '{exam}'], function() {
      Route::get('{question}', [
        'as'      => 'question.show',
        'uses'    => 'QuestionController@show'
      ]);
    });
    
    // For: `/exams/{exam}/{question}`
    Route::group(['as' => 'exams.', 'prefix' => 'exams/{exam}'], function() {
      Route::get('{question}', [
        'as'      => 'question.show',
        'uses'    => 'QuestionController@show'
      ]);
    });
    
    // For: `/profile`
    Route::get('profile', function() {
      $controller = resolve('App\Http\Controllers\UserController');
      return $controller->callAction('edit', $user = [ Auth::user() ]);
    })->middleware('auth')->name('users.edit');
    
    // For: `/{page}`
    // -------------- 
    // Note that the above `/profile` route must come before 
    // this route if using both methods as this route
    // will capture `/profile` as a `{page}` otherwise
    Route::get('{page}', [
      'as'      => 'page.show',
      'uses'    => 'PageController@show'
    ]);