From b2615d0de679fcc5696835bd8446632f87957522 Mon Sep 17 00:00:00 2001 From: Alejandro Celaya <alejandro@alejandrocelaya.com> Date: Sat, 30 Apr 2016 18:59:03 +0200 Subject: [PATCH] Implemented routable redirect middleware --- composer.json | 6 +- config/autoload/routes.global.php | 13 ++-- config/autoload/services.global.php | 5 +- src/Middleware/CliParamsMiddleware.php | 2 +- .../Factory/CliParamsMiddlewareFactory.php | 2 +- .../Routable/RedirectMiddleware.php | 75 +++++++++++++++++++ templates/error/404.html.twig | 3 +- templates/layout/default.html.twig | 36 +-------- 8 files changed, 92 insertions(+), 50 deletions(-) create mode 100644 src/Middleware/Routable/RedirectMiddleware.php diff --git a/composer.json b/composer.json index 652d81d1..d43d7fbb 100644 --- a/composer.json +++ b/composer.json @@ -14,10 +14,10 @@ "php": "^5.5 || ^7.0", "zendframework/zend-expressive": "^1.0", "zendframework/zend-expressive-helpers": "^2.0", - "zendframework/zend-stdlib": "^2.7", - "zendframework/zend-expressive-aurarouter": "^1.0", - "zendframework/zend-servicemanager": "^3.0", + "zendframework/zend-expressive-fastroute": "^1.1", "zendframework/zend-expressive-twigrenderer": "^1.0", + "zendframework/zend-stdlib": "^2.7", + "zendframework/zend-servicemanager": "^3.0", "doctrine/orm": "^2.5", "guzzlehttp/guzzle": "^6.2", "acelaya/zsm-annotated-services": "^0.2.0" diff --git a/config/autoload/routes.global.php b/config/autoload/routes.global.php index a95711aa..40a3d20b 100644 --- a/config/autoload/routes.global.php +++ b/config/autoload/routes.global.php @@ -1,14 +1,15 @@ <?php +use Acelaya\UrlShortener\Middleware\Routable; return [ 'routes' => [ -// [ -// 'name' => 'home', -// 'path' => '/', -// 'middleware' => '', -// 'allowed_methods' => ['GET'], -// ], + [ + 'name' => 'long-url-redirect', + 'path' => '/{shortCode}', + 'middleware' => Routable\RedirectMiddleware::class, + 'allowed_methods' => ['GET'], + ], ], ]; diff --git a/config/autoload/services.global.php b/config/autoload/services.global.php index 421c8a00..414b2e56 100644 --- a/config/autoload/services.global.php +++ b/config/autoload/services.global.php @@ -25,7 +25,7 @@ return [ Helper\ServerUrlMiddleware::class => Helper\ServerUrlMiddlewareFactory::class, Helper\UrlHelperMiddleware::class => Helper\UrlHelperMiddlewareFactory::class, Helper\ServerUrlHelper::class => InvokableFactory::class, - Router\AuraRouter::class => InvokableFactory::class, + Router\FastRouteRouter::class => InvokableFactory::class, // View 'Zend\Expressive\FinalHandler' => Container\TemplatedErrorHandlerFactory::class, @@ -39,12 +39,13 @@ return [ // Middleware Middleware\CliRoutable\GenerateShortcodeMiddleware::class => AnnotatedFactory::class, + Middleware\Routable\RedirectMiddleware::class => AnnotatedFactory::class, Middleware\CliParamsMiddleware::class => Middleware\Factory\CliParamsMiddlewareFactory::class, ], 'aliases' => [ 'em' => EntityManager::class, 'httpClient' => GuzzleHttp\Client::class, - Router\RouterInterface::class => Router\AuraRouter::class, + Router\RouterInterface::class => Router\FastRouteRouter::class, ] ], diff --git a/src/Middleware/CliParamsMiddleware.php b/src/Middleware/CliParamsMiddleware.php index c750ff9b..da243a15 100644 --- a/src/Middleware/CliParamsMiddleware.php +++ b/src/Middleware/CliParamsMiddleware.php @@ -46,7 +46,7 @@ class CliParamsMiddleware implements MiddlewareInterface public function __invoke(Request $request, Response $response, callable $out = null) { // When not in CLI, just call next middleware - if (! php_sapi_name() === 'cli') { + if (php_sapi_name() !== 'cli') { return $out($request, $response); } diff --git a/src/Middleware/Factory/CliParamsMiddlewareFactory.php b/src/Middleware/Factory/CliParamsMiddlewareFactory.php index 73e365ac..b806cbeb 100644 --- a/src/Middleware/Factory/CliParamsMiddlewareFactory.php +++ b/src/Middleware/Factory/CliParamsMiddlewareFactory.php @@ -24,6 +24,6 @@ class CliParamsMiddlewareFactory implements FactoryInterface */ public function __invoke(ContainerInterface $container, $requestedName, array $options = null) { - return new CliParamsMiddleware($_SERVER['argv']); + return new CliParamsMiddleware(isset($_SERVER['argv']) ? $_SERVER['argv'] : []); } } diff --git a/src/Middleware/Routable/RedirectMiddleware.php b/src/Middleware/Routable/RedirectMiddleware.php new file mode 100644 index 00000000..29870d46 --- /dev/null +++ b/src/Middleware/Routable/RedirectMiddleware.php @@ -0,0 +1,75 @@ +<?php +namespace Acelaya\UrlShortener\Middleware\Routable; + +use Acelaya\UrlShortener\Service\UrlShortener; +use Acelaya\UrlShortener\Service\UrlShortenerInterface; +use Acelaya\ZsmAnnotatedServices\Annotation\Inject; +use Psr\Http\Message\ResponseInterface as Response; +use Psr\Http\Message\ServerRequestInterface as Request; +use Zend\Diactoros\Response\RedirectResponse; +use Zend\Stratigility\MiddlewareInterface; + +class RedirectMiddleware implements MiddlewareInterface +{ + /** + * @var UrlShortenerInterface + */ + private $urlShortener; + + /** + * RedirectMiddleware constructor. + * @param UrlShortenerInterface|UrlShortener $urlShortener + * + * @Inject({UrlShortener::class}) + */ + public function __construct(UrlShortenerInterface $urlShortener) + { + $this->urlShortener = $urlShortener; + } + + /** + * 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) + { + $shortCode = $request->getAttribute('shortCode', ''); + + try { + $longUrl = $this->urlShortener->shortCodeToUrl($shortCode); + + // If provided shortCode does not belong to a valid long URL, dispatch next middleware, which is 404 + // middleware + if (! isset($longUrl)) { + return $out($request, $response); + } + + // Return a redirect response to the long URL + return new RedirectResponse($longUrl, 301); + } catch (\Exception $e) { + // In case of error, dispatch 404 error + return $out($request, $response); + } + } +} diff --git a/templates/error/404.html.twig b/templates/error/404.html.twig index 7b4e363e..8e3f3a7a 100644 --- a/templates/error/404.html.twig +++ b/templates/error/404.html.twig @@ -7,7 +7,6 @@ <h2>This is awkward.</h2> <p>We encountered a 404 Not Found error.</p> <p> - You are looking for something that doesn't exist or may have moved. Check out one of the links on this page - or head back to <a href="{{ path('home') }}">Home</a>. + You are looking for something that doesn't exist or may have moved. </p> {% endblock %} diff --git a/templates/layout/default.html.twig b/templates/layout/default.html.twig index b3664d0e..ac34990a 100644 --- a/templates/layout/default.html.twig +++ b/templates/layout/default.html.twig @@ -17,40 +17,6 @@ {% block stylesheets %}{% endblock %} </head> <body class="app"> - <header class="app-header"> - <nav class="navbar navbar-inverse navbar-fixed-top" role="navigation"> - <div class="container"> - <div class="navbar-header"> - <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"> - <span class="icon-bar"></span> - <span class="icon-bar"></span> - <span class="icon-bar"></span> - </button> - <a class="navbar-brand" href="{{ path('home') }}"> - <img src="{{ asset('zf-logo.png') }}" alt="Zend Expressive" /> - </a> - </div> - <div class="collapse navbar-collapse"> - <ul class="nav navbar-nav"> - <li> - <a href="https://zendframework.github.io/zend-expressive/" target="_blank"> - <i class="fa fa-book"></i> Docs - </a> - </li> - <li> - <a href="https://github.com/zendframework/zend-expressive" target="_blank"> - <i class="fa fa-wrench"></i> Contribute - </a> - </li> - <li> - - </li> - </ul> - </div> - </div> - </nav> - </header> - <div class="app-content"> <main class="container"> {% block content %}{% endblock %} @@ -62,7 +28,7 @@ <hr /> {% block footer %} <p> - © 2005 - {{ "now"|date("Y") }} by Zend Technologies Ltd. All rights reserved. + © {{ "now" | date("Y") }} by Alejandro Celaya. </p> {% endblock %} </div>