From 9e814f4a159c7767ac094a1dec1ed8116f633994 Mon Sep 17 00:00:00 2001 From: Marc Scholten Date: Fri, 15 Jul 2016 14:24:26 +0200 Subject: [PATCH 1/8] Added Psr7 integration --- README.md | 53 ++++++++++++++++++++++++- composer.json | 4 +- examples/psr7.php | 62 ++++++++++++++++++++++++++++++ src/Psr7/ControllerHelperTrait.php | 53 +++++++++++++++++++++++++ src/Psr7/Psr7RequestParser.php | 49 +++++++++++++++++++++++ 5 files changed, 218 insertions(+), 3 deletions(-) create mode 100644 examples/psr7.php create mode 100644 src/Psr7/ControllerHelperTrait.php create mode 100644 src/Psr7/Psr7RequestParser.php diff --git a/README.md b/README.md index f1539d3..3c3454b 100644 --- a/README.md +++ b/README.md @@ -70,9 +70,16 @@ Install via composer composer require mpscholten/request-parser ``` -If you're using the `symfony/http-foundation` `Request`, you just need to import a trait into your controller. 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). -The following example asumes you're using the symfony `Request`: +**Integrations:** + + - If you're using `symfony/http-foundation`, [click here](#symfony-httpfoundation) + - If you're using a Psr7 `ServerRequestInterface` implementation, [click here](#psr7) + - 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). + +#### Symfony HttpFoundation + +The following example assumes you're using the symfony `Request`: ```php class MyController @@ -112,6 +119,48 @@ be handled by your application to show an error message. Take a look at [the examples](https://github.com/mpscholten/request-parser/tree/master/examples). +#### Psr7 + +The following example assumes you're using the Psr7 `ServerRequestInterface`: + +```php +class MyController +{ + use \MPScholten\RequestParser\Psr7\ControllerHelperTrait; + + public function __construct(ServerRequestInterface $request) + { + $this->initRequestParser($request); + } +} +``` + +Then you can use the library like this: +```php +class MyController +{ + use \MPScholten\RequestParser\Psr7\ControllerHelperTrait; + + public function __construct(ServerRequestInterface $request) + { + $this->initRequestParser($request); + } + + public function myAction() + { + $someParameter = $this->queryParameter('someParameter')->string()->required(); + } +} +``` + +When doing `GET /MyController/myAction?someParameter=example`, the `$someParameter` variable will contain the string `"example"`. + +You might wonder what happens when we leave out the `?someParameter` part, like `GET /MyController/myAction`. In this case the +`$this->queryParameter('someParameter')->string()->required()` will throw a `NotFoundException`. This exception can +be handled by your application to show an error message. + +Take a look at [the examples](https://github.com/mpscholten/request-parser/tree/master/examples). + #### Optional Parameters To make the `someParameter` optional, we can just replace `required()` with `defaultsTo($someDefaultValue)`: diff --git a/composer.json b/composer.json index ad64487..438e93c 100644 --- a/composer.json +++ b/composer.json @@ -10,7 +10,9 @@ "require": {}, "require-dev": { "phpunit/phpunit": "3.7.*", - "symfony/http-foundation": "3.1.*" + "symfony/http-foundation": "3.1.*", + "symfony/psr-http-message-bridge": "^0.2.0", + "zendframework/zend-diactoros": "^1.3" }, "autoload": { "psr-4": {"MPScholten\\RequestParser\\": "src/"} diff --git a/examples/psr7.php b/examples/psr7.php new file mode 100644 index 0000000..bca0e48 --- /dev/null +++ b/examples/psr7.php @@ -0,0 +1,62 @@ +createRequest($symfonyRequest); + +class MyController +{ + use ControllerHelperTrait; + + public function __construct(ServerRequestInterface $request) + { + $this->initRequestParser($request); + } + + public function hello() + { + $name = $this->queryParameter('name')->string()->required(); + + return "Hello $name"; + } + + public function helloWithDefault() + { + $name = $this->queryParameter('name')->string()->defaultsTo('unknown'); + + return "Hello $name"; + } + + public function json() + { + $payload = $this->queryParameter('payload')->json()->required(); + + return print_r($payload, true); + } +} + +$controller = new MyController($request); +$action = $request->getQueryParams()['action']; + +try { + echo $controller->$action(); +} catch (\MPScholten\RequestParser\NotFoundException $e) { + echo $e->getMessage(); +} diff --git a/src/Psr7/ControllerHelperTrait.php b/src/Psr7/ControllerHelperTrait.php new file mode 100644 index 0000000..836cb3b --- /dev/null +++ b/src/Psr7/ControllerHelperTrait.php @@ -0,0 +1,53 @@ +queryParser = $requestParser->createQueryParser(); + $this->bodyParser = $requestParser->createBodyParser(); + } + + /** + * Use this method to access the query parameters of the request. + * + * $page = $this->queryParameter('page')->int()->defaultsTo(0) + * + * @param string $name + * @return TypeParser + */ + protected function queryParameter($name) + { + return $this->queryParser->get($name); + } + + /** + * Use this method to access the body parameters of the request (e.g. $_POST). + * + * $password = $this->bodyParameter('password')->string()->required() + * + * @param string $name + * @return TypeParser + */ + protected function bodyParameter($name) + { + return $this->bodyParser->get($name); + } +} diff --git a/src/Psr7/Psr7RequestParser.php b/src/Psr7/Psr7RequestParser.php new file mode 100644 index 0000000..1afe770 --- /dev/null +++ b/src/Psr7/Psr7RequestParser.php @@ -0,0 +1,49 @@ +request = $request; + $this->exceptionFactory = $exceptionFactory; + } + + public function createQueryParser() + { + $query = $this->request->getQueryParams(); + + $readParameter = function ($name) use ($query) { + if (!isset($query[$name])) { + return null; + } + + return $query[$name]; + }; + + return new RequestParser($readParameter, $this->exceptionFactory); + } + + public function createBodyParser() + { + $body = $this->request->getParsedBody(); + + $readParameter = function ($name) use ($body) { + if (!isset($body[$name])) { + return null; + } + + return $body[$name]; + }; + + return new RequestParser($readParameter, $this->exceptionFactory); + } +} From a31fb89de394de013df6efc8f862265cb1ca5335 Mon Sep 17 00:00:00 2001 From: Marc Scholten Date: Fri, 15 Jul 2016 14:27:47 +0200 Subject: [PATCH 2/8] Removed empty line --- src/Psr7/Psr7RequestParser.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Psr7/Psr7RequestParser.php b/src/Psr7/Psr7RequestParser.php index 1afe770..6c1d2ed 100644 --- a/src/Psr7/Psr7RequestParser.php +++ b/src/Psr7/Psr7RequestParser.php @@ -9,8 +9,7 @@ class Psr7RequestParser { private $request; private $exceptionFactory; - - + public function __construct(ServerRequestInterface $request, $exceptionFactory = null) { $this->request = $request; From 4e0d542608eddaced28a8a77db9ea3c31882628d Mon Sep 17 00:00:00 2001 From: Marc Scholten Date: Fri, 15 Jul 2016 14:29:24 +0200 Subject: [PATCH 3/8] Improved consistency in the docs --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3c3454b..5aa3aeb 100644 --- a/README.md +++ b/README.md @@ -73,8 +73,8 @@ composer require mpscholten/request-parser **Integrations:** - - If you're using `symfony/http-foundation`, [click here](#symfony-httpfoundation) - - If you're using a Psr7 `ServerRequestInterface` implementation, [click here](#psr7) + - If you're using `symfony/http-foundation`, [click here](#symfony-httpfoundation). + - If you're using a Psr7 `ServerRequestInterface` implementation, [click here](#psr7). - 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). #### Symfony HttpFoundation From dffc7ccf8978c43ad96144535f32e27eb4d4c5b2 Mon Sep 17 00:00:00 2001 From: Marc Scholten Date: Sat, 16 Jul 2016 16:03:20 +0200 Subject: [PATCH 4/8] Introduced BaseControllerHelperTrait --- src/BaseControllerHelperTrait.php | 52 +++++++++++++++++++++++++++ src/Psr7/ControllerHelperTrait.php | 46 +++--------------------- src/Symfony/ControllerHelperTrait.php | 46 +++--------------------- 3 files changed, 60 insertions(+), 84 deletions(-) create mode 100644 src/BaseControllerHelperTrait.php diff --git a/src/BaseControllerHelperTrait.php b/src/BaseControllerHelperTrait.php new file mode 100644 index 0000000..770e12e --- /dev/null +++ b/src/BaseControllerHelperTrait.php @@ -0,0 +1,52 @@ +createRequestParser($request, $exceptionFactory); + $this->queryParser = $requestParser->createQueryParser(); + $this->bodyParser = $requestParser->createBodyParser(); + } + + /** + * Use this method to access the query parameters of the request. + * + * $page = $this->queryParameter('page')->int()->defaultsTo(0) + * + * @param string $name + * @return TypeParser + */ + protected function queryParameter($name) + { + return $this->queryParser->get($name); + } + + /** + * Use this method to access the body parameters of the request (e.g. $_POST). + * + * $password = $this->bodyParameter('password')->string()->required() + * + * @param string $name + * @return TypeParser + */ + protected function bodyParameter($name) + { + return $this->bodyParser->get($name); + } +} diff --git a/src/Psr7/ControllerHelperTrait.php b/src/Psr7/ControllerHelperTrait.php index 836cb3b..a6ffb10 100644 --- a/src/Psr7/ControllerHelperTrait.php +++ b/src/Psr7/ControllerHelperTrait.php @@ -2,52 +2,14 @@ namespace MPScholten\RequestParser\Psr7; -use MPScholten\RequestParser\RequestParser; -use MPScholten\RequestParser\TypeParser; -use Psr\Http\Message\ServerRequestInterface; +use MPScholten\RequestParser\BaseControllerHelperTrait; trait ControllerHelperTrait { - /** - * @var RequestParser - */ - private $queryParser; + use BaseControllerHelperTrait; - /** - * @var RequestParser - */ - private $bodyParser; - - protected final function initRequestParser(ServerRequestInterface $request, callable $exceptionFactory = null) - { - $requestParser = new Psr7RequestParser($request, $exceptionFactory); - $this->queryParser = $requestParser->createQueryParser(); - $this->bodyParser = $requestParser->createBodyParser(); - } - - /** - * Use this method to access the query parameters of the request. - * - * $page = $this->queryParameter('page')->int()->defaultsTo(0) - * - * @param string $name - * @return TypeParser - */ - protected function queryParameter($name) - { - return $this->queryParser->get($name); - } - - /** - * Use this method to access the body parameters of the request (e.g. $_POST). - * - * $password = $this->bodyParameter('password')->string()->required() - * - * @param string $name - * @return TypeParser - */ - protected function bodyParameter($name) + protected final function createRequestParser($request, $exceptionFactory) { - return $this->bodyParser->get($name); + return new Psr7RequestParser($request, $exceptionFactory); } } diff --git a/src/Symfony/ControllerHelperTrait.php b/src/Symfony/ControllerHelperTrait.php index 0e1b747..66bc012 100644 --- a/src/Symfony/ControllerHelperTrait.php +++ b/src/Symfony/ControllerHelperTrait.php @@ -2,52 +2,14 @@ namespace MPScholten\RequestParser\Symfony; -use MPScholten\RequestParser\RequestParser; -use MPScholten\RequestParser\TypeParser; -use Symfony\Component\HttpFoundation\Request; +use MPScholten\RequestParser\BaseControllerHelperTrait; trait ControllerHelperTrait { - /** - * @var RequestParser - */ - private $queryParser; + use BaseControllerHelperTrait; - /** - * @var RequestParser - */ - private $bodyParser; - - protected final function initRequestParser(Request $request, callable $exceptionFactory = null) - { - $requestParser = new SymfonyRequestParser($request, $exceptionFactory); - $this->queryParser = $requestParser->createQueryParser(); - $this->bodyParser = $requestParser->createBodyParser(); - } - - /** - * Use this method to access the query parameters of the request. - * - * $page = $this->queryParameter('page')->int()->defaultsTo(0) - * - * @param string $name - * @return TypeParser - */ - protected function queryParameter($name) - { - return $this->queryParser->get($name); - } - - /** - * Use this method to access the body parameters of the request (e.g. $_POST). - * - * $password = $this->bodyParameter('password')->string()->required() - * - * @param string $name - * @return TypeParser - */ - protected function bodyParameter($name) + protected final function createRequestParser($request, $exceptionFactory) { - return $this->bodyParser->get($name); + return new SymfonyRequestParser($request, $exceptionFactory); } } From b34229e6756153120f675bcb072443942c6ec8c5 Mon Sep 17 00:00:00 2001 From: Marc Scholten Date: Sat, 16 Jul 2016 16:04:38 +0200 Subject: [PATCH 5/8] Removed unused use statements --- src/BaseControllerHelperTrait.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/BaseControllerHelperTrait.php b/src/BaseControllerHelperTrait.php index 770e12e..e3c2fbd 100644 --- a/src/BaseControllerHelperTrait.php +++ b/src/BaseControllerHelperTrait.php @@ -2,9 +2,6 @@ namespace MPScholten\RequestParser; -use MPScholten\RequestParser\RequestParser; -use MPScholten\RequestParser\TypeParser; - trait BaseControllerHelperTrait { /** From 0aa2b1658bbdc450cd2ec7cd000e4602e3760e68 Mon Sep 17 00:00:00 2001 From: Marc Scholten Date: Sat, 16 Jul 2016 16:32:40 +0200 Subject: [PATCH 6/8] Added integration tests --- tests/Integration/Psr7IntegrationTest.php | 90 +++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 tests/Integration/Psr7IntegrationTest.php diff --git a/tests/Integration/Psr7IntegrationTest.php b/tests/Integration/Psr7IntegrationTest.php new file mode 100644 index 0000000..d848935 --- /dev/null +++ b/tests/Integration/Psr7IntegrationTest.php @@ -0,0 +1,90 @@ + 'Test', + 'int' => 1 + ]; + + $request = (new Zend\Diactoros\ServerRequest()); + + $getRequest = $request + ->withMethod('GET') + ->withQueryParams($parameters); + + $postRequest = $request + ->withMethod('POST') + ->withParsedBody($parameters); + + return [ + [new Psr7Controller($getRequest)], + [new Psr7Controller($postRequest)] + ]; + } + + /** + * @dataProvider controllersProvider + */ + public function testStringAction(Psr7Controller $controller) + { + $this->assertEquals('Test', $controller->testString()); + } + + /** + * @dataProvider controllersProvider + */ + public function testIntAction(Psr7Controller $controller) + { + $this->assertEquals(1, $controller->testInt()); + } + + /** + * @dataProvider controllersProvider + */ + public function testNotFoundActionThrowsException(Psr7Controller $controller) + { + $this->setExpectedException(\MPScholten\RequestParser\NotFoundException::class, "Parameter notFound not found"); + $controller->testNotFound(); + } +} + +class Psr7Controller +{ + use \MPScholten\RequestParser\Psr7\ControllerHelperTrait; + + private $request; + + public function __construct(Psr\Http\Message\ServerRequestInterface $request) + { + $this->initRequestParser($request); + $this->request = $request; + } + + protected function parameter($name) + { + if ($this->request->getMethod() === 'GET') { + return $this->queryParameter($name); + } else { + return $this->bodyParameter($name); + } + } + + public function testString() + { + return $this->parameter('string')->string()->required(); + } + + public function testInt() + { + return $this->parameter('int')->int()->required(); + } + + public function testNotFound() + { + return $this->parameter('notFound')->string()->required(); + } +} + From 4e55181ff6dadcdd6f7d8297f55a0db71a4776da Mon Sep 17 00:00:00 2001 From: Marc Scholten Date: Sat, 16 Jul 2016 16:58:14 +0200 Subject: [PATCH 7/8] Further refactoring --- examples/not-symfony.php | 61 +++++++++++++------ src/BaseControllerHelperTrait.php | 7 ++- src/Psr7/ControllerHelperTrait.php | 4 +- ...arser.php => Psr7RequestParserFactory.php} | 3 +- src/RequestParserFactory.php | 16 +++++ src/Symfony/ControllerHelperTrait.php | 4 +- src/Symfony/SymfonyRequestParser.php | 34 ++--------- src/Symfony/SymfonyRequestParserFactory.php | 37 +++++++++++ 8 files changed, 108 insertions(+), 58 deletions(-) rename src/Psr7/{Psr7RequestParser.php => Psr7RequestParserFactory.php} (90%) create mode 100644 src/RequestParserFactory.php create mode 100644 src/Symfony/SymfonyRequestParserFactory.php diff --git a/examples/not-symfony.php b/examples/not-symfony.php index eca623d..1e5d2be 100644 --- a/examples/not-symfony.php +++ b/examples/not-symfony.php @@ -12,45 +12,60 @@ require __DIR__ . '/../vendor/autoload.php'; -trait CustomControllerHelperTrait +class CustomRequestParserFactory implements \MPScholten\RequestParser\RequestParserFactory { - private $queryParser; - private $bodyParser; + /** + * @var array + */ + private $request; + private $exceptionFactory; + + public function __construct(array $request, $exceptionFactory) + { + $this->request = $request; + $this->exceptionFactory = $exceptionFactory; + } - protected final function initRequestParser() + public function createQueryParser() { - $this->queryParser = new MPScholten\RequestParser\RequestParser( + return new MPScholten\RequestParser\RequestParser( function ($parameterName) { - if (isset($_GET[$parameterName])) { - return $_GET[$parameterName]; + if (isset($this->request[$parameterName])) { + return $this->request[$parameterName]; } return null; }, - null + $this->exceptionFactory ); - $this->bodyParser = new MPScholten\RequestParser\RequestParser( + } + + public function createBodyParser() + { + return new MPScholten\RequestParser\RequestParser( function ($parameterName) { - if (isset($_POST[$parameterName])) { - return $_POST[$parameterName]; + if (isset($this->request[$parameterName])) { + return $this->request[$parameterName]; } return null; }, - null + $this->exceptionFactory ); } +} - protected function queryParameter($name) - { - return $this->queryParser->get($name); - } +trait CustomControllerHelperTrait +{ + use \MPScholten\RequestParser\BaseControllerHelperTrait; - protected function bodyParameter($name) + /** + * Will be called during the `initRequestParser()` call in `MyController` + */ + protected final function createRequestParserFactory($request, $exceptionFactory) { - return $this->bodyParser->get($name); + return new CustomRequestParserFactory($request, $exceptionFactory); } - } class MyController @@ -59,7 +74,13 @@ class MyController public function __construct() { - $this->initRequestParser(); + if ($_SERVER['REQUEST_METHOD'] === 'GET') { + $request = $_GET; + } else { + $request = $_POST; + } + + $this->initRequestParser($request); } public function hello() diff --git a/src/BaseControllerHelperTrait.php b/src/BaseControllerHelperTrait.php index e3c2fbd..491695d 100644 --- a/src/BaseControllerHelperTrait.php +++ b/src/BaseControllerHelperTrait.php @@ -16,9 +16,10 @@ trait BaseControllerHelperTrait protected final function initRequestParser($request, callable $exceptionFactory = null) { - $requestParser = $this->createRequestParser($request, $exceptionFactory); - $this->queryParser = $requestParser->createQueryParser(); - $this->bodyParser = $requestParser->createBodyParser(); + /** @var $requestParserFactory RequestParserFactory */ + $requestParserFactory = $this->createRequestParserFactory($request, $exceptionFactory); + $this->queryParser = $requestParserFactory->createQueryParser(); + $this->bodyParser = $requestParserFactory->createBodyParser(); } /** diff --git a/src/Psr7/ControllerHelperTrait.php b/src/Psr7/ControllerHelperTrait.php index a6ffb10..e48fac0 100644 --- a/src/Psr7/ControllerHelperTrait.php +++ b/src/Psr7/ControllerHelperTrait.php @@ -8,8 +8,8 @@ trait ControllerHelperTrait { use BaseControllerHelperTrait; - protected final function createRequestParser($request, $exceptionFactory) + protected final function createRequestParserFactory($request, $exceptionFactory) { - return new Psr7RequestParser($request, $exceptionFactory); + return new Psr7RequestParserFactory($request, $exceptionFactory); } } diff --git a/src/Psr7/Psr7RequestParser.php b/src/Psr7/Psr7RequestParserFactory.php similarity index 90% rename from src/Psr7/Psr7RequestParser.php rename to src/Psr7/Psr7RequestParserFactory.php index 6c1d2ed..be760e1 100644 --- a/src/Psr7/Psr7RequestParser.php +++ b/src/Psr7/Psr7RequestParserFactory.php @@ -3,9 +3,10 @@ namespace MPScholten\RequestParser\Psr7; use MPScholten\RequestParser\RequestParser; +use MPScholten\RequestParser\RequestParserFactory; use Psr\Http\Message\ServerRequestInterface; -class Psr7RequestParser +class Psr7RequestParserFactory implements RequestParserFactory { private $request; private $exceptionFactory; diff --git a/src/RequestParserFactory.php b/src/RequestParserFactory.php new file mode 100644 index 0000000..17eeb78 --- /dev/null +++ b/src/RequestParserFactory.php @@ -0,0 +1,16 @@ +request = $request; - $this->exceptionFactory = $exceptionFactory; - } - - public function createQueryParser() - { - $readParameter = function ($name) { - return $this->request->query->get($name, null); - }; - - return new RequestParser($readParameter, $this->exceptionFactory); - } - - public function createBodyParser() - { - $readParameter = function ($name) { - return $this->request->request->get($name, null); - }; - - return new RequestParser($readParameter, $this->exceptionFactory); - } } diff --git a/src/Symfony/SymfonyRequestParserFactory.php b/src/Symfony/SymfonyRequestParserFactory.php new file mode 100644 index 0000000..8fd48bb --- /dev/null +++ b/src/Symfony/SymfonyRequestParserFactory.php @@ -0,0 +1,37 @@ +request = $request; + $this->exceptionFactory = $exceptionFactory; + } + + public function createQueryParser() + { + $readParameter = function ($name) { + return $this->request->query->get($name, null); + }; + + return new RequestParser($readParameter, $this->exceptionFactory); + } + + public function createBodyParser() + { + $readParameter = function ($name) { + return $this->request->request->get($name, null); + }; + + return new RequestParser($readParameter, $this->exceptionFactory); + } +} From f3ce868a66d78600afcf30dedd96f577ea0acd61 Mon Sep 17 00:00:00 2001 From: Marc Scholten Date: Sat, 16 Jul 2016 17:03:40 +0200 Subject: [PATCH 8/8] Removed empty new line --- tests/Integration/Psr7IntegrationTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Integration/Psr7IntegrationTest.php b/tests/Integration/Psr7IntegrationTest.php index d848935..bbf5a3b 100644 --- a/tests/Integration/Psr7IntegrationTest.php +++ b/tests/Integration/Psr7IntegrationTest.php @@ -87,4 +87,3 @@ public function testNotFound() return $this->parameter('notFound')->string()->required(); } } -