From 99b7c77997b07b1c0f8ea46c83a7f03f9155d00d Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Tue, 9 Aug 2016 10:24:42 +0200 Subject: [PATCH] Created action to generate QR codes --- composer.json | 3 +- module/Common/src/Response/QrCodeResponse.php | 35 ++++++ module/Core/config/dependencies.config.php | 5 +- module/Core/config/routes.config.php | 10 +- module/Core/src/Action/QrCodeAction.php | 113 ++++++++++++++++++ 5 files changed, 161 insertions(+), 5 deletions(-) create mode 100644 module/Common/src/Response/QrCodeResponse.php create mode 100644 module/Core/src/Action/QrCodeAction.php diff --git a/composer.json b/composer.json index 9ea805ba..1f9bf7bd 100644 --- a/composer.json +++ b/composer.json @@ -28,7 +28,8 @@ "symfony/console": "^3.0", "firebase/php-jwt": "^4.0", "monolog/monolog": "^1.21", - "theorchard/monolog-cascade": "^0.4" + "theorchard/monolog-cascade": "^0.4", + "endroid/qrcode": "^1.7" }, "require-dev": { "phpunit/phpunit": "^5.0", diff --git a/module/Common/src/Response/QrCodeResponse.php b/module/Common/src/Response/QrCodeResponse.php new file mode 100644 index 00000000..e19e4578 --- /dev/null +++ b/module/Common/src/Response/QrCodeResponse.php @@ -0,0 +1,35 @@ +createBody($qrCode), + $status, + $this->injectContentType($qrCode->getContentType(), $headers) + ); + } + + /** + * Create the message body. + * + * @param QrCode $qrCode + * @return StreamInterface + */ + private function createBody(QrCode $qrCode) + { + $body = new Stream('php://temp', 'wb+'); + $body->write($qrCode->get()); + $body->rewind(); + return $body; + } +} diff --git a/module/Core/config/dependencies.config.php b/module/Core/config/dependencies.config.php index 27983069..eb6168f9 100644 --- a/module/Core/config/dependencies.config.php +++ b/module/Core/config/dependencies.config.php @@ -1,6 +1,6 @@ AnnotatedFactory::class, // Middleware - RedirectAction::class => AnnotatedFactory::class, + Action\RedirectAction::class => AnnotatedFactory::class, + Action\QrCodeAction::class => AnnotatedFactory::class, ], ], diff --git a/module/Core/config/routes.config.php b/module/Core/config/routes.config.php index 4d9a85e5..9b499f71 100644 --- a/module/Core/config/routes.config.php +++ b/module/Core/config/routes.config.php @@ -1,5 +1,5 @@ 'long-url-redirect', 'path' => '/{shortCode}', - 'middleware' => RedirectAction::class, + 'middleware' => Action\RedirectAction::class, + 'allowed_methods' => ['GET'], + ], + [ + 'name' => 'short-url-qr-code', + 'path' => '/qr/{shortCode}[/{size:[0-9]+}]', + 'middleware' => Action\QrCodeAction::class, 'allowed_methods' => ['GET'], ], ], diff --git a/module/Core/src/Action/QrCodeAction.php b/module/Core/src/Action/QrCodeAction.php new file mode 100644 index 00000000..5d0549eb --- /dev/null +++ b/module/Core/src/Action/QrCodeAction.php @@ -0,0 +1,113 @@ +router = $router; + $this->urlShortener = $urlShortener; + $this->logger = $logger ?: new NullLogger(); + } + + /** + * Process an incoming request and/or response. + * + * Accepts a server-side request and a response instance, and does + * something with them. + * + * If the response is not complete and/or further processing would not + * interfere with the work done in the middleware, or if the middleware + * wants to delegate to another process, it can use the `$out` callable + * if present. + * + * If the middleware does not return a value, execution of the current + * request is considered complete, and the response instance provided will + * be considered the response to return. + * + * Alternately, the middleware may return a response instance. + * + * Often, middleware will `return $out();`, with the assumption that a + * later middleware will return a response. + * + * @param Request $request + * @param Response $response + * @param null|callable $out + * @return null|Response + */ + public function __invoke(Request $request, Response $response, callable $out = null) + { + // Make sure the short URL exists for this short code + $shortCode = $request->getAttribute('shortCode'); + try { + $shortUrl = $this->urlShortener->shortCodeToUrl($shortCode); + if (! isset($shortUrl)) { + return $out($request, $response->withStatus(404), 'Not Found'); + } + } catch (InvalidShortCodeException $e) { + $this->logger->warning('Tried to create a QR code with an invalid short code' . PHP_EOL . $e); + return $out($request, $response->withStatus(404), 'Not Found'); + } + + $path = $this->router->generateUri('long-url-redirect', ['shortCode' => $shortCode]); + $size = $this->getSizeParam($request); + + $qrCode = new QrCode($request->getUri()->withPath($path)->withQuery('')); + $qrCode->setSize($size) + ->setPadding(0); + return new QrCodeResponse($qrCode); + } + + /** + * @param Request $request + * @return int + */ + protected function getSizeParam(Request $request) + { + $size = intval($request->getAttribute('size', 300)); + if ($size < 50) { + return 50; + } elseif ($size > 1000) { + return 1000; + } + + return $size; + } +}