13

I am creating a project where i have multiple user types, eg. superadmin, admin, managers etc. Once the user is authenticated, the system checks the user type and sends him to the respective controller. The middle ware for this is working fine.

So when manager goes to http://example.com/dashboard he will see the managers dashboard while when admin goes to the same link he can see the admin dashboard.

The below route groups work fine individually but when placed together only the last one works.

/*****  Routes.php  ****/
 // SuperAdmin Routes
    Route::group(['middleware' => 'App\Http\Middleware\SuperAdminMiddleware'], function () {
        Route::get('dashboard', 'SuperAdmin\dashboard@index'); // SuperAdmin Dashboard
        Route::get('users', 'SuperAdmin\manageUsers@index'); // SuperAdmin Users
    });

 // Admin Routes
    Route::group(['middleware' => 'App\Http\Middleware\AdminMiddleware'], function () {
        Route::get('dashboard', 'Admin\dashboard@index'); // Admin Dashboard
        Route::get('users', 'Admin\manageUsers@index'); // Admin Users
    });

I know we can rename the routes like superadmin/dashboard and admin/dashboard but i was wondering if there is any other way to achieve the clean route. Does anyone know of any anywork arounds ?

BTW i am using LARAVEL 5.1

Any help is appreciated :)

Omer Farooq
  • 3,754
  • 6
  • 31
  • 60

2 Answers2

8

You can do this with a Before Middleware that overrides the route action's namespace, uses and controller attributes:

use Closure;
use Illuminate\Http\Request;
use Illuminate\Contracts\Container\Container;
use App\Http\Middleware\AdminMiddleware;
use App\Http\Middleware\SuperAdminMiddleware;

class AdminRoutingMiddleware
{
    /**
     * @var Container
     */
    private $container;

    public function __construct(Container $container)
    {
        $this->container = $container;
    }

    private static $ROLES = [
        'admin' => [
            'namespace' => 'Admin',
            'middleware' => AdminMiddleware::class,
        ],
        'super' => [
            'namespace' => 'SuperAdmin',
            'middleware' => SuperAdminMiddleware::class,
        ]
    ];

    public function handle(Request $request, Closure $next)
    {
        $action = $request->route()->getAction();
        $role = static::$ROLES[$request->user()->role];

        $namespace = $action['namespace'] . '\\' . $role['namespace'];

        $action['uses'] = str_replace($action['namespace'], $namespace, $action['uses']);
        $action['controller'] = str_replace($action['namespace'], $namespace, $action['controller']);
        $action['namespace'] = $namespace;

        $request->route()->setAction($action);

        return $this->container->make($role['middleware'])->handle($request, $next);
    }
}

This way you have to register each route only once without the final namespace prefix:

Route::group(['middleware' => 'App\Http\Middleware\AdminRoutingMiddleware'], function () {
    Route::get('dashboard', 'dashboard@index');
    Route::get('users', 'manageUsers@index');
});

The middleware will convert 'dashboard@index' to 'Admin\dashboard@index' or 'SuperAdmin\dashboard@index' depending on current user's role attribute as well as apply the role specific middleware.

nCrazed
  • 1,025
  • 6
  • 20
3

The best solution I can think is to create one controller that manages all the pages for the users.

example in routes.php file:

Route::get('dashboard', 'PagesController@dashboard');
Route::get('users', 'PagesController@manageUsers');

your PagesController.php file:

protected $user;

public function __construct()
{
    $this->user = Auth::user();
}

public function dashboard(){
    //you have to define 'isSuperAdmin' and 'isAdmin' functions inside your user model or somewhere else
    if($this->user->isSuperAdmin()){
        $controller = app()->make('SuperAdminController');
        return $controller->callAction('dashboard');    
    }
    if($this->user->isAdmin()){
        $controller = app()->make('AdminController');
        return $controller->callAction('dashboard');    
    }
}
public function manageUsers(){
    if($this->user->isSuperAdmin()){
        $controller = app()->make('SuperAdminController');
        return $controller->callAction('manageUsers');  
    }
    if($this->user->isAdmin()){
        $controller = app()->make('AdminController');
        return $controller->callAction('manageUsers');  
    }
}
Alex Kyriakidis
  • 2,861
  • 1
  • 19
  • 28
  • Thankyou for your reply, i tried doing that. But for some reason app()->make('SuperAdminController'); gave an error that the SuperAdminController doesn't exist. Although it did exist and i also used the command to dump-autoload. Its wierd but i think it might be because i am using the latest version and it might not understand the make command. – Omer Farooq Jul 14 '15 at 16:36
  • Try `$app = app();` then `$app->make()` – Alex Kyriakidis Jul 14 '15 at 16:45
  • Thankyou, I managed to make it work this way app()->make('App\Http\Controllers\SuperAdmin\SuperAdminController')->dashboard(); Everything is working as i wanted. I am just concerned if this is a good way to call methods from another controller? – Omer Farooq Jul 14 '15 at 19:16
  • 1
    Generally, is not a good practice to call a controller method from anything else than a HTTP request. In this case, technically controller actions still being called by the HTTP request. You may find this conversation useful: https://laracasts.com/discuss/channels/general-discussion/trigger-controllers-action – Alex Kyriakidis Jul 14 '15 at 20:43