0

I have a route like this:

Route::get('users/{type}', ['as'=>'users.index', 'uses'=>'UserController@index', 'middleware' => ['can:user-index']])->where('type', '(members|enquiries)');

Can I use dynamic middleware here based on route parameter type.

Like If type is enquiries then middleware should be 'can:enquiries-index', similarly for members 'can:members-index'.

I know this can be done in controller function with authorize method, but I am using all authorizations in route file only. SO wanted to keep this here only.

I am using Laravel Gates definition for authorizing routes:

In AuthServiceProvider@boot

    Gate::before(function ($user, $ability) {
        $permission = Permission::where('slug', $ability)->first();
        return $user->hasPermissionTo($permission);
    });

Laravel Version: 7.9.2

PHP Version: 7.2

2 Answers 2

1

No you can't do dynamic middleware but you don't have to do it in controller too. You may do something like that; You bind two middleware to that route.

Route::get('users/{type}', ['as'=>'users.index', 'uses'=>'UserController@index', 'middleware' => ['can:members-index', 'can:enquiries-index']])->where('type', '(members|enquiries)');

Just check type is as expected in that middleware, such as;

// can:enquiries-index middleware class
public function handle($request, Closure $next)
{
    if ($request->route()->parameter('type') === 'enquiries') {
        // enquiries related code blocks
    }
}

// can:members-index middleware class
public function handle($request, Closure $next)
{
    if ($request->route()->parameter('type') === 'members') {
        // members related code blocks
    }
}

Edit:

While using policies, it is possible to use same check block inside the service provider such request()->route()->parameter('type').

Sign up to request clarification or add additional context in comments.

7 Comments

Why not make a single one and check inside it?
separation of concerns @vivek_23
@vivek_23 but when you wrote i noticed a mistake - this one is easily expendable without modifying none of the classes.
@Ersoy Can I have access to route parameters in Providers. Because I'm using Gate definition for authorizing the routes. Check the updated question.
@SunnyKumar you may try to access via using request()->route()->parameter('type') inside your ServiceProvider - request could be resolved.
|
0

It’s unfortunate that Laravel doesn’t provide conditional middleware out of the box. While there are workarounds—such as writing conditions directly in middleware or splitting route definitions—these approaches may not be ideal for every project.

To address this, I created a generic middleware proxy that allows you to apply another middleware conditionally based on route parameters:

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Symfony\Component\HttpFoundation\Response;

class ConditionalParameterMiddleware
{
    /**
     * Handle an incoming request and conditionally apply a middleware.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @param  string  $condition  Format: param=value
     * @param  string  $middlewareAliasID  Alias defined in Kernel
     * @param  mixed  ...$middlewareArgs  Additional arguments for the target middleware
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function handle(Request $request, Closure $next, string $condition, string $middlewareAliasID, ...$middlewareArgs): Response
    {
        // Split condition string into parameter name and expected value
        $separated = explode('=', $condition, 2);

        if (count($separated) !== 2) {
            Log::warning("Invalid condition format '{$condition}' in ConditionalParameterMiddleware.");
            return $next($request);
        }

        [$paramName, $expectedValue] = $separated;

        // Check if route parameter matches the expected value
        if ($request->route($paramName) == $expectedValue) {
            // Retrieve actual middleware class from Kernel aliases
            $middlewareClass = app(\App\Http\Kernel::class)->getMiddlewareAliases()[$middlewareAliasID] ?? null;

            if ($middlewareClass) {
                $middlewareInstance = app($middlewareClass);
                return $middlewareInstance->handle($request, $next, ...$middlewareArgs);
            }

            Log::warning("Middleware alias ID '{$middlewareAliasID}' not found in Kernel middleware aliases.");
        }

        return $next($request);
    }
}

Example Usage

Assuming you have registered the conditional middleware alias in your `Kernel.php`:

protected $middlewareAliases = [
    'conditional' => \App\Http\Middleware\ConditionalParameterMiddleware::class,
    'verified' => \App\Http\Middleware\EnsureEmailIsVerified::class,
];

You can then use it in a route like this:

Route::match(['get', 'post'], 'self/{section?}', [MyController::class, 'form'])
     ->middleware('conditional:section=mysection,verified')
     ->name('my.route');

In this example, the verified middleware will only be applied if the route parameter section equals mysection.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.