{"id":16337501,"url":"https://github.com/mpscholten/request-parser","last_synced_at":"2025-08-11T05:16:25.283Z","repository":{"id":57020628,"uuid":"61488582","full_name":"mpscholten/request-parser","owner":"mpscholten","description":"Small PHP Library for type-safe input handling","archived":false,"fork":false,"pushed_at":"2020-06-19T14:45:04.000Z","size":720,"stargazers_count":53,"open_issues_count":10,"forks_count":3,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-08-02T23:04:31.933Z","etag":null,"topics":["input","php-library","psr","psr7-http","symfony-httpfoundation","type-safety"],"latest_commit_sha":null,"homepage":"","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/mpscholten.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-06-19T16:10:51.000Z","updated_at":"2025-04-28T09:29:44.000Z","dependencies_parsed_at":"2022-08-23T12:20:11.448Z","dependency_job_id":null,"html_url":"https://github.com/mpscholten/request-parser","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/mpscholten/request-parser","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mpscholten%2Frequest-parser","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mpscholten%2Frequest-parser/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mpscholten%2Frequest-parser/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mpscholten%2Frequest-parser/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mpscholten","download_url":"https://codeload.github.com/mpscholten/request-parser/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mpscholten%2Frequest-parser/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":269833251,"owners_count":24482413,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-11T02:00:10.019Z","response_time":75,"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":["input","php-library","psr","psr7-http","symfony-httpfoundation","type-safety"],"created_at":"2024-10-10T23:47:13.508Z","updated_at":"2025-08-11T05:16:25.220Z","avatar_url":"https://github.com/mpscholten.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# request parser\n\n[![Latest Stable Version](https://poser.pugx.org/mpscholten/request-parser/version)](https://packagist.org/packages/mpscholten/request-parser) \n[![License](https://poser.pugx.org/mpscholten/request-parser/license)](https://packagist.org/packages/mpscholten/request-parser) \n[![Circle CI](https://circleci.com/gh/mpscholten/request-parser.svg?style=shield)](https://circleci.com/gh/mpscholten/request-parser)\n[![Total Downloads](https://poser.pugx.org/mpscholten/request-parser/downloads)](https://packagist.org/packages/mpscholten/request-parser)\n\nSmall PHP Library for type-safe input handling.\n\n* [The Problem](https://github.com/mpscholten/request-parser/#the-problem)\n* [Examples](https://github.com/mpscholten/request-parser/#examples)\n* [Getting Started](https://github.com/mpscholten/request-parser/#getting-started)\n* [Integrations](https://github.com/mpscholten/request-parser/#integrations)\n * [Symfony HttpFoundation](https://github.com/mpscholten/request-parser/#symfony-httpfoundation)\n * [Psr7](https://github.com/mpscholten/request-parser/#psr7)\n* [Optional Parameters](https://github.com/mpscholten/request-parser/#additional-parameters)\n * [Integers, Enums, DateTimes and Json Payloads](https://github.com/mpscholten/request-parser/#integers-enums-datetimes-and-json-payloads)\n * [Supported Data Types](https://github.com/mpscholten/request-parser/#supported-data-types)\n* [GET Requests](https://github.com/mpscholten/request-parser/#get-requests)\n* [POST Requests](https://github.com/mpscholten/request-parser/#post-requests)\n* [Autocompletion](https://github.com/mpscholten/request-parser/#autocompletion)\n* [Static Analysis](https://github.com/mpscholten/request-parser/#static-analysis)\n* [Error Handling](https://github.com/mpscholten/request-parser/#error-handling)\n * [Using Custom Exception Classes](https://github.com/mpscholten/request-parser/#using-custom-exception-classes)\n * [Using Custom Exception Messages](https://github.com/mpscholten/request-parser/#using-custom-exception-messages)\n* [Is It Production Ready?](https://github.com/mpscholten/request-parser/#is-it-production-ready)\n* [Tests](https://github.com/mpscholten/request-parser/#tests)\n* [Contributing](https://github.com/mpscholten/request-parser/#contributing)\n\n### The Problem\n\nLet's say you have an action which lists some entities. This includes paging, ascending or descending ordering and optional filtering by the time the entity was created.\nThis action will have some kind of input parsing, which can look like this:\n\n```php\npublic function index()\n{\n    $page = $this-\u003erequest-\u003equery-\u003eget('page');\n    if ($page === null || !is_integer($page)) {\n        throw new Exception(\"Parameter page not found\");\n    }\n    \n    $order = $this-\u003erequest-\u003equery-\u003eget('order');\n    if ($order === null || !in_array($order, ['asc', 'desc'])) {\n        throw new Exception(\"Parameter order not found\");\n    }\n    \n    // Optional parameter\n    $createdAt = $this-\u003equery-\u003equery-\u003eget('createdAt');\n    if (is_string($createdAt)) {\n        $createdAt = new DateTime($createdAt);\n    } else {\n        $createdAt = null;\n    }\n}\n```\n\nObviously this code is not very nice to read because it is not very descriptive. It's also pretty verbose for what it's doing.\nAnd when you don't pay close attention you will probably miss a null check or a type check.\n\nNow compare the above code to this version:\n\n```php\npublic function index()\n{\n    $page = $this-\u003equeryParameter('page')-\u003eint()-\u003erequired();\n    $order = $this-\u003equeryParameter('order')-\u003eoneOf(['asc', 'desc'])-\u003erequired();\n    $createdAt = $this-\u003equeryParameter('createdAt')-\u003edateTime()-\u003edefaultsTo(null);\n}\n```\n\nThat's what this library offers. It allows you to express \"_this action requires a page parameter of type int_\" or \"_this action has an optional parameter createdAt of type DateTime, and will be set to a default value if absent_\".\n\n### Examples\n\nIf you'd like to go straight to the code now, you can just play around with the examples.\n\n0. `cd /tmp`\n1. `git clone git@github.com:mpscholten/request-parser.git`\n2. `cd request-parser`\n3. `composer install`\n4. `cd examples`\n5. `php -S localhost:8080`\n6. Open it: http://localhost:8080/symfony.php?action=hello\n\nThere are also several other php files inside the examples directory. To get your hands dirty, I suggest just modifying the examples a bit.\n\n### Getting Started\n\nInstall via composer\n\n```\ncomposer require mpscholten/request-parser\n```\n\n\n### Integrations\n\n - If you're using `symfony/http-foundation`, [click here](#symfony-httpfoundation).\n - If you're using a Psr7 `ServerRequestInterface` implementation, [click here](#psr7).\n - If you're using some other `Request` abstraction (or maybe just plain old `$_GET` and friends), [check out this example](https://github.com/mpscholten/request-parser/blob/master/examples/not-symfony.php).\n\n#### Symfony HttpFoundation\n\nThe following example assumes you're using the symfony `Request`:\n\n```php\nclass MyController\n{\n    use \\MPScholten\\RequestParser\\Symfony\\ControllerHelperTrait;\n    \n    public function __construct(Request $request)\n    {\n        $this-\u003einitRequestParser($request);\n    }\n}\n```\n\nThen you can use the library like this:\n```php\nclass MyController\n{\n    use \\MPScholten\\RequestParser\\Symfony\\ControllerHelperTrait;\n    \n    public function __construct(Request $request)\n    {\n        $this-\u003einitRequestParser($request);\n    }\n    \n    public function myAction()\n    {\n        $someParameter = $this-\u003equeryParameter('someParameter')-\u003estring()-\u003erequired();\n    }\n}\n```\n\nWhen doing `GET /MyController/myAction?someParameter=example`, the `$someParameter` variable will contain the string `\"example\"`.\n\nYou might wonder what happens when we leave out the `?someParameter` part, like `GET /MyController/myAction`. In this case the\n`$this-\u003equeryParameter('someParameter')-\u003estring()-\u003erequired()` will throw a `NotFoundException`. This exception can\nbe handled by your application to show an error message.\n\nTake a look at [the examples](https://github.com/mpscholten/request-parser/tree/master/examples).\n\n#### Psr7\n\nThe following example assumes you're using the Psr7 `ServerRequestInterface`:\n\n```php\nclass MyController\n{\n    use \\MPScholten\\RequestParser\\Psr7\\ControllerHelperTrait;\n    \n    public function __construct(ServerRequestInterface $request)\n    {\n        $this-\u003einitRequestParser($request);\n    }\n}\n```\n\nThen you can use the library like this:\n```php\nclass MyController\n{\n    use \\MPScholten\\RequestParser\\Psr7\\ControllerHelperTrait;\n    \n    public function __construct(ServerRequestInterface $request)\n    {\n        $this-\u003einitRequestParser($request);\n    }\n    \n    public function myAction()\n    {\n        $someParameter = $this-\u003equeryParameter('someParameter')-\u003estring()-\u003erequired();\n    }\n}\n```\n\nWhen doing `GET /MyController/myAction?someParameter=example`, the `$someParameter` variable will contain the string `\"example\"`.\n\nYou might wonder what happens when we leave out the `?someParameter` part, like `GET /MyController/myAction`. In this case the\n`$this-\u003equeryParameter('someParameter')-\u003estring()-\u003erequired()` will throw a `NotFoundException`. This exception can\nbe handled by your application to show an error message.\n\nTake a look at [the examples](https://github.com/mpscholten/request-parser/tree/master/examples).\n\n#### Optional Parameters\n\nTo make the `someParameter` optional, we can just replace `required()` with `defaultsTo($someDefaultValue)`:\n```php\nclass MyController\n{\n    use \\MPScholten\\RequestParser\\Symfony\\ControllerHelperTrait;\n    \n    public function __construct(Request $request)\n    {\n        $this-\u003einitRequestParser($request);\n    }\n    \n    public function myAction()\n    {\n        $someParameter = $this-\u003equeryParameter('someParameter')-\u003estring()-\u003edefaultsTo('no value given');\n    }\n}\n```\n\nWhen doing `GET /MyController/myAction`, the `$someParameter` variable will now contain the string `\"no value given\"`. No\nexception will be thrown because we specified a default value.\n\n\nIn general you first specify the parameter name, followed by the type and then specify whether the parameter is required or is optional with a default value.\n\nFor more examples, check out the `examples/` directory of this repository. It contains several runnable examples.\n\n##### Integers, Enums, DateTimes and Json Payloads\n\nOften we need more than just strings. *RequestParser* also provides methods for other data types:\n\n```php\nclass DashboardController\n{\n    public function show()\n    {\n        $dashboardId = $this-\u003equeryParameter('id')-\u003eint()-\u003erequired();\n        \n        // GET /dashboard?name=Hello   =\u003e   $dashboardName == \"Hello\"\n        $dashboardName = $this-\u003equeryParameter('name')-\u003estring()-\u003erequired();\n        \n        // Get /dashboard?name=   =\u003e $dashboardName == \"default value\"\n        $dashboardName = $this-\u003equeryParameter('name')-\u003estring()-\u003edefaultsToIfEmpty(\"default value\");\n        \n        // GET /dashboard?status=private  =\u003e   $dashboardStatus == \"private\"\n        // GET /dashboard?status=public   =\u003e   $dashboardStatus == \"public\"\n        // GET /dashboard?status=invalid  =\u003e   A NotFoundException will be thrown\n        $dashboardStatus = $this-\u003equeryParameter('status')-\u003eoneOf(['private', 'public'])-\u003erequired();\n        \n        // GET /dashboard?createdAt=01.01.2016     =\u003e   $dateTime == new DateTime(\"01.01.2016\")\n        // GET /dashboard?createdAt=invalid_date   =\u003e   A NotFoundException will be thrown\n        $dateTime = $this-\u003equeryParameter('createdAt')-\u003edateTime()-\u003erequired();\n        \n        // GET /dashboard?config={\"a\":true}     =\u003e   $json == ['a' =\u003e true]\n        $json = $this-\u003equeryParameter('config')-\u003ejson()-\u003erequired();\n        \n        // GET /dashboard?includeWidgets=true    =\u003e   $includeWidgets == true\n        // GET /dashboard?includeWidgets=false   =\u003e   $includeWidgets == false\n        // GET /dashboard?includeWidgets=0       =\u003e   $includeWidgets == false\n        // GET /dashboard?includeWidgets=abcde   =\u003e   A NotFoundException will be thrown\n        $includeWidgets = $this-\u003equeryParameter('includeWidgets')-\u003eboolean()-\u003erequired();\n        \n        // GET /dashboard?includeWidgets=yes   =\u003e   $includeWidgets == true\n        // GET /dashboard?includeWidgets=no    =\u003e   $includeWidgets == false\n        $includeWidgets = $this-\u003equeryParameter('includeWidgets')-\u003eyesNoBoolean()-\u003erequired();\n        \n        // GET /image?scale=2.5   =\u003e   $scale == 2.5\n        $scale = $this-\u003equeryParameter('scale')-\u003efloat()-\u003erequired();\n    }\n}\n```\n\nAll of these types also provide a `defaultsTo` variant.\n\n###### Supported Data Types\n\n| Type  | Code example | Input example |\n| ------------- | ------------- | ------------- |\n| **String** | `$this-\u003equeryParameter('name')-\u003estring()-\u003erequired();` | `'John Doe'`  |\n| **Comma-Separated String** | `$this-\u003equeryParameter('names')-\u003ecommaSeparated()-\u003estring()-\u003erequired();` | `'John Doe,John Oliver'` |\n| **Integer** | `$this-\u003equeryParameter('id')-\u003eint()-\u003erequired();` | `'5'` |\n| **Comma-Separated Integer**  | `$this-\u003equeryParameter('groupIds')-\u003ecommaSeparated()-\u003eint()-\u003erequired();` | `'5,6,7,8'` |\n| **Float** | `$this-\u003equeryParameter('ratio')-\u003efloat()-\u003erequired();` | `'0.98'` |\n| **Comma-Separated Float**  | `$this-\u003equeryParameter('precipitation')-\u003ecommaSeparated()-\u003efloat()-\u003erequired();` | `'0.98,1.24,5.21'`  |\n| **DateTime** | `$this-\u003equeryParameter('timestamp')-\u003edateTime()-\u003erequired();` | `'2016-07-20'` |\n| **Comma-Separated DateTime** | `$this-\u003equeryParameter('eventTimes')-\u003ecommaSeparated()-\u003edateTime()-\u003erequired();` | `'2016-07-20 13:10:50,2016-07-21 12:01:07'`  |\n| **Boolean** | `$this-\u003equeryParameter('success')-\u003eboolean()-\u003erequired();` | `'true'` | \n| **Comma-Separated Boolean** | `$this-\u003equeryParameter('answers')-\u003ecommaSeparated()-\u003eboolean()-\u003erequired();` | `'1,0,0,1'` |\n| **Yes/No Boolean**  | `$this-\u003equeryParameter('success')-\u003eyesNoBoolean()-\u003erequired();` | `'yes'`  |\n| **Comma-Separated Yes/No Boolean** | `$this-\u003equeryParameter('answers')-\u003ecommaSeparated()-\u003eyesNoBoolean()-\u003erequired();` | `'y,n,n,y,n'`  |\n| **JSON** | `$this-\u003equeryParameter('payload')-\u003ejson()-\u003erequired();` | `'{\"event\":\"click\",\"timestamp\":\"2016-07-20 13:10:50\"}'` |\n| **Comma-Separated JSON** | `$this-\u003equeryParameter('events')-\u003ecommaSeparated()-\u003ejson()-\u003erequired();` | `'{\"event\":\"click\",\"timestamp\":\"2016-07-20 13:10:50\"},{\"event\":\"add_to_basket\",\"timestamp\":\"2016-07-20 13:11:01\"}'`  |\n\n\n##### GET Requests:\n`$this-\u003equeryParameter($name)` tells the controller that we want a query parameter ([everything after the \"?\" is called the query string](https://en.wikipedia.org/wiki/Query_string)). This is usually what we want when dealing with GET requests\n\n##### POST Requests:\nWhen we're dealing with a POST request, we need to use `$this-\u003ebodyParameter($name)` to access form fields or the ajax payload.\n\n### Autocompletion\n\nThe library allows you to take extensive use of autocompletion features of your IDE. E.g. after typing `$this-\u003equeryParameter('someParameter)-\u003e`\nyour IDE will offer you all the possible input types, e.g. `string()` or `int()`. After picking a type, e.g. `string()`, your IDE will offer\n`required()` or `defaultsTo(defaultValue)` to specify the behavior when the parameter is not set.\n\n![](https://github.com/mpscholten/request-parser/blob/master/images/autocomplete-anim.gif?raw=true)\n\n![](https://github.com/mpscholten/request-parser/blob/master/images/autocompletion-type.png?raw=true)\n![](https://github.com/mpscholten/request-parser/blob/master/images/autocompletion-required.png?raw=true)\n\n### Static Analysis\n\nThe library supports static analysis by your IDE. E.g. when having a parameter like `$createdAt = $this-\u003equeryParameter('createdAt')-\u003edateTime()-\u003erequired();`,\nyour IDE will know that `$createdAt` is a `DateTime` object. This allows you to detect type errors while editing and also decreases the maintenance cost of\nan action because the types improve legibility.\n\nThe library also decreases the risk of unexpected null values because parameters always have an explicit default value or are required.\n\n### Error Handling\n\nWhen a parameter is required but not found or when validation fails, the library will throw an exception. The default exceptions are `\\MPScholten\\RequestParser\\NotFoundException` and `\\MPScholten\\RequestParser\\InvalidValueException`.\nThe suggested way to handle the errors thrown by the library is to catch them inside your front controller:\n\n```php\ntry {\n    $controller-\u003e$action();\n} catch (NotFoundException $e) {\n    echo $e-\u003egetMessage();\n} catch (InvalidValueException $e) {\n    echo $e-\u003egetMessage();\n}\n```\n\n#### Using Custom Exception Classes\n\n```php\nclass MyController\n{\n    use \\MPScholten\\RequestParser\\Symfony\\ControllerHelperTrait;\n    \n    public function __construct(Request $request)\n    {\n        $exceptionFactory = new ExceptionFactory(CustomNotFoundException::class, CustomInvalidValueException::class));\n\n        $config = new \\MPScholten\\RequestParser\\Config();\n        $config-\u003esetExceptionFactory($exceptionFactory);\n\n        $this-\u003einitRequestParser($request, $config);\n    }\n}\n```\n\n#### Using Custom Exception Messages\n\n##### Overriding Single Messages\nIf you need to override the exception message thrown by the library just once or twice, you can do this by passing the exception messages as the first and second argument to `-\u003erequired()`:\n\n```php\nclass DashboardController\n{\n    public function show()\n    {\n        $dashboardId = $this-\u003equeryParameter('id')-\u003eint()-\u003erequired(\"The dashboard id has to be a valid number\", \"No dashboard id given\");\n    }\n}\n```\n\n##### Overriding All Messages\nIf you don't want to specify a custom exception message for all your actions, but still don't want to use the built-in exception messages, you can provide your own exception message generator:\n\n```php\n\nclass FriendlyExceptionMessageFactory extends \\MPScholten\\RequestParser\\ExceptionMessageFactory\n{\n    protected function createNotFoundMessage($parameterName)\n    {\n        return \"Looks like $parameterName is missing :)\";\n    }\n\n    protected function createInvalidValueMessage($parameterName, $parameterValue, $expected)\n    {\n        return \"Whoops :) $parameterName seems to be invalid. We're looking for $expected but you provided '$parameterValue'\";\n    }\n}\n\nclass MyController\n{\n    use \\MPScholten\\RequestParser\\Symfony\\ControllerHelperTrait;\n    \n    public function __construct(Request $request)\n    {\n        $config = new \\MPScholten\\RequestParser\\Config();\n        $config-\u003esetExceptionMessageFactory(new FriendlyExceptionMessageFactory());\n\n        $this-\u003einitRequestParser($request, $config);\n    }\n}\n```\n\nCheck it out [this example about custom exceptions](https://github.com/mpscholten/request-parser/blob/master/examples/custom-exception.php).\n\n\n### Is It Production Ready?\n\nAbsolutely. This library was initially developed at [quintly](https://www.quintly.com) and is extensively used in production since april 2015. Using it at scale in production means there's a a big focus on backwards compatibility and not breaking stuff.\n\n### Tests\n\n```\ncomposer tests\ncomposer tests-coverage\n```\n\n### Contributing\n\nFeel free to send pull requests!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmpscholten%2Frequest-parser","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmpscholten%2Frequest-parser","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmpscholten%2Frequest-parser/lists"}