Blog Detail

31

Jan
 Pass Arguments to Laravel Middleware in a More PHP'ish Way cover image

arrow_back Pass Arguments to Laravel Middleware in a More PHP'ish Way

Tim Macdonald introduced a trait for Laravel middleware that allows you to pass arguments in a more PHP’ish way, including as a key => value pair for named parameters, and as a list for variadic parameters. Improves static analysis/IDE support, allows you to specify arguments by referencing the parameter name, enables skipping optional parameters (which fall back to their default value), and adds some validation so you don’t forget any required parameters by accident.

Installation

You can install this package through composer by running this command.

$ composer require timacdonald/has-parameters

Basic usage

To get started with an example, I’m going to use a stripped-back version of Laravel’s ThrottleRequests. First up, add the HasParameters trait to your middleware.

<?php

class ThrottleRequests
{
    use HasParameters;

    public function handle($request, Closure $next, $maxAttempts = 60, $decayMinutes = 1, $prefix = '')
    {
        //
    }
}

You can now pass arguments to this middleware using the static with() method, using the parameter name as the key.

<?php

Route::stuff()
    ->middleware([
        ThrottleRequests::with([
            'maxAttempts' => 120,
        ]),
    ]);

You’ll notice at first this is a little more verbose, but I think you’ll enjoy the complete feature set after reading these docs and taking it for a spin.

Middleware::with()

The static with() method allows you to easily see which values represent what when declaring your middleware, instead of just declaring a comma separate list of values. The order of the keys does not matter. The trait will pair up the keys to the parameter names in the handle() method.

<?php

// before...
Route::stuff()
    ->middleware([
        'throttle:10,1' // what does 10 or 1 stand for here?
    ]);

// after...
Route::stuff()
    ->middleware([
        ThrottleRequests::with([
            'decayMinutes' => 1,
            'maxAttempts' => 10,
        ]),
    ]);

Arrays for variadic parameters

When your middleware ends in a variadic parameter, you can pass an array of values for the variadic parameter key. Take a look at the following handle() method.

<?php

public function handle(Request $request, Closure $next, string $ability, string ...$models)

Here is how we can pass a list of values to the variadic $models parameter.

<?php

Route::stuff()
    ->middleware([
        Authorize::with([
            'ability' => PostVideoPolicy::UPDATE,
            'models' => [Post::class, Video::class],
        ]),
    ]);

Parameter aliases

Some middleware will have different behavior based on the type of values passed through to a specific parameter. As an example, Laravel’s ThrottleRequests middleware allows you to pass the name of a rate limiter to the $maxAttempts parameter, instead of a numeric value, in order to utilize that named limiter on the endpoint.

<?php

// a named rate limiter...

RateLimiter::for('api', function (Request $request) {
    return Limit::perMinute(60)->by(optional($request->user())->id ?: $request->ip());
});

// using the rate limiter WITHOUT an alias...

Route::stuff()
    ->middleware([
        ThrottleRequests::with([
            'maxAttempts' => 'api',
        ]),
    ]);

In this kind of scenario, it is nice to be able to alias the $maxAttempts parameter name to something more readable.

<?php

Route::stuff()
    ->middleware([
        ThrottleRequests::with([
            'limiter' => 'api',
        ]),
    ]);

To achieve this, you can set up a parameter alias map in your middleware.

<?php

class ThrottleRequests
{
    use HasParameters;

    public function handle($request, Closure $next, $maxAttempts = 60, $decayMinutes = 1, $prefix = '')
    {
        //
    }

    protected static function parameterAliasMap(): array
    {
        return [
            'limiter' => 'maxAttempts',
            // 'alias' => 'parameter',
        ];
    }
}

Middleware::in()

The static in() method very much reflects and works the same as the existing concatenation API. It accepts a list of values, i.e. a non-associative array. You should use this method if your handle() method is a single variadic parameter, i.e. expecting a single list of values, as shown in the following middleware handle method.

<?php

public function handle(Request $request, Closure $next, string ...$states)
{
    //
}

You can pass through a list of states to the middleware like so:

<?php

Route::stuff()
    ->middleware([
        EnsurePostState::in([PostState::DRAFT, PostState::UNDER_REVIEW]),
    ]);

This package has a lot more features and validation methods with code examples, You can visit its complete documentation and source code on Github.

Published at : 31-01-2022

Author : Rizwan Aslam
AUTHOR
Rizwan Aslam

I am a highly results-driven professional with 12+ years of collective experience in the grounds of web application development especially in laravel, native android application development in java, and desktop application development in the dot net framework. Now managing a team of expert developers at Codebrisk.

Launch your project

Launch project