Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Single Laravel Route for multiple controllers

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 :)

like image 435
Omer Farooq Avatar asked Jul 12 '15 13:07

Omer Farooq


People also ask

What is route controller in Laravel?

These controllers let you create your controller classes using methods that are used for handling various requests. It would be a lot easier if we understand the concept of laravel route controller with the help of an example.

What is resource routing in Laravel?

It is likely that users can create, read, update, or delete these resources. Because of this common use case, Laravel resource routing assigns the typical create, read, update, and delete ("CRUD") routes to a controller with a single line of code.

How do I resolve multiple controllers in Laravel?

Remember to keep your controllers focused. If you find yourself routinely needing methods outside of the typical set of resource actions, consider splitting your controller into two, smaller controllers. The Laravel service container is used to resolve all Laravel controllers.

What happens if you don’t specify any action in Laravel route?

Note: In case you don’t specify any action, i.e., you don’t write the method __invoke (), It will throw an Invalid Route Action error, i.e., UnexpectedValueExpression. Every route in Laravel is defined in route files. These route files can be found in the sub-directory of routes.


1 Answers

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.

like image 179
nCrazed Avatar answered Sep 28 '22 17:09

nCrazed