简体   繁体   中英

laravel filter group routes with same name

I'm stuck with this annoying problem in my laravel 4 project wich has three types of users being students, teachers and moderator (I use Entrust as role management solution).

Each of them can browse the same route, but depending on the user type, another method should be called. So my route.php files was structured like this:

Route::group(array('before' => 'auth'), function(){


Route::group(array('before' => 'teacher'), function(){
        Route::get('/tasks',array('as'=>'tasks','uses'=>'TasksController@tasksAsTeacher'));
        Route::get('/task/{id}',array('as'=>'showTask','uses'=>'TasksController@showTaskAsTeacher'));



});
Route::group(array('before' => 'moderator'), function(){
        Route::get('/tasks',array('as'=>'tasks','uses'=>'TasksController@tasksAsModerator'));
        Route::get('/task/{id}',array('as'=>'showTask','uses'=>'TasksController@showTaskAsModerator'));

});     
Route::group(array('before' => 'student'), function(){

        Route::get('/tasks',array('as'=>'tasks','uses'=>'TasksController@tasksAsStudent'));
        Route::get('/task/{id}',array('as'=>'showTask','uses'=>'TasksController@showTaskAsStudent'));




});

});

However, browsing these routes with a teacher or moderator account always returned 404 errors. I found that was because the routes were redefined in the two other filter groups.

So if I would redirect a teacher user to 'showTask', laravel would return tasks as a route for students,as that's the last time the 'showTask' route was redefined, and I would get a 404 error.

My question now was: what would be the best way to handle this error?

I hope this isn't too messy. Thanks in advance!

Taking from @Matthias S's answer, does this work? Instead of using the entrust filter, check the permissions for the route like this:

//routes.php
 if(Entrust::hasRole('teacher')) {
     Route::get('/tasks',array('as'=>'tasks','uses'=>'TasksController@tasksAsTeacher'));
     Route::get('/task/{id}',array('as'=>'showTask','uses'=>'TasksController@showTaskAsTeacher'));
 }

Repeat for different roles

EDIT: Also if you had the role of the user stored in a session, you could use a sort of automatic route like this:

//routes.php
 if(Entrust::hasRole(Session::get('role'))) {
     Route::get('/tasks',array('as'=>'tasks','uses'=>'TasksController@tasksAs'.Session::get('role')));
     Route::get('/task/{id}',array('as'=>'showTask','uses'=>'TasksController@showTaskAs'.Session::get('role')));
 }

This way you can add as many roles as you want once you add the correct controller function for the role.

EDIT #2:

Or I guess even better

//routes.php - UPDATED, verify role inside controller instead of defining routes based on role
     Route::get('/tasks',array('as'=>'tasks','uses'=>'TasksController@tasks'));
     Route::get('/task/{id}',array('as'=>'showTask','uses'=>'TasksController@showTask'));


//TasksController.php
public function __construct(){
    if(!Session::get('role')){ //Make sure the user has a role assigned
        return Redirect::to('login'); // Redirect to login or permission screen if not
    }
}

public function tasks(){
    if(Entrust::hasRole(Session::get('role')){
        $tasks = Tasks::where('role_id', '=', $role->id); // Get tasks based on role
        View::make('tasks.index')->with('tasks', $tasks);
    } else{
        // Show permissions error for user
    }
}

public function showTask($task_id){
    if(Entrust::hasRole(Session::get('role')){
        $task = Tasks::where('role_id', '=', $role->id)->where('id', '=', $task_id)->first();
        View::make('tasks.view')->with('task', $task);
    }
}

Move the secondary routes group out of the main auth group, then use the pipe command to run auth before for each group eg

Route::group(array('before' => 'auth|teacher'), function(){
Route::group(array('before' => 'auth|moderator'), function(){

I am not sure if your approach is a good way to get this done. I would think that defining the same routes twice is not good practice, but I have no idea if that is true.

One way to work around this could be that you define only two routes and let the controller decide which action to perform based on the role of the user. This is not a direct solution to your problem but another way of handling the issue of having different roles performing different controller actions.

Route::group(array('before' => 'auth'), function(){

     Route::get('/tasks',array('as'=>'tasks','uses'=>'TasksController@tasks'));
     Route::get('/task/{id}',array('as'=>'showTask','uses'=>'TasksController@showTask'));

});

Then in your TasksController, you make the methods tasks and showTask something like this

class TasksController extends BaseController {
  public function tasks() {
    if(Entrust::hasRole('teacher')) {
      return $this->tasksAsTeacher();
    } else if(Entrust::hasRole('moderator')) {
      return $this->tasksAsModerator();
    } else if(Entrust::hasRole('student')) {
      return $this->tasksAsStudent();
    }
  }

  public function showTask($id) {
    if(Entrust::hasRole('teacher')) {
      return $this->showTaskAsTeacher($id);
    } else if(Entrust::hasRole('moderator')) {
      return $this->showTaskAsModerator($id);
    } else if(Entrust::hasRole('student')) {
      return $this->showTaskAsStudent($id);
    }
  }
}

Just another way to do this, makes your routes cleaner and puts the logic into the controller.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM