{"id":15472655,"url":"https://github.com/timacdonald/has-parameters","last_synced_at":"2026-04-13T03:23:13.199Z","repository":{"id":43893031,"uuid":"254801867","full_name":"timacdonald/has-parameters","owner":"timacdonald","description":"A trait that allows you to pass arguments to Laravel middleware in a more PHP'ish way.","archived":false,"fork":false,"pushed_at":"2025-05-26T23:55:44.000Z","size":1257,"stargazers_count":229,"open_issues_count":0,"forks_count":12,"subscribers_count":4,"default_branch":"master","last_synced_at":"2026-02-10T07:40:10.370Z","etag":null,"topics":["hacktoberfest","helper","laravel","middleware","php","trait"],"latest_commit_sha":null,"homepage":"https://timacdonald.me/rethinking-laravels-middleware-argument-api/","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/timacdonald.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"license.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2020-04-11T05:46:48.000Z","updated_at":"2025-10-14T01:14:53.000Z","dependencies_parsed_at":"2024-05-18T06:22:38.827Z","dependency_job_id":"f8d189ee-089d-41f5-94b0-5114c72480a8","html_url":"https://github.com/timacdonald/has-parameters","commit_stats":{"total_commits":111,"total_committers":9,"mean_commits":"12.333333333333334","dds":0.3873873873873874,"last_synced_commit":"ee09e2bc3d214b4bed1a1b457cc823f294410be0"},"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/timacdonald/has-parameters","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timacdonald%2Fhas-parameters","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timacdonald%2Fhas-parameters/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timacdonald%2Fhas-parameters/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timacdonald%2Fhas-parameters/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/timacdonald","download_url":"https://codeload.github.com/timacdonald/has-parameters/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timacdonald%2Fhas-parameters/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31738337,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-12T22:19:12.206Z","status":"online","status_checked_at":"2026-04-13T02:00:06.623Z","response_time":93,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["hacktoberfest","helper","laravel","middleware","php","trait"],"created_at":"2024-10-02T02:40:30.509Z","updated_at":"2026-04-13T03:23:13.181Z","avatar_url":"https://github.com/timacdonald.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\u003cimg src=\"/art/header.png\" alt=\"Has Parameters: a Laravel package by Tim MacDonald\"\u003e\u003c/p\u003e\n\n# Has Parameters\n\nA trait for Laravel middleware that allows you to pass arguments in a more PHP'ish way, including as a key =\u003e 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 fallback to their default value), and adds some validation so you don't forget any required parameters by accident.\n\nRead more about the why in my blog post [Rethinking Laravel's middleware argument API](https://timacdonald.me/rethinking-laravels-middleware-argument-api/)\n\n## Installation\n\nYou can install using [composer](https://getcomposer.org/):\n\n```\ncomposer require timacdonald/has-parameters\n```\n\n## Basic usage\n\nTo 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.\n\n```php\nclass ThrottleRequests\n{\n    use HasParameters;\n\n    public function handle($request, Closure $next, $maxAttempts = 60, $decayMinutes = 1, $prefix = '')\n    {\n        //\n    }\n}\n```\n\nYou can now pass arguments to this middleware using the static `with()` method, using the parameter name as the key.\n\n```php\nRoute::stuff()\n    -\u003emiddleware([\n        ThrottleRequests::with([\n            'maxAttempts' =\u003e 120,\n        ]),\n    ]);\n```\n\nYou'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.\n\n## Middleware::with()\n\nThe static `with()` method allows you to easily see which values represent what when declaring your middleware, instead of just declaring a comma seperate list of values.\nThe order of the keys does not matter. The trait will pair up the keys to the parameter names in the `handle()` method.\n\n```php\n// before...\nRoute::stuff()\n    -\u003emiddleware([\n        'throttle:10,1' // what does 10 or 1 stand for here?\n    ]);\n\n// after...\nRoute::stuff()\n    -\u003emiddleware([\n        ThrottleRequests::with([\n            'decayMinutes' =\u003e 1,\n            'maxAttempts' =\u003e 10,\n        ]),\n    ]);\n```\n\n### Skipping parameters\n\nIf any parameters in the `handle` method have a default value, you do not need to pass them through - unless you are changing their value. As an example, if you'd like to only specify a prefix for the `ThrottleRequests` middleware, but keep the `$decayMinutes` and `$maxAttempts` as their default values, you can do the following...\n\n```php\nRoute::stuff()\n    -\u003emiddleware([\n        ThrottleRequests::with([\n            'prefix' =\u003e 'admins',\n        ]),\n    ]);\n```\n\nAs we saw previously in the handle method, the default values of `$decayMinutes` is `1` and `$maxAttempts` is `60`. The middleware will receive those values for those parameters, but will now receive `\"admins\"` for the `$prefix`.\n\n### Arrays for variadic parameters\n\nWhen your middleware ends in a variadic paramater, you can pass an array of values for the variadic parameter key. Take a look at the following `handle()` method.\n\n```php\npublic function handle(Request $request, Closure $next, string $ability, string ...$models)\n```\n\nHere is how we can pass a list of values to the variadic `$models` parameter...\n\n```php\nRoute::stuff()\n    -\u003emiddleware([\n        Authorize::with([\n            'ability' =\u003e PostVideoPolicy::UPDATE,\n            'models' =\u003e [Post::class, Video::class],\n        ]),\n    ]);\n```\n\n### Parameter aliases\n\nSome middleware will have different behaviour 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 utilise that named limiter on the endpoint.\n\n```php\n// a named rate limiter...\n\nRateLimiter::for('api', function (Request $request) {\n    return Limit::perMinute(60)-\u003eby(optional($request-\u003euser())-\u003eid ?: $request-\u003eip());\n});\n\n// using the rate limiter WITHOUT an alias...\n\nRoute::stuff()\n    -\u003emiddleware([\n        ThrottleRequests::with([\n            'maxAttempts' =\u003e 'api',\n        ]),\n    ]);\n```\n\nIn this kind of scenario, it is nice to be able to alias the `$maxAttempts` parameter name to something more readable.\n\n```php\nRoute::stuff()\n    -\u003emiddleware([\n        ThrottleRequests::with([\n            'limiter' =\u003e 'api',\n        ]),\n    ]);\n```\n\nTo achieve this, you can setup a parameter alias map in your middleware...\n\n```php\nclass ThrottleRequests\n{\n    use HasParameters;\n\n    public function handle($request, Closure $next, $maxAttempts = 60, $decayMinutes = 1, $prefix = '')\n    {\n        //\n    }\n\n    protected static function parameterAliasMap(): array\n    {\n        return [\n            'limiter' =\u003e 'maxAttempts',\n            // 'alias' =\u003e 'parameter',\n        ];\n    }\n}\n```\n\n### Validation\n\nThese validations occur whenever the routes file is loaded or compiled, not just when you hit a route that contains the declaration.\n\n#### Unexpected parameter\n\nEnsures that you do not declare any keys that do not exist as parameter variables in the `handle()` method. This helps make sure you don't mis-type a parameter name.\n\n#### Required parameters\n\nEnsures all required parameters (those without default values) have been provided.\n\n#### Aliases\n\n- Ensures all aliases specified reference an existing parameter.\n- Provided aliases don't reference the same parameter.\n- An original parameter key and an alias have not both been provided.\n\n## Middleware::in()\n\nThe static `in()` method very much reflects and works the same as the existing concatination 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...\n.\n```php\npublic function handle(Request $request, Closure $next, string ...$states)\n{\n    //\n}\n```\n\nYou can pass through a list of \"states\" to the middleware like so...\n\n```php\nRoute::stuff()\n    -\u003emiddleware([\n        EnsurePostState::in([PostState::DRAFT, PostState::UNDER_REVIEW]),\n    ]);\n```\n\n### Validation\n\n#### Required parameters\n\nJust like the `with()` method, the `in()` method will validate that you have passed enough values through to cover all the required parameters. Because variadic parameters do not require any values to be passed through, you only really rub up against this when you should probably be using the `with()` method.\n\n## Value transformation\n\nYou should keep in mind that everything will still be cast to a string. Although you are passing in, for example, integers, the middleware itself will *always* receive a string. This is how Laravel works under-the-hood to implement route caching.\n\nOne thing to note is the `false` is actually cast to the string `\"0\"` to keep some consistency with casting `true` to a string, which results in the string `\"1\"`.\n\n## Typing values\n\nIt is possible to provide stronge type information by utilising docblocks on your middleware class. Here is an example of how you could create a strongly typed middleware:\n\n```php\n/**\n * @method static string with(array{\n *     maxAttempts?: int,\n *     decayMinutes?: float|int,\n *     prefix?: string,\n * }|'admin' $arguments)\n */\nclass ThrottleMiddleware\n{\n    use HasParameters;\n\n    // ...\n}\n```\n\nYou will then receive autocomplete and diagnostics from your language server:\n\n```php\nThrottleMiddleware::with('admin');\n// ✅\n\nThrottleMiddleware::with(['decayMinutes' =\u003e 10]);\n// ✅\n\nThrottleMiddleware::with('foo');\n// ❌ fails because 'foo' is not in the allowed string values\n\nThrottleMiddleware::with(['maxAttempts' =\u003e 'ten']);\n// ❌ fails because `maxAttempts` must be an int\n```\n\nCheckout the example in the [PHPStan playground](https://phpstan.org/r/8c0ba5d8-a730-4fd9-9af8-bcec33d3b043).\n\n## Credits\n\n- [Tim MacDonald](https://github.com/timacdonald)\n- [All Contributors](../../contributors)\n\nAnd a special (vegi) thanks to [Caneco](https://twitter.com/caneco) for the logo ✨\n\n## Thanksware\n\nYou are free to use this package, but I ask that you reach out to someone (not me) who has previously, or is currently, maintaining or contributing to an open source library you are using in your project and thank them for their work. Consider your entire tech stack: packages, frameworks, languages, databases, operating systems, frontend, backend, etc.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftimacdonald%2Fhas-parameters","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftimacdonald%2Fhas-parameters","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftimacdonald%2Fhas-parameters/lists"}