diff --git a/.travis.yml b/.travis.yml index 6e5357c0f..982179948 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,6 @@ branches: - /.*/ php: - - 7 - 7.1 - 7.2 @@ -16,12 +15,10 @@ before_install: before_script: - composer self-update - composer install --no-interaction - - if [[ $TRAVIS_PHP_VERSION = 7.1 ]] || [[ $TRAVIS_PHP_VERSION = 7.2 ]]; then composer global require --dev phpstan/phpstan:0.9.*; fi script: - mkdir build - composer check - - if [[ $TRAVIS_PHP_VERSION = 7.1 ]] || [[ $TRAVIS_PHP_VERSION = 7.2 ]]; then ~/.composer/vendor/bin/phpstan analyse module/*/src/ --level=6 -c phpstan.neon; fi after_script: - vendor/bin/phpcov merge build --clover build/clover.xml diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d5b69cbd..114abffcb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,21 @@ ## CHANGELOG +### 1.8.1 + +**Features** + +* [125: Implement a path which returns a 1px image instead of a redirection](https://github.com/shlinkio/shlink/issues/125) + +**Enhancements:** + +* [130: Update to Expressive 3](https://github.com/shlinkio/shlink/issues/130) +* [137: Update symfony packages to v4](https://github.com/shlinkio/shlink/issues/137) + +**Tasks** + +* [131: Drop support for PHP 7](https://github.com/shlinkio/shlink/issues/131) +* [132: Add infection to improve tests](https://github.com/shlinkio/shlink/issues/132) + ### 1.7.2 **Bugs:** diff --git a/composer.json b/composer.json index d961f5d5d..7fe311bb3 100644 --- a/composer.json +++ b/composer.json @@ -12,8 +12,8 @@ } ], "require": { - "php": "^7.0", - "acelaya/ze-content-based-error-handler": "^2.0", + "php": "^7.1", + "acelaya/ze-content-based-error-handler": "^2.2", "cocur/slugify": "^3.0", "doctrine/annotations": "^1.4", "doctrine/cache": "^1.6", @@ -22,23 +22,23 @@ "doctrine/dbal": "^2.5", "doctrine/migrations": "^1.4", "doctrine/orm": "^2.5", - "endroid/qrcode": "^1.7", + "endroid/qr-code": "^1.7", "firebase/php-jwt": "^4.0", "guzzlehttp/guzzle": "^6.2", - "http-interop/http-middleware": "^0.4.1", "mikehaertl/phpwkhtmltopdf": "^2.2", "monolog/monolog": "^1.21", "roave/security-advisories": "dev-master", - "symfony/console": "^3.4", - "symfony/filesystem": "^3.0", - "symfony/process": "^3.0", + "symfony/console": "^4.0", + "symfony/filesystem": "^4.0", + "symfony/process": "^4.0", "theorchard/monolog-cascade": "^0.4", "zendframework/zend-config": "^3.0", "zendframework/zend-config-aggregator": "^1.0", - "zendframework/zend-expressive": "^2.0", - "zendframework/zend-expressive-fastroute": "^2.0", - "zendframework/zend-expressive-helpers": "^4.2", - "zendframework/zend-expressive-platesrenderer": "^1.3", + "zendframework/zend-diactoros": "^1.7", + "zendframework/zend-expressive": "^3.0", + "zendframework/zend-expressive-fastroute": "^3.0", + "zendframework/zend-expressive-helpers": "^5.0", + "zendframework/zend-expressive-platesrenderer": "^2.0", "zendframework/zend-i18n": "^2.7", "zendframework/zend-inputfilter": "^2.8", "zendframework/zend-paginator": "^2.6", @@ -47,14 +47,16 @@ }, "require-dev": { "filp/whoops": "^2.0", - "phpunit/dbunit": "^3.0", - "phpunit/phpcov": "^4.0", - "phpunit/phpunit": "^6.0", + "infection/infection": "^0.8.1", + "phpstan/phpstan": "0.9", + "phpunit/phpcov": "^5.0", + "phpunit/phpunit": "^7.0", "slevomat/coding-standard": "^4.0", "squizlabs/php_codesniffer": "^3.1 <3.2", - "symfony/dotenv": "^3.4", - "symfony/var-dumper": "^3.0", - "zendframework/zend-expressive-tooling": "^0.4" + "symfony/dotenv": "^4.0", + "symfony/var-dumper": "^4.0", + "zendframework/zend-component-installer": "^2.1", + "zendframework/zend-expressive-tooling": "^1.0" }, "autoload": { "psr-4": { @@ -84,8 +86,10 @@ "scripts": { "check": [ "@cs", + "@stan", "@test", - "@func-test" + "@func-test", + "@infect" ], "cs": "phpcs", "cs-fix": "phpcbf", @@ -97,13 +101,17 @@ "@test", "@func-test", "phpcov merge build --html build/html" - ] + ], + "stan": "phpstan analyse module/*/src/ --level=6 -c phpstan.neon", + "infect": "infection --threads=4 --min-msi=65 --only-covered --log-verbosity=2", + "infect-show": "infection --threads=4 --min-msi=65 --only-covered --log-verbosity=2 --show-mutations", + "expressive": "expressive" }, "config": { "process-timeout": 0, "sort-packages": true, "platform": { - "php": "7.0.8" + "php": "7.1.8" } } } diff --git a/config/autoload/dependencies.global.php b/config/autoload/dependencies.global.php index 8afccea03..aa105e6d6 100644 --- a/config/autoload/dependencies.global.php +++ b/config/autoload/dependencies.global.php @@ -5,30 +5,23 @@ use Zend\Expressive; use Zend\Expressive\Container; use Zend\Expressive\Helper; -use Zend\Expressive\Middleware; -use Zend\Expressive\Plates; -use Zend\Expressive\Router; use Zend\Expressive\Router\Middleware\ImplicitOptionsMiddleware; -use Zend\Expressive\Template; use Zend\ServiceManager\Factory\InvokableFactory; -use Zend\Stratigility\Middleware\ErrorHandler; return [ 'dependencies' => [ 'factories' => [ - Expressive\Application::class => Container\ApplicationFactory::class, - Template\TemplateRendererInterface::class => Plates\PlatesRendererFactory::class, - Router\RouterInterface::class => Router\FastRouteRouterFactory::class, - ErrorHandler::class => Container\ErrorHandlerFactory::class, ImplicitOptionsMiddleware::class => EmptyResponseImplicitOptionsMiddlewareFactory::class, Helper\UrlHelper::class => Helper\UrlHelperFactory::class, Helper\ServerUrlHelper::class => InvokableFactory::class, ], - 'aliases' => [ - Middleware\ImplicitOptionsMiddleware::class => ImplicitOptionsMiddleware::class, + 'delegators' => [ + Expressive\Application::class => [ + Container\ApplicationConfigInjectionDelegator::class, + ], ], ], diff --git a/config/autoload/middleware-pipeline.global.php b/config/autoload/middleware-pipeline.global.php index 2d4c0c18d..dad75c139 100644 --- a/config/autoload/middleware-pipeline.global.php +++ b/config/autoload/middleware-pipeline.global.php @@ -2,6 +2,7 @@ declare(strict_types=1); use Shlinkio\Shlink\Common\Middleware\LocaleMiddleware; +use Shlinkio\Shlink\Core\Response\NotFoundDelegate; use Shlinkio\Shlink\Rest\Middleware\BodyParserMiddleware; use Shlinkio\Shlink\Rest\Middleware\CheckAuthenticationMiddleware; use Shlinkio\Shlink\Rest\Middleware\CrossDomainMiddleware; @@ -48,6 +49,7 @@ 'post-routing' => [ 'middleware' => [ Expressive\Router\Middleware\DispatchMiddleware::class, + NotFoundDelegate::class, ], 'priority' => 1, ], diff --git a/config/config.php b/config/config.php index 28ad33348..d7ec97e90 100644 --- a/config/config.php +++ b/config/config.php @@ -7,6 +7,7 @@ use Shlinkio\Shlink\Core; use Shlinkio\Shlink\Rest; use Zend\ConfigAggregator; +use Zend\Expressive; /** * Configuration files are loaded in a specific order. First ``global.php``, then ``*.global.php``. @@ -18,8 +19,11 @@ */ return (new ConfigAggregator\ConfigAggregator([ - Zend\Expressive\ConfigProvider::class, - Zend\Expressive\Router\ConfigProvider::class, + Expressive\ConfigProvider::class, + Expressive\Router\ConfigProvider::class, + Expressive\Router\FastRouteRouter\ConfigProvider::class, + Expressive\Plates\ConfigProvider::class, + Expressive\Helper\ConfigProvider::class, ExpressiveErrorHandler\ConfigProvider::class, Common\ConfigProvider::class, Core\ConfigProvider::class, diff --git a/infection.json b/infection.json new file mode 100644 index 000000000..5f5fb65bf --- /dev/null +++ b/infection.json @@ -0,0 +1,18 @@ +{ + "source": { + "directories": [ + "module/*/src" + ], + "excludes": [] + }, + "timeout": 10, + "logs": { + "text": "build/infection/infection-log.txt", + "summary": "build/infection/summary-log.txt", + "debug": "build/infection/debug-log.txt" + }, + "tmpDir": "build/infection/temp", + "phpUnit": { + "configDir": "." + } +} diff --git a/module/CLI/src/Command/Install/InstallCommand.php b/module/CLI/src/Command/Install/InstallCommand.php index ef08b460c..06f1be930 100644 --- a/module/CLI/src/Command/Install/InstallCommand.php +++ b/module/CLI/src/Command/Install/InstallCommand.php @@ -134,7 +134,7 @@ public function execute(InputInterface $input, OutputInterface $output) if (! $this->isUpdate) { $this->io->write('Initializing database...'); if (! $this->runCommand( - 'php vendor/bin/doctrine.php orm:schema-tool:create', + 'php vendor/bin/doctrine orm:schema-tool:create', 'Error generating database.', $output )) { @@ -155,7 +155,7 @@ public function execute(InputInterface $input, OutputInterface $output) // Generate proxies $this->io->write('Generating proxies...'); if (! $this->runCommand( - 'php vendor/bin/doctrine.php orm:generate-proxies', + 'php vendor/bin/doctrine orm:generate-proxies', 'Error generating proxies.', $output )) { diff --git a/module/Common/src/Factory/EmptyResponseImplicitOptionsMiddlewareFactory.php b/module/Common/src/Factory/EmptyResponseImplicitOptionsMiddlewareFactory.php index 89858e8c0..4371bb6b8 100644 --- a/module/Common/src/Factory/EmptyResponseImplicitOptionsMiddlewareFactory.php +++ b/module/Common/src/Factory/EmptyResponseImplicitOptionsMiddlewareFactory.php @@ -27,6 +27,8 @@ class EmptyResponseImplicitOptionsMiddlewareFactory implements FactoryInterface */ public function __invoke(ContainerInterface $container, $requestedName, array $options = null) { - return new ImplicitOptionsMiddleware(new EmptyResponse()); + return new ImplicitOptionsMiddleware(function () { + return new EmptyResponse(); + }); } } diff --git a/module/Common/src/Middleware/LocaleMiddleware.php b/module/Common/src/Middleware/LocaleMiddleware.php index 1c48c863c..cdb5df196 100644 --- a/module/Common/src/Middleware/LocaleMiddleware.php +++ b/module/Common/src/Middleware/LocaleMiddleware.php @@ -3,10 +3,10 @@ namespace Shlinkio\Shlink\Common\Middleware; -use Interop\Http\ServerMiddleware\DelegateInterface; -use Interop\Http\ServerMiddleware\MiddlewareInterface; use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; +use Psr\Http\Server\MiddlewareInterface; +use Psr\Http\Server\RequestHandlerInterface as DelegateInterface; use Zend\I18n\Translator\Translator; class LocaleMiddleware implements MiddlewareInterface @@ -32,15 +32,15 @@ public function __construct(Translator $translator) * * @return Response */ - public function process(Request $request, DelegateInterface $delegate) + public function process(Request $request, DelegateInterface $delegate): Response { if (! $request->hasHeader('Accept-Language')) { - return $delegate->process($request); + return $delegate->handle($request); } $locale = $request->getHeaderLine('Accept-Language'); $this->translator->setLocale($this->normalizeLocale($locale)); - return $delegate->process($request); + return $delegate->handle($request); } /** diff --git a/module/Common/src/Response/PixelResponse.php b/module/Common/src/Response/PixelResponse.php new file mode 100644 index 000000000..a19c1c85c --- /dev/null +++ b/module/Common/src/Response/PixelResponse.php @@ -0,0 +1,33 @@ +createBody(), $status, $headers); + } + + /** + * Create the message body. + * + * @return StreamInterface + */ + private function createBody(): StreamInterface + { + $body = new Stream('php://temp', 'wb+'); + $body->write(\base64_decode(self::BASE_64_IMAGE)); + $body->rewind(); + return $body; + } +} diff --git a/module/Common/test-func/DbUnit/DatabaseTestCase.php b/module/Common/test-func/DbUnit/DatabaseTestCase.php index 58a10bdc3..89ee871f0 100644 --- a/module/Common/test-func/DbUnit/DatabaseTestCase.php +++ b/module/Common/test-func/DbUnit/DatabaseTestCase.php @@ -3,40 +3,17 @@ namespace ShlinkioTest\Shlink\Common\DbUnit; -use Doctrine\DBAL\Driver\PDOConnection; use Doctrine\ORM\EntityManagerInterface; -use PHPUnit\DbUnit\Database\Connection as DbConn; -use PHPUnit\DbUnit\DataSet\IDataSet as DataSet; -use PHPUnit\DbUnit\TestCase; +use PHPUnit\Framework\TestCase; abstract class DatabaseTestCase extends TestCase { - const ENTITIES_TO_EMPTY = []; + protected const ENTITIES_TO_EMPTY = []; /** * @var EntityManagerInterface */ public static $em; - /** - * @var DbConn - */ - private static $conn; - - public function getConnection(): DbConn - { - if (isset(self::$conn)) { - return self::$conn; - } - - /** @var PDOConnection $pdo */ - $pdo = static::$em->getConnection()->getWrappedConnection(); - return self::$conn = $this->createDefaultDBConnection($pdo, static::$em->getConnection()->getDatabase()); - } - - public function getDataSet(): DataSet - { - return $this->createArrayDataSet([]); - } protected function getEntityManager(): EntityManagerInterface { diff --git a/module/Common/test/Factory/EmptyResponseImplicitOptionsMiddlewareFactoryTest.php b/module/Common/test/Factory/EmptyResponseImplicitOptionsMiddlewareFactoryTest.php index 11b76440c..8e6b17b76 100644 --- a/module/Common/test/Factory/EmptyResponseImplicitOptionsMiddlewareFactoryTest.php +++ b/module/Common/test/Factory/EmptyResponseImplicitOptionsMiddlewareFactoryTest.php @@ -38,8 +38,8 @@ public function responsePrototypeIsEmptyResponse() $instance = $this->factory->__invoke(new ServiceManager(), ''); $ref = new \ReflectionObject($instance); - $prop = $ref->getProperty('response'); + $prop = $ref->getProperty('responseFactory'); $prop->setAccessible(true); - $this->assertInstanceOf(EmptyResponse::class, $prop->getValue($instance)); + $this->assertInstanceOf(EmptyResponse::class, $prop->getValue($instance)()); } } diff --git a/module/Common/test/Middleware/LocaleMiddlewareTest.php b/module/Common/test/Middleware/LocaleMiddlewareTest.php index 703ef7000..35b6aa3ae 100644 --- a/module/Common/test/Middleware/LocaleMiddlewareTest.php +++ b/module/Common/test/Middleware/LocaleMiddlewareTest.php @@ -32,7 +32,7 @@ public function setUp() public function whenNoHeaderIsPresentLocaleIsNotChanged() { $this->assertEquals('ru', $this->translator->getLocale()); - $this->middleware->process(ServerRequestFactory::fromGlobals(), TestUtils::createDelegateMock()->reveal()); + $this->middleware->process(ServerRequestFactory::fromGlobals(), TestUtils::createReqHandlerMock()->reveal()); $this->assertEquals('ru', $this->translator->getLocale()); } @@ -43,7 +43,7 @@ public function whenTheHeaderIsPresentLocaleIsChanged() { $this->assertEquals('ru', $this->translator->getLocale()); $request = ServerRequestFactory::fromGlobals()->withHeader('Accept-Language', 'es'); - $this->middleware->process($request, TestUtils::createDelegateMock()->reveal()); + $this->middleware->process($request, TestUtils::createReqHandlerMock()->reveal()); $this->assertEquals('es', $this->translator->getLocale()); } @@ -52,7 +52,7 @@ public function whenTheHeaderIsPresentLocaleIsChanged() */ public function localeGetsNormalized() { - $delegate = TestUtils::createDelegateMock(); + $delegate = TestUtils::createReqHandlerMock(); $this->assertEquals('ru', $this->translator->getLocale()); diff --git a/module/Common/test/Util/TestUtils.php b/module/Common/test/Util/TestUtils.php index 075498d29..64ed655ab 100644 --- a/module/Common/test/Util/TestUtils.php +++ b/module/Common/test/Util/TestUtils.php @@ -3,22 +3,22 @@ namespace ShlinkioTest\Shlink\Common\Util; -use Interop\Http\ServerMiddleware\DelegateInterface; use Prophecy\Argument; use Prophecy\Prophet; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; +use Psr\Http\Server\RequestHandlerInterface; use Zend\Diactoros\Response; class TestUtils { private static $prophet; - public static function createDelegateMock(ResponseInterface $response = null, RequestInterface $request = null) + public static function createReqHandlerMock(ResponseInterface $response = null, RequestInterface $request = null) { $argument = $request ?: Argument::any(); - $delegate = static::getProphet()->prophesize(DelegateInterface::class); - $delegate->process($argument)->willReturn($response ?: new Response()); + $delegate = static::getProphet()->prophesize(RequestHandlerInterface::class); + $delegate->handle($argument)->willReturn($response ?: new Response()); return $delegate; } diff --git a/module/Core/config/dependencies.config.php b/module/Core/config/dependencies.config.php index 11038e4b0..9061a3f5e 100644 --- a/module/Core/config/dependencies.config.php +++ b/module/Core/config/dependencies.config.php @@ -28,6 +28,7 @@ // Middleware Action\RedirectAction::class => ConfigAbstractFactory::class, + Action\PixelAction::class => ConfigAbstractFactory::class, Action\QrCodeAction::class => ConfigAbstractFactory::class, Action\PreviewAction::class => ConfigAbstractFactory::class, Middleware\QrCodeCacheMiddleware::class => ConfigAbstractFactory::class, @@ -60,6 +61,11 @@ Service\VisitsTracker::class, Options\AppOptions::class, ], + Action\PixelAction::class => [ + Service\UrlShortener::class, + Service\VisitsTracker::class, + Options\AppOptions::class, + ], Action\QrCodeAction::class => [RouterInterface::class, Service\UrlShortener::class, 'Logger_Shlink'], Action\PreviewAction::class => [PreviewGenerator::class, Service\UrlShortener::class], Middleware\QrCodeCacheMiddleware::class => [Cache::class], diff --git a/module/Core/config/routes.config.php b/module/Core/config/routes.config.php index e18cb4485..2d8c80b37 100644 --- a/module/Core/config/routes.config.php +++ b/module/Core/config/routes.config.php @@ -13,6 +13,12 @@ 'middleware' => Action\RedirectAction::class, 'allowed_methods' => ['GET'], ], + [ + 'name' => 'pixel-tracking', + 'path' => '/{shortCode}/track', + 'middleware' => Action\PixelAction::class, + 'allowed_methods' => ['GET'], + ], [ 'name' => 'short-url-qr-code', 'path' => '/{shortCode}/qr-code[/{size:[0-9]+}]', diff --git a/module/Core/src/Action/AbstractTrackingAction.php b/module/Core/src/Action/AbstractTrackingAction.php new file mode 100644 index 000000000..0ee475dbe --- /dev/null +++ b/module/Core/src/Action/AbstractTrackingAction.php @@ -0,0 +1,74 @@ +urlShortener = $urlShortener; + $this->visitTracker = $visitTracker; + $this->appOptions = $appOptions; + } + + /** + * Process an incoming server request and return a response, optionally delegating + * to the next middleware component to create the response. + * + * @param ServerRequestInterface $request + * @param RequestHandlerInterface $handler + * + * @return ResponseInterface + */ + public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface + { + $shortCode = $request->getAttribute('shortCode', ''); + $query = $request->getQueryParams(); + $disableTrackParam = $this->appOptions->getDisableTrackParam(); + + try { + $longUrl = $this->urlShortener->shortCodeToUrl($shortCode); + + // Track visit to this short code + if ($disableTrackParam === null || ! \array_key_exists($disableTrackParam, $query)) { + $this->visitTracker->track($shortCode, $request); + } + + return $this->createResp($longUrl); + } catch (InvalidShortCodeException | EntityDoesNotExistException $e) { + return $this->buildErrorResponse($request, $handler); + } + } + + abstract protected function createResp(string $longUrl): ResponseInterface; +} diff --git a/module/Core/src/Action/PixelAction.php b/module/Core/src/Action/PixelAction.php new file mode 100644 index 000000000..5f2c797ae --- /dev/null +++ b/module/Core/src/Action/PixelAction.php @@ -0,0 +1,15 @@ +getAttribute('shortCode'); @@ -52,12 +52,8 @@ public function process(Request $request, DelegateInterface $delegate) $url = $this->urlShortener->shortCodeToUrl($shortCode); $imagePath = $this->previewGenerator->generatePreview($url); return $this->generateImageResponse($imagePath); - } catch (InvalidShortCodeException $e) { - return $this->buildErrorResponse($request, $delegate); - } catch (EntityDoesNotExistException $e) { - return $this->buildErrorResponse($request, $delegate); - } catch (PreviewGenerationException $e) { - return $this->buildErrorResponse($request, $delegate); + } catch (InvalidShortCodeException | EntityDoesNotExistException | PreviewGenerationException $e) { + return $this->buildErrorResponse($request, $handler); } } } diff --git a/module/Core/src/Action/QrCodeAction.php b/module/Core/src/Action/QrCodeAction.php index 303636191..3e5aeaf92 100644 --- a/module/Core/src/Action/QrCodeAction.php +++ b/module/Core/src/Action/QrCodeAction.php @@ -4,10 +4,10 @@ namespace Shlinkio\Shlink\Core\Action; use Endroid\QrCode\QrCode; -use Interop\Http\ServerMiddleware\DelegateInterface; -use Interop\Http\ServerMiddleware\MiddlewareInterface; use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; +use Psr\Http\Server\MiddlewareInterface; +use Psr\Http\Server\RequestHandlerInterface; use Psr\Log\LoggerInterface; use Psr\Log\NullLogger; use Shlinkio\Shlink\Common\Response\QrCodeResponse; @@ -49,11 +49,11 @@ public function __construct( * to the next middleware component to create the response. * * @param Request $request - * @param DelegateInterface $delegate + * @param RequestHandlerInterface $handler * * @return Response */ - public function process(Request $request, DelegateInterface $delegate) + public function process(Request $request, RequestHandlerInterface $handler): Response { // Make sure the short URL exists for this short code $shortCode = $request->getAttribute('shortCode'); @@ -61,10 +61,10 @@ public function process(Request $request, DelegateInterface $delegate) $this->urlShortener->shortCodeToUrl($shortCode); } catch (InvalidShortCodeException $e) { $this->logger->warning('Tried to create a QR code with an invalid short code' . PHP_EOL . $e); - return $this->buildErrorResponse($request, $delegate); + return $this->buildErrorResponse($request, $handler); } catch (EntityDoesNotExistException $e) { $this->logger->warning('Tried to create a QR code with a not found short code' . PHP_EOL . $e); - return $this->buildErrorResponse($request, $delegate); + return $this->buildErrorResponse($request, $handler); } $path = $this->router->generateUri('long-url-redirect', ['shortCode' => $shortCode]); @@ -80,7 +80,7 @@ public function process(Request $request, DelegateInterface $delegate) * @param Request $request * @return int */ - protected function getSizeParam(Request $request) + private function getSizeParam(Request $request): int { $size = (int) $request->getAttribute('size', 300); if ($size < 50) { diff --git a/module/Core/src/Action/RedirectAction.php b/module/Core/src/Action/RedirectAction.php index e7702dde8..4654e1fe4 100644 --- a/module/Core/src/Action/RedirectAction.php +++ b/module/Core/src/Action/RedirectAction.php @@ -3,75 +3,15 @@ namespace Shlinkio\Shlink\Core\Action; -use Interop\Http\ServerMiddleware\DelegateInterface; -use Interop\Http\ServerMiddleware\MiddlewareInterface; use Psr\Http\Message\ResponseInterface as Response; -use Psr\Http\Message\ServerRequestInterface as Request; -use Shlinkio\Shlink\Core\Action\Util\ErrorResponseBuilderTrait; -use Shlinkio\Shlink\Core\Exception\EntityDoesNotExistException; -use Shlinkio\Shlink\Core\Exception\InvalidShortCodeException; -use Shlinkio\Shlink\Core\Options\AppOptions; -use Shlinkio\Shlink\Core\Service\UrlShortenerInterface; -use Shlinkio\Shlink\Core\Service\VisitsTrackerInterface; use Zend\Diactoros\Response\RedirectResponse; -class RedirectAction implements MiddlewareInterface +class RedirectAction extends AbstractTrackingAction { - use ErrorResponseBuilderTrait; - - /** - * @var UrlShortenerInterface - */ - private $urlShortener; - /** - * @var VisitsTrackerInterface - */ - private $visitTracker; - /** - * @var AppOptions - */ - private $appOptions; - - public function __construct( - UrlShortenerInterface $urlShortener, - VisitsTrackerInterface $visitTracker, - AppOptions $appOptions - ) { - $this->urlShortener = $urlShortener; - $this->visitTracker = $visitTracker; - $this->appOptions = $appOptions; - } - - /** - * Process an incoming server request and return a response, optionally delegating - * to the next middleware component to create the response. - * - * @param Request $request - * @param DelegateInterface $delegate - * - * @return Response - */ - public function process(Request $request, DelegateInterface $delegate) + protected function createResp(string $longUrl): Response { - $shortCode = $request->getAttribute('shortCode', ''); - $query = $request->getQueryParams(); - $disableTrackParam = $this->appOptions->getDisableTrackParam(); - - try { - $longUrl = $this->urlShortener->shortCodeToUrl($shortCode); - - // Track visit to this short code - if ($disableTrackParam === null || ! \array_key_exists($disableTrackParam, $query)) { - $this->visitTracker->track($shortCode, $request); - } - - // Return a redirect response to the long URL. - // Use a temporary redirect to make sure browsers always hit the server for analytics purposes - return new RedirectResponse($longUrl); - } catch (InvalidShortCodeException $e) { - return $this->buildErrorResponse($request, $delegate); - } catch (EntityDoesNotExistException $e) { - return $this->buildErrorResponse($request, $delegate); - } + // Return a redirect response to the long URL. + // Use a temporary redirect to make sure browsers always hit the server for analytics purposes + return new RedirectResponse($longUrl); } } diff --git a/module/Core/src/Action/Util/ErrorResponseBuilderTrait.php b/module/Core/src/Action/Util/ErrorResponseBuilderTrait.php index 57380b8b3..efd0bc2ad 100644 --- a/module/Core/src/Action/Util/ErrorResponseBuilderTrait.php +++ b/module/Core/src/Action/Util/ErrorResponseBuilderTrait.php @@ -3,16 +3,18 @@ namespace Shlinkio\Shlink\Core\Action\Util; -use Interop\Http\ServerMiddleware\DelegateInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Server\RequestHandlerInterface; use Shlinkio\Shlink\Core\Response\NotFoundDelegate; trait ErrorResponseBuilderTrait { - private function buildErrorResponse(ServerRequestInterface $request, DelegateInterface $delegate): ResponseInterface - { + private function buildErrorResponse( + ServerRequestInterface $request, + RequestHandlerInterface $handler + ): ResponseInterface { $request = $request->withAttribute(NotFoundDelegate::NOT_FOUND_TEMPLATE, 'ShlinkCore::invalid-short-code'); - return $delegate->process($request); + return $handler->handle($request); } } diff --git a/module/Core/src/Entity/Visit.php b/module/Core/src/Entity/Visit.php index 5f67f636d..48edfb11c 100644 --- a/module/Core/src/Entity/Visit.php +++ b/module/Core/src/Entity/Visit.php @@ -57,7 +57,7 @@ public function __construct() /** * @return string */ - public function getReferer() + public function getReferer(): string { return $this->referer; } @@ -66,7 +66,7 @@ public function getReferer() * @param string $referer * @return $this */ - public function setReferer($referer) + public function setReferer($referer): self { $this->referer = $referer; return $this; @@ -75,7 +75,7 @@ public function setReferer($referer) /** * @return \DateTime */ - public function getDate() + public function getDate(): \DateTime { return $this->date; } @@ -84,7 +84,7 @@ public function getDate() * @param \DateTime $date * @return $this */ - public function setDate($date) + public function setDate($date): self { $this->date = $date; return $this; @@ -93,7 +93,7 @@ public function setDate($date) /** * @return ShortUrl */ - public function getShortUrl() + public function getShortUrl(): ShortUrl { return $this->shortUrl; } @@ -102,7 +102,7 @@ public function getShortUrl() * @param ShortUrl $shortUrl * @return $this */ - public function setShortUrl($shortUrl) + public function setShortUrl($shortUrl): self { $this->shortUrl = $shortUrl; return $this; @@ -111,7 +111,7 @@ public function setShortUrl($shortUrl) /** * @return string */ - public function getRemoteAddr() + public function getRemoteAddr(): string { return $this->remoteAddr; } @@ -120,7 +120,7 @@ public function getRemoteAddr() * @param string $remoteAddr * @return $this */ - public function setRemoteAddr($remoteAddr) + public function setRemoteAddr($remoteAddr): self { $this->remoteAddr = $remoteAddr; return $this; @@ -129,7 +129,7 @@ public function setRemoteAddr($remoteAddr) /** * @return string */ - public function getUserAgent() + public function getUserAgent(): string { return $this->userAgent; } @@ -138,7 +138,7 @@ public function getUserAgent() * @param string $userAgent * @return $this */ - public function setUserAgent($userAgent) + public function setUserAgent($userAgent): self { $this->userAgent = $userAgent; return $this; @@ -147,7 +147,7 @@ public function setUserAgent($userAgent) /** * @return VisitLocation */ - public function getVisitLocation() + public function getVisitLocation(): VisitLocation { return $this->visitLocation; } @@ -156,7 +156,7 @@ public function getVisitLocation() * @param VisitLocation $visitLocation * @return $this */ - public function setVisitLocation($visitLocation) + public function setVisitLocation($visitLocation): self { $this->visitLocation = $visitLocation; return $this; @@ -165,11 +165,11 @@ public function setVisitLocation($visitLocation) /** * Specify data which should be serialized to JSON * @link http://php.net/manual/en/jsonserializable.jsonserialize.php - * @return mixed data which can be serialized by json_encode, + * @return array data which can be serialized by json_encode, * which is a value of any type other than a resource. * @since 5.4.0 */ - public function jsonSerialize() + public function jsonSerialize(): array { return [ 'referer' => $this->referer, diff --git a/module/Core/src/Middleware/QrCodeCacheMiddleware.php b/module/Core/src/Middleware/QrCodeCacheMiddleware.php index e91ebd5ea..2f8bafe81 100644 --- a/module/Core/src/Middleware/QrCodeCacheMiddleware.php +++ b/module/Core/src/Middleware/QrCodeCacheMiddleware.php @@ -4,10 +4,10 @@ namespace Shlinkio\Shlink\Core\Middleware; use Doctrine\Common\Cache\Cache; -use Interop\Http\ServerMiddleware\DelegateInterface; -use Interop\Http\ServerMiddleware\MiddlewareInterface; use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; +use Psr\Http\Server\MiddlewareInterface; +use Psr\Http\Server\RequestHandlerInterface; use Zend\Diactoros\Response as DiactResp; class QrCodeCacheMiddleware implements MiddlewareInterface @@ -27,11 +27,11 @@ public function __construct(Cache $cache) * to the next middleware component to create the response. * * @param Request $request - * @param DelegateInterface $delegate + * @param RequestHandlerInterface $handler * * @return Response */ - public function process(Request $request, DelegateInterface $delegate) + public function process(Request $request, RequestHandlerInterface $handler): Response { $cacheKey = $request->getUri()->getPath(); @@ -45,7 +45,7 @@ public function process(Request $request, DelegateInterface $delegate) // If not, call the next middleware and cache it /** @var Response $resp */ - $resp = $delegate->process($request); + $resp = $handler->handle($request); $this->cache->save($cacheKey, [ 'body' => $resp->getBody()->__toString(), 'content-type' => $resp->getHeaderLine('Content-Type'), diff --git a/module/Core/src/Response/NotFoundDelegate.php b/module/Core/src/Response/NotFoundDelegate.php index abe5f06ae..db5ab040f 100644 --- a/module/Core/src/Response/NotFoundDelegate.php +++ b/module/Core/src/Response/NotFoundDelegate.php @@ -4,9 +4,9 @@ namespace Shlinkio\Shlink\Core\Response; use Fig\Http\Message\StatusCodeInterface; -use Interop\Http\ServerMiddleware\DelegateInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Server\RequestHandlerInterface as DelegateInterface; use Zend\Diactoros\Response; use Zend\Expressive\Template\TemplateRendererInterface; @@ -37,14 +37,14 @@ public function __construct(TemplateRendererInterface $renderer, string $default * @return ResponseInterface * @throws \InvalidArgumentException */ - public function process(ServerRequestInterface $request): ResponseInterface + public function handle(ServerRequestInterface $request): ResponseInterface { - $accepts = explode(',', $request->getHeaderLine('Accept')); - $accept = array_shift($accepts); + $accepts = \explode(',', $request->getHeaderLine('Accept')); + $accept = \array_shift($accepts); $status = StatusCodeInterface::STATUS_NOT_FOUND; // If the first accepted type is json, return a json response - if (in_array($accept, ['application/json', 'text/json', 'application/x-json'], true)) { + if (\in_array($accept, ['application/json', 'text/json', 'application/x-json'], true)) { return new Response\JsonResponse([ 'error' => 'NOT_FOUND', 'message' => 'Not found', diff --git a/module/Core/src/Util/TagManagerTrait.php b/module/Core/src/Util/TagManagerTrait.php index 2d1b3d6c0..d93664639 100644 --- a/module/Core/src/Util/TagManagerTrait.php +++ b/module/Core/src/Util/TagManagerTrait.php @@ -14,7 +14,7 @@ trait TagManagerTrait * @param string[] $tags * @return Collections\Collection|Tag[] */ - protected function tagNamesToEntities(EntityManagerInterface $em, array $tags) + private function tagNamesToEntities(EntityManagerInterface $em, array $tags) { $entities = []; foreach ($tags as $tagName) { @@ -33,8 +33,8 @@ protected function tagNamesToEntities(EntityManagerInterface $em, array $tags) * @param string $tagName * @return string */ - protected function normalizeTagName($tagName) + private function normalizeTagName($tagName): string { - return str_replace(' ', '-', strtolower(trim($tagName))); + return \str_replace(' ', '-', \strtolower(\trim($tagName))); } } diff --git a/module/Core/src/Validation/InputFactoryTrait.php b/module/Core/src/Validation/InputFactoryTrait.php index 289c54e2b..4e5146944 100644 --- a/module/Core/src/Validation/InputFactoryTrait.php +++ b/module/Core/src/Validation/InputFactoryTrait.php @@ -9,7 +9,7 @@ trait InputFactoryTrait { - public function createInput($name, $required = true): Input + private function createInput($name, $required = true): Input { $input = new Input($name); $input->setRequired($required) diff --git a/module/Core/test/Action/PixelActionTest.php b/module/Core/test/Action/PixelActionTest.php new file mode 100644 index 000000000..1a7f72967 --- /dev/null +++ b/module/Core/test/Action/PixelActionTest.php @@ -0,0 +1,63 @@ +urlShortener = $this->prophesize(UrlShortener::class); + $this->visitTracker = $this->prophesize(VisitsTracker::class); + + $this->action = new PixelAction( + $this->urlShortener->reveal(), + $this->visitTracker->reveal(), + new AppOptions() + ); + } + + /** + * @test + */ + public function imageIsReturned() + { + $shortCode = 'abc123'; + $this->urlShortener->shortCodeToUrl($shortCode)->willReturn('http://domain.com/foo/bar') + ->shouldBeCalledTimes(1); + $this->visitTracker->track(Argument::cetera())->willReturn(null) + ->shouldBeCalledTimes(1); + + $request = ServerRequestFactory::fromGlobals()->withAttribute('shortCode', $shortCode); + $response = $this->action->process($request, TestUtils::createReqHandlerMock()->reveal()); + + $this->assertInstanceOf(PixelResponse::class, $response); + $this->assertEquals(200, $response->getStatusCode()); + $this->assertEquals('image/gif', $response->getHeaderLine('content-type')); + } +} diff --git a/module/Core/test/Action/PreviewActionTest.php b/module/Core/test/Action/PreviewActionTest.php index 8817eaa4d..abd4dc35d 100644 --- a/module/Core/test/Action/PreviewActionTest.php +++ b/module/Core/test/Action/PreviewActionTest.php @@ -3,11 +3,11 @@ namespace ShlinkioTest\Shlink\Core\Action; -use Interop\Http\ServerMiddleware\DelegateInterface; use PHPUnit\Framework\TestCase; use Prophecy\Argument; use Prophecy\Prophecy\MethodProphecy; use Prophecy\Prophecy\ObjectProphecy; +use Psr\Http\Server\RequestHandlerInterface; use Shlinkio\Shlink\Common\Service\PreviewGenerator; use Shlinkio\Shlink\Core\Action\PreviewAction; use Shlinkio\Shlink\Core\Exception\EntityDoesNotExistException; @@ -47,8 +47,8 @@ public function invalidShortCodeFallsBackToNextMiddleware() $shortCode = 'abc123'; $this->urlShortener->shortCodeToUrl($shortCode)->willThrow(EntityDoesNotExistException::class) ->shouldBeCalledTimes(1); - $delegate = $this->prophesize(DelegateInterface::class); - $delegate->process(Argument::cetera())->shouldBeCalledTimes(1) + $delegate = $this->prophesize(RequestHandlerInterface::class); + $delegate->handle(Argument::cetera())->shouldBeCalledTimes(1) ->willReturn(new Response()); $this->action->process( @@ -70,7 +70,7 @@ public function correctShortCodeReturnsImageResponse() $resp = $this->action->process( ServerRequestFactory::fromGlobals()->withAttribute('shortCode', $shortCode), - TestUtils::createDelegateMock()->reveal() + TestUtils::createReqHandlerMock()->reveal() ); $this->assertEquals(filesize($path), $resp->getHeaderLine('Content-length')); @@ -85,9 +85,9 @@ public function invalidShortCodeExceptionFallsBackToNextMiddleware() $shortCode = 'abc123'; $this->urlShortener->shortCodeToUrl($shortCode)->willThrow(InvalidShortCodeException::class) ->shouldBeCalledTimes(1); - $delegate = $this->prophesize(DelegateInterface::class); + $delegate = $this->prophesize(RequestHandlerInterface::class); /** @var MethodProphecy $process */ - $process = $delegate->process(Argument::any())->willReturn(new Response()); + $process = $delegate->handle(Argument::any())->willReturn(new Response()); $this->action->process( ServerRequestFactory::fromGlobals()->withAttribute('shortCode', $shortCode), diff --git a/module/Core/test/Action/QrCodeActionTest.php b/module/Core/test/Action/QrCodeActionTest.php index c071ef7e9..2d58c8c9b 100644 --- a/module/Core/test/Action/QrCodeActionTest.php +++ b/module/Core/test/Action/QrCodeActionTest.php @@ -3,11 +3,11 @@ namespace ShlinkioTest\Shlink\Core\Action; -use Interop\Http\ServerMiddleware\DelegateInterface; use PHPUnit\Framework\TestCase; use Prophecy\Argument; use Prophecy\Prophecy\MethodProphecy; use Prophecy\Prophecy\ObjectProphecy; +use Psr\Http\Server\RequestHandlerInterface; use Shlinkio\Shlink\Common\Response\QrCodeResponse; use Shlinkio\Shlink\Core\Action\QrCodeAction; use Shlinkio\Shlink\Core\Exception\EntityDoesNotExistException; @@ -46,8 +46,8 @@ public function aNotFoundShortCodeWillDelegateIntoNextMiddleware() $shortCode = 'abc123'; $this->urlShortener->shortCodeToUrl($shortCode)->willThrow(EntityDoesNotExistException::class) ->shouldBeCalledTimes(1); - $delegate = $this->prophesize(DelegateInterface::class); - $process = $delegate->process(Argument::any())->willReturn(new Response()); + $delegate = $this->prophesize(RequestHandlerInterface::class); + $process = $delegate->handle(Argument::any())->willReturn(new Response()); $this->action->process( ServerRequestFactory::fromGlobals()->withAttribute('shortCode', $shortCode), @@ -65,9 +65,9 @@ public function anInvalidShortCodeWillReturnNotFoundResponse() $shortCode = 'abc123'; $this->urlShortener->shortCodeToUrl($shortCode)->willThrow(InvalidShortCodeException::class) ->shouldBeCalledTimes(1); - $delegate = $this->prophesize(DelegateInterface::class); + $delegate = $this->prophesize(RequestHandlerInterface::class); /** @var MethodProphecy $process */ - $process = $delegate->process(Argument::any())->willReturn(new Response()); + $process = $delegate->handle(Argument::any())->willReturn(new Response()); $this->action->process( ServerRequestFactory::fromGlobals()->withAttribute('shortCode', $shortCode), @@ -84,7 +84,7 @@ public function aCorrectRequestReturnsTheQrCodeResponse() { $shortCode = 'abc123'; $this->urlShortener->shortCodeToUrl($shortCode)->willReturn('')->shouldBeCalledTimes(1); - $delegate = $this->prophesize(DelegateInterface::class); + $delegate = $this->prophesize(RequestHandlerInterface::class); $resp = $this->action->process( ServerRequestFactory::fromGlobals()->withAttribute('shortCode', $shortCode), @@ -93,6 +93,6 @@ public function aCorrectRequestReturnsTheQrCodeResponse() $this->assertInstanceOf(QrCodeResponse::class, $resp); $this->assertEquals(200, $resp->getStatusCode()); - $delegate->process(Argument::any())->shouldHaveBeenCalledTimes(0); + $delegate->handle(Argument::any())->shouldHaveBeenCalledTimes(0); } } diff --git a/module/Core/test/Action/RedirectActionTest.php b/module/Core/test/Action/RedirectActionTest.php index ed37baaef..88b44d074 100644 --- a/module/Core/test/Action/RedirectActionTest.php +++ b/module/Core/test/Action/RedirectActionTest.php @@ -3,11 +3,11 @@ namespace ShlinkioTest\Shlink\Core\Action; -use Interop\Http\ServerMiddleware\DelegateInterface; use PHPUnit\Framework\TestCase; use Prophecy\Argument; use Prophecy\Prophecy\MethodProphecy; use Prophecy\Prophecy\ObjectProphecy; +use Psr\Http\Server\RequestHandlerInterface; use Shlinkio\Shlink\Core\Action\RedirectAction; use Shlinkio\Shlink\Core\Exception\EntityDoesNotExistException; use Shlinkio\Shlink\Core\Options\AppOptions; @@ -57,7 +57,7 @@ public function redirectionIsPerformedToLongUrl() ->shouldBeCalledTimes(1); $request = ServerRequestFactory::fromGlobals()->withAttribute('shortCode', $shortCode); - $response = $this->action->process($request, TestUtils::createDelegateMock()->reveal()); + $response = $this->action->process($request, TestUtils::createReqHandlerMock()->reveal()); $this->assertInstanceOf(Response\RedirectResponse::class, $response); $this->assertEquals(302, $response->getStatusCode()); @@ -76,9 +76,9 @@ public function nextMiddlewareIsInvokedIfLongUrlIsNotFound() $this->visitTracker->track(Argument::cetera())->willReturn(null) ->shouldNotBeCalled(); - $delegate = $this->prophesize(DelegateInterface::class); + $delegate = $this->prophesize(RequestHandlerInterface::class); /** @var MethodProphecy $process */ - $process = $delegate->process(Argument::any())->willReturn(new Response()); + $process = $delegate->handle(Argument::any())->willReturn(new Response()); $request = ServerRequestFactory::fromGlobals()->withAttribute('shortCode', $shortCode); $this->action->process($request, $delegate->reveal()); @@ -100,7 +100,7 @@ public function visitIsNotTrackedIfDisableParamIsProvided() $request = ServerRequestFactory::fromGlobals()->withAttribute('shortCode', $shortCode) ->withQueryParams(['foobar' => true]); - $response = $this->action->process($request, TestUtils::createDelegateMock()->reveal()); + $response = $this->action->process($request, TestUtils::createReqHandlerMock()->reveal()); $this->assertInstanceOf(Response\RedirectResponse::class, $response); $this->assertEquals(302, $response->getStatusCode()); diff --git a/module/Core/test/Middleware/QrCodeCacheMiddlewareTest.php b/module/Core/test/Middleware/QrCodeCacheMiddlewareTest.php index 5b173f68d..f566a6bfc 100644 --- a/module/Core/test/Middleware/QrCodeCacheMiddlewareTest.php +++ b/module/Core/test/Middleware/QrCodeCacheMiddlewareTest.php @@ -5,9 +5,9 @@ use Doctrine\Common\Cache\ArrayCache; use Doctrine\Common\Cache\Cache; -use Interop\Http\ServerMiddleware\DelegateInterface; use PHPUnit\Framework\TestCase; use Prophecy\Argument; +use Psr\Http\Server\RequestHandlerInterface; use Shlinkio\Shlink\Core\Middleware\QrCodeCacheMiddleware; use Zend\Diactoros\Response; use Zend\Diactoros\ServerRequestFactory; @@ -35,8 +35,8 @@ public function setUp() */ public function noCachedPathFallsBackToNextMiddleware() { - $delegate = $this->prophesize(DelegateInterface::class); - $delegate->process(Argument::any())->willReturn(new Response())->shouldBeCalledTimes(1); + $delegate = $this->prophesize(RequestHandlerInterface::class); + $delegate->handle(Argument::any())->willReturn(new Response())->shouldBeCalledTimes(1); $this->middleware->process(ServerRequestFactory::fromGlobals()->withUri( new Uri('/foo/bar') @@ -53,7 +53,7 @@ public function cachedPathReturnsCacheContent() $isCalled = false; $uri = (new Uri())->withPath('/foo'); $this->cache->save('/foo', ['body' => 'the body', 'content-type' => 'image/png']); - $delegate = $this->prophesize(DelegateInterface::class); + $delegate = $this->prophesize(RequestHandlerInterface::class); $resp = $this->middleware->process( ServerRequestFactory::fromGlobals()->withUri($uri), @@ -64,6 +64,6 @@ public function cachedPathReturnsCacheContent() $resp->getBody()->rewind(); $this->assertEquals('the body', $resp->getBody()->getContents()); $this->assertEquals('image/png', $resp->getHeaderLine('Content-Type')); - $delegate->process(Argument::any())->shouldHaveBeenCalledTimes(0); + $delegate->handle(Argument::any())->shouldHaveBeenCalledTimes(0); } } diff --git a/module/Core/test/Response/NotFoundDelegateTest.php b/module/Core/test/Response/NotFoundDelegateTest.php index 4f80bf562..b3ce2e66d 100644 --- a/module/Core/test/Response/NotFoundDelegateTest.php +++ b/module/Core/test/Response/NotFoundDelegateTest.php @@ -43,7 +43,7 @@ public function properResponseTypeIsReturned(string $expectedResponse, string $a /** @var MethodProphecy $render */ $render = $this->renderer->render(Argument::cetera())->willReturn(''); - $resp = $this->delegate->process($request); + $resp = $this->delegate->handle($request); $this->assertInstanceOf($expectedResponse, $resp); $render->shouldHaveBeenCalledTimes($renderCalls); diff --git a/module/Rest/src/Action/AbstractRestAction.php b/module/Rest/src/Action/AbstractRestAction.php index 9ba1e6507..a9f491b6f 100644 --- a/module/Rest/src/Action/AbstractRestAction.php +++ b/module/Rest/src/Action/AbstractRestAction.php @@ -5,11 +5,11 @@ use Fig\Http\Message\RequestMethodInterface; use Fig\Http\Message\StatusCodeInterface; -use Interop\Http\ServerMiddleware\MiddlewareInterface; +use Psr\Http\Server\RequestHandlerInterface; use Psr\Log\LoggerInterface; use Psr\Log\NullLogger; -abstract class AbstractRestAction implements MiddlewareInterface, RequestMethodInterface, StatusCodeInterface +abstract class AbstractRestAction implements RequestHandlerInterface, RequestMethodInterface, StatusCodeInterface { /** * @var LoggerInterface diff --git a/module/Rest/src/Action/AuthenticateAction.php b/module/Rest/src/Action/AuthenticateAction.php index f4ac08b0f..22dcee430 100644 --- a/module/Rest/src/Action/AuthenticateAction.php +++ b/module/Rest/src/Action/AuthenticateAction.php @@ -3,7 +3,6 @@ namespace Shlinkio\Shlink\Rest\Action; -use Interop\Http\ServerMiddleware\DelegateInterface; use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Log\LoggerInterface; @@ -43,11 +42,10 @@ public function __construct( /** * @param Request $request - * @param DelegateInterface $delegate - * @return null|Response + * @return Response * @throws \InvalidArgumentException */ - public function process(Request $request, DelegateInterface $delegate) + public function handle(Request $request): Response { $authData = $request->getParsedBody(); if (! isset($authData['apiKey'])) { @@ -61,7 +59,7 @@ public function process(Request $request, DelegateInterface $delegate) // Authenticate using provided API key $apiKey = $this->apiKeyService->getByKey($authData['apiKey']); - if (! isset($apiKey) || ! $apiKey->isValid()) { + if ($apiKey === null || ! $apiKey->isValid()) { return new JsonResponse([ 'error' => RestUtils::INVALID_API_KEY_ERROR, 'message' => $this->translator->translate('Provided API key does not exist or is invalid.'), diff --git a/module/Rest/src/Action/CreateShortcodeAction.php b/module/Rest/src/Action/CreateShortcodeAction.php index 561695924..b3c093d38 100644 --- a/module/Rest/src/Action/CreateShortcodeAction.php +++ b/module/Rest/src/Action/CreateShortcodeAction.php @@ -3,7 +3,6 @@ namespace Shlinkio\Shlink\Rest\Action; -use Interop\Http\ServerMiddleware\DelegateInterface; use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Log\LoggerInterface; @@ -44,11 +43,10 @@ public function __construct( /** * @param Request $request - * @param DelegateInterface $delegate - * @return null|Response + * @return Response * @throws \InvalidArgumentException */ - public function process(Request $request, DelegateInterface $delegate) + public function handle(Request $request): Response { $postData = (array) $request->getParsedBody(); if (! isset($postData['longUrl'])) { diff --git a/module/Rest/src/Action/EditShortCodeAction.php b/module/Rest/src/Action/EditShortCodeAction.php index a8f12de6a..3e9be062f 100644 --- a/module/Rest/src/Action/EditShortCodeAction.php +++ b/module/Rest/src/Action/EditShortCodeAction.php @@ -3,7 +3,6 @@ namespace Shlinkio\Shlink\Rest\Action; -use Interop\Http\ServerMiddleware\DelegateInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Log\LoggerInterface; @@ -41,12 +40,11 @@ public function __construct( * to the next middleware component to create the response. * * @param ServerRequestInterface $request - * @param DelegateInterface $delegate * * @return ResponseInterface * @throws \InvalidArgumentException */ - public function process(ServerRequestInterface $request, DelegateInterface $delegate): ResponseInterface + public function handle(ServerRequestInterface $request): ResponseInterface { $postData = (array) $request->getParsedBody(); $shortCode = $request->getAttribute('shortCode', ''); diff --git a/module/Rest/src/Action/EditShortcodeTagsAction.php b/module/Rest/src/Action/EditShortcodeTagsAction.php index b1aa6492b..c226605af 100644 --- a/module/Rest/src/Action/EditShortcodeTagsAction.php +++ b/module/Rest/src/Action/EditShortcodeTagsAction.php @@ -3,7 +3,6 @@ namespace Shlinkio\Shlink\Rest\Action; -use Interop\Http\ServerMiddleware\DelegateInterface; use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Log\LoggerInterface; @@ -36,11 +35,10 @@ public function __construct( /** * @param Request $request - * @param DelegateInterface $delegate - * @return null|Response + * @return Response * @throws \InvalidArgumentException */ - public function process(Request $request, DelegateInterface $delegate) + public function handle(Request $request): Response { $shortCode = $request->getAttribute('shortCode'); $bodyParams = $request->getParsedBody(); diff --git a/module/Rest/src/Action/GetVisitsAction.php b/module/Rest/src/Action/GetVisitsAction.php index 490b04707..0892da85f 100644 --- a/module/Rest/src/Action/GetVisitsAction.php +++ b/module/Rest/src/Action/GetVisitsAction.php @@ -3,7 +3,6 @@ namespace Shlinkio\Shlink\Rest\Action; -use Interop\Http\ServerMiddleware\DelegateInterface; use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Log\LoggerInterface; @@ -37,11 +36,10 @@ public function __construct( /** * @param Request $request - * @param DelegateInterface $delegate - * @return null|Response + * @return Response * @throws \InvalidArgumentException */ - public function process(Request $request, DelegateInterface $delegate) + public function handle(Request $request): Response { $shortCode = $request->getAttribute('shortCode'); $startDate = $this->getDateQueryParam($request, 'startDate'); diff --git a/module/Rest/src/Action/ListShortcodesAction.php b/module/Rest/src/Action/ListShortcodesAction.php index 83007e295..fe071a287 100644 --- a/module/Rest/src/Action/ListShortcodesAction.php +++ b/module/Rest/src/Action/ListShortcodesAction.php @@ -3,7 +3,6 @@ namespace Shlinkio\Shlink\Rest\Action; -use Interop\Http\ServerMiddleware\DelegateInterface; use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Log\LoggerInterface; @@ -38,11 +37,10 @@ public function __construct( /** * @param Request $request - * @param DelegateInterface $delegate - * @return null|Response + * @return Response * @throws \InvalidArgumentException */ - public function process(Request $request, DelegateInterface $delegate) + public function handle(Request $request): Response { try { $params = $this->queryToListParams($request->getQueryParams()); @@ -61,13 +59,13 @@ public function process(Request $request, DelegateInterface $delegate) * @param array $query * @return array */ - public function queryToListParams(array $query) + private function queryToListParams(array $query): array { return [ - isset($query['page']) ? $query['page'] : 1, - isset($query['searchTerm']) ? $query['searchTerm'] : null, - isset($query['tags']) ? $query['tags'] : [], - isset($query['orderBy']) ? $query['orderBy'] : null, + $query['page'] ?? 1, + $query['searchTerm'] ?? null, + $query['tags'] ?? [], + $query['orderBy'] ?? null, ]; } } diff --git a/module/Rest/src/Action/ResolveUrlAction.php b/module/Rest/src/Action/ResolveUrlAction.php index 1abf56269..54109049f 100644 --- a/module/Rest/src/Action/ResolveUrlAction.php +++ b/module/Rest/src/Action/ResolveUrlAction.php @@ -3,7 +3,6 @@ namespace Shlinkio\Shlink\Rest\Action; -use Interop\Http\ServerMiddleware\DelegateInterface; use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Log\LoggerInterface; @@ -37,11 +36,10 @@ public function __construct( /** * @param Request $request - * @param DelegateInterface $delegate - * @return null|Response + * @return Response * @throws \InvalidArgumentException */ - public function process(Request $request, DelegateInterface $delegate) + public function handle(Request $request): Response { $shortCode = $request->getAttribute('shortCode'); diff --git a/module/Rest/src/Action/Tag/CreateTagsAction.php b/module/Rest/src/Action/Tag/CreateTagsAction.php index da27547c5..6f93b46fe 100644 --- a/module/Rest/src/Action/Tag/CreateTagsAction.php +++ b/module/Rest/src/Action/Tag/CreateTagsAction.php @@ -3,7 +3,6 @@ namespace Shlinkio\Shlink\Rest\Action\Tag; -use Interop\Http\ServerMiddleware\DelegateInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Log\LoggerInterface; @@ -29,15 +28,14 @@ public function __construct(TagServiceInterface $tagService, LoggerInterface $lo * to the next middleware component to create the response. * * @param ServerRequestInterface $request - * @param DelegateInterface $delegate * * @return ResponseInterface * @throws \InvalidArgumentException */ - public function process(ServerRequestInterface $request, DelegateInterface $delegate) + public function handle(ServerRequestInterface $request): ResponseInterface { $body = $request->getParsedBody(); - $tags = isset($body['tags']) ? $body['tags'] : []; + $tags = $body['tags'] ?? []; return new JsonResponse([ 'tags' => [ diff --git a/module/Rest/src/Action/Tag/DeleteTagsAction.php b/module/Rest/src/Action/Tag/DeleteTagsAction.php index ce172cb59..e7ae7b488 100644 --- a/module/Rest/src/Action/Tag/DeleteTagsAction.php +++ b/module/Rest/src/Action/Tag/DeleteTagsAction.php @@ -3,7 +3,6 @@ namespace Shlinkio\Shlink\Rest\Action\Tag; -use Interop\Http\ServerMiddleware\DelegateInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Log\LoggerInterface; @@ -29,14 +28,13 @@ public function __construct(TagServiceInterface $tagService, LoggerInterface $lo * to the next middleware component to create the response. * * @param ServerRequestInterface $request - * @param DelegateInterface $delegate * * @return ResponseInterface */ - public function process(ServerRequestInterface $request, DelegateInterface $delegate) + public function handle(ServerRequestInterface $request): ResponseInterface { $query = $request->getQueryParams(); - $tags = isset($query['tags']) ? $query['tags'] : []; + $tags = $query['tags'] ?? []; $this->tagService->deleteTags($tags); return new EmptyResponse(); diff --git a/module/Rest/src/Action/Tag/ListTagsAction.php b/module/Rest/src/Action/Tag/ListTagsAction.php index c78f4ca45..79c6a79e0 100644 --- a/module/Rest/src/Action/Tag/ListTagsAction.php +++ b/module/Rest/src/Action/Tag/ListTagsAction.php @@ -3,7 +3,6 @@ namespace Shlinkio\Shlink\Rest\Action\Tag; -use Interop\Http\ServerMiddleware\DelegateInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Log\LoggerInterface; @@ -29,12 +28,11 @@ public function __construct(TagServiceInterface $tagService, LoggerInterface $lo * to the next middleware component to create the response. * * @param ServerRequestInterface $request - * @param DelegateInterface $delegate * * @return ResponseInterface * @throws \InvalidArgumentException */ - public function process(ServerRequestInterface $request, DelegateInterface $delegate) + public function handle(ServerRequestInterface $request): ResponseInterface { return new JsonResponse([ 'tags' => [ diff --git a/module/Rest/src/Action/Tag/UpdateTagAction.php b/module/Rest/src/Action/Tag/UpdateTagAction.php index bb8fbbe21..d2e9b8713 100644 --- a/module/Rest/src/Action/Tag/UpdateTagAction.php +++ b/module/Rest/src/Action/Tag/UpdateTagAction.php @@ -3,7 +3,6 @@ namespace Shlinkio\Shlink\Rest\Action\Tag; -use Interop\Http\ServerMiddleware\DelegateInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Log\LoggerInterface; @@ -41,12 +40,11 @@ public function __construct( * to the next middleware component to create the response. * * @param ServerRequestInterface $request - * @param DelegateInterface $delegate * * @return ResponseInterface * @throws \InvalidArgumentException */ - public function process(ServerRequestInterface $request, DelegateInterface $delegate) + public function handle(ServerRequestInterface $request): ResponseInterface { $body = $request->getParsedBody(); if (! isset($body['oldName'], $body['newName'])) { diff --git a/module/Rest/src/Authentication/JWTService.php b/module/Rest/src/Authentication/JWTService.php index 6a0d3ac87..0b4a99492 100644 --- a/module/Rest/src/Authentication/JWTService.php +++ b/module/Rest/src/Authentication/JWTService.php @@ -92,7 +92,7 @@ public function getPayload(string $jwt): array * @param array $data * @return string */ - protected function encode(array $data): string + private function encode(array $data): string { return JWT::encode($data, $this->appOptions->getSecretKey(), self::DEFAULT_ENCRYPTION_ALG); } @@ -101,7 +101,7 @@ protected function encode(array $data): string * @param string $jwt * @return array */ - protected function decode(string $jwt): array + private function decode(string $jwt): array { return (array) JWT::decode($jwt, $this->appOptions->getSecretKey(), [self::DEFAULT_ENCRYPTION_ALG]); } diff --git a/module/Rest/src/Entity/ApiKey.php b/module/Rest/src/Entity/ApiKey.php index 284cc3028..fe475c3aa 100644 --- a/module/Rest/src/Entity/ApiKey.php +++ b/module/Rest/src/Entity/ApiKey.php @@ -44,7 +44,7 @@ public function __construct() /** * @return string */ - public function getKey() + public function getKey(): string { return $this->key; } @@ -53,7 +53,7 @@ public function getKey() * @param string $key * @return $this */ - public function setKey($key) + public function setKey($key): self { $this->key = $key; return $this; @@ -62,7 +62,7 @@ public function setKey($key) /** * @return \DateTime|null */ - public function getExpirationDate() + public function getExpirationDate(): ?\DateTime { return $this->expirationDate; } @@ -71,7 +71,7 @@ public function getExpirationDate() * @param \DateTime $expirationDate * @return $this */ - public function setExpirationDate($expirationDate) + public function setExpirationDate($expirationDate): self { $this->expirationDate = $expirationDate; return $this; @@ -80,9 +80,9 @@ public function setExpirationDate($expirationDate) /** * @return bool */ - public function isExpired() + public function isExpired(): bool { - if (! isset($this->expirationDate)) { + if ($this->expirationDate === null) { return false; } @@ -92,7 +92,7 @@ public function isExpired() /** * @return boolean */ - public function isEnabled() + public function isEnabled(): bool { return $this->enabled; } @@ -101,7 +101,7 @@ public function isEnabled() * @param boolean $enabled * @return $this */ - public function setEnabled($enabled) + public function setEnabled($enabled): self { $this->enabled = $enabled; return $this; @@ -112,7 +112,7 @@ public function setEnabled($enabled) * * @return $this */ - public function disable() + public function disable(): self { return $this->setEnabled(false); } @@ -122,17 +122,17 @@ public function disable() * * @return bool */ - public function isValid() + public function isValid(): bool { return $this->isEnabled() && ! $this->isExpired(); } /** - * The string repesentation of an API key is the key itself + * The string representation of an API key is the key itself * * @return string */ - public function __toString() + public function __toString(): string { return $this->getKey(); } diff --git a/module/Rest/src/ErrorHandler/JsonErrorResponseGenerator.php b/module/Rest/src/ErrorHandler/JsonErrorResponseGenerator.php index 7d0b6013a..035099c8a 100644 --- a/module/Rest/src/ErrorHandler/JsonErrorResponseGenerator.php +++ b/module/Rest/src/ErrorHandler/JsonErrorResponseGenerator.php @@ -20,7 +20,7 @@ class JsonErrorResponseGenerator implements ErrorResponseGeneratorInterface, Sta * @return Response * @throws \InvalidArgumentException */ - public function __invoke($e, Request $request, Response $response) + public function __invoke(?\Throwable $e, Request $request, Response $response) { $status = $response->getStatusCode(); $responsePhrase = $status < 400 ? 'Internal Server Error' : $response->getReasonPhrase(); @@ -32,8 +32,8 @@ public function __invoke($e, Request $request, Response $response) ], $status); } - protected function responsePhraseToCode(string $responsePhrase): string + private function responsePhraseToCode(string $responsePhrase): string { - return strtoupper(str_replace(' ', '_', $responsePhrase)); + return \strtoupper(\str_replace(' ', '_', $responsePhrase)); } } diff --git a/module/Rest/src/Middleware/BodyParserMiddleware.php b/module/Rest/src/Middleware/BodyParserMiddleware.php index 69929af45..1bbc26ea7 100644 --- a/module/Rest/src/Middleware/BodyParserMiddleware.php +++ b/module/Rest/src/Middleware/BodyParserMiddleware.php @@ -4,10 +4,10 @@ namespace Shlinkio\Shlink\Rest\Middleware; use Fig\Http\Message\RequestMethodInterface; -use Interop\Http\ServerMiddleware\DelegateInterface; -use Interop\Http\ServerMiddleware\MiddlewareInterface; use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; +use Psr\Http\Server\MiddlewareInterface; +use Psr\Http\Server\RequestHandlerInterface; use Shlinkio\Shlink\Rest\Exception\RuntimeException; class BodyParserMiddleware implements MiddlewareInterface, RequestMethodInterface @@ -17,11 +17,11 @@ class BodyParserMiddleware implements MiddlewareInterface, RequestMethodInterfac * to the next middleware component to create the response. * * @param Request $request - * @param DelegateInterface $delegate + * @param RequestHandlerInterface $handler * * @return Response */ - public function process(Request $request, DelegateInterface $delegate) + public function process(Request $request, RequestHandlerInterface $handler): Response { $method = $request->getMethod(); $currentParams = $request->getParsedBody(); @@ -32,16 +32,16 @@ public function process(Request $request, DelegateInterface $delegate) self::METHOD_HEAD, self::METHOD_OPTIONS, ], true)) { - return $delegate->process($request); + return $handler->handle($request); } // If the accepted content is JSON, try to parse the body from JSON $contentType = $this->getRequestContentType($request); if (\in_array($contentType, ['application/json', 'text/json', 'application/x-json'], true)) { - return $delegate->process($this->parseFromJson($request)); + return $handler->handle($this->parseFromJson($request)); } - return $delegate->process($this->parseFromUrlEncoded($request)); + return $handler->handle($this->parseFromUrlEncoded($request)); } /** diff --git a/module/Rest/src/Middleware/CheckAuthenticationMiddleware.php b/module/Rest/src/Middleware/CheckAuthenticationMiddleware.php index 071eadba1..32e10ed87 100644 --- a/module/Rest/src/Middleware/CheckAuthenticationMiddleware.php +++ b/module/Rest/src/Middleware/CheckAuthenticationMiddleware.php @@ -4,10 +4,10 @@ namespace Shlinkio\Shlink\Rest\Middleware; use Fig\Http\Message\StatusCodeInterface; -use Interop\Http\ServerMiddleware\DelegateInterface; -use Interop\Http\ServerMiddleware\MiddlewareInterface; use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; +use Psr\Http\Server\MiddlewareInterface; +use Psr\Http\Server\RequestHandlerInterface; use Psr\Log\LoggerInterface; use Psr\Log\NullLogger; use Shlinkio\Shlink\Rest\Action\AuthenticateAction; @@ -21,7 +21,7 @@ class CheckAuthenticationMiddleware implements MiddlewareInterface, StatusCodeInterface { - const AUTHORIZATION_HEADER = 'Authorization'; + public const AUTHORIZATION_HEADER = 'Authorization'; /** * @var TranslatorInterface @@ -51,13 +51,13 @@ public function __construct( * to the next middleware component to create the response. * * @param Request $request - * @param DelegateInterface $delegate + * @param RequestHandlerInterface $handler * * @return Response * @throws \InvalidArgumentException * @throws \ErrorException */ - public function process(Request $request, DelegateInterface $delegate) + public function process(Request $request, RequestHandlerInterface $handler): Response { // If current route is the authenticate route or an OPTIONS request, continue to the next middleware /** @var RouteResult|null $routeResult */ @@ -67,7 +67,7 @@ public function process(Request $request, DelegateInterface $delegate) || $routeResult->getMatchedRouteName() === AuthenticateAction::class || $request->getMethod() === 'OPTIONS' ) { - return $delegate->process($request); + return $handler->handle($request); } // Check that the auth header was provided, and that it belongs to a non-expired token @@ -77,22 +77,22 @@ public function process(Request $request, DelegateInterface $delegate) // Get token making sure the an authorization type is provided $authToken = $request->getHeaderLine(self::AUTHORIZATION_HEADER); - $authTokenParts = explode(' ', $authToken); - if (count($authTokenParts) === 1) { + $authTokenParts = \explode(' ', $authToken); + if (\count($authTokenParts) === 1) { return new JsonResponse([ 'error' => RestUtils::INVALID_AUTHORIZATION_ERROR, - 'message' => sprintf($this->translator->translate( + 'message' => \sprintf($this->translator->translate( 'You need to provide the Bearer type in the %s header.' ), self::AUTHORIZATION_HEADER), ], self::STATUS_UNAUTHORIZED); } // Make sure the authorization type is Bearer - list($authType, $jwt) = $authTokenParts; - if (strtolower($authType) !== 'bearer') { + [$authType, $jwt] = $authTokenParts; + if (\strtolower($authType) !== 'bearer') { return new JsonResponse([ 'error' => RestUtils::INVALID_AUTHORIZATION_ERROR, - 'message' => sprintf($this->translator->translate( + 'message' => \sprintf($this->translator->translate( 'Provided authorization type %s is not supported. Use Bearer instead.' ), $authType), ], self::STATUS_UNAUTHORIZED); @@ -107,7 +107,7 @@ public function process(Request $request, DelegateInterface $delegate) // Update the token expiration and continue to next middleware $jwt = $this->jwtService->refresh($jwt); - $response = $delegate->process($request); + $response = $handler->handle($request); // Return the response with the updated token on it return $response->withHeader(self::AUTHORIZATION_HEADER, 'Bearer ' . $jwt); @@ -119,11 +119,15 @@ public function process(Request $request, DelegateInterface $delegate) } } - protected function createTokenErrorResponse() + /** + * @return JsonResponse + * @throws \InvalidArgumentException + */ + private function createTokenErrorResponse(): JsonResponse { return new JsonResponse([ 'error' => RestUtils::INVALID_AUTH_TOKEN_ERROR, - 'message' => sprintf( + 'message' => \sprintf( $this->translator->translate( 'Missing or invalid auth token provided. Perform a new authentication request and send provided ' . 'token on every new request on the "%s" header' diff --git a/module/Rest/src/Middleware/CrossDomainMiddleware.php b/module/Rest/src/Middleware/CrossDomainMiddleware.php index 9237c743d..dc4bf9d69 100644 --- a/module/Rest/src/Middleware/CrossDomainMiddleware.php +++ b/module/Rest/src/Middleware/CrossDomainMiddleware.php @@ -4,10 +4,10 @@ namespace Shlinkio\Shlink\Rest\Middleware; use Fig\Http\Message\RequestMethodInterface; -use Interop\Http\ServerMiddleware\DelegateInterface; -use Interop\Http\ServerMiddleware\MiddlewareInterface; use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; +use Psr\Http\Server\MiddlewareInterface; +use Psr\Http\Server\RequestHandlerInterface; class CrossDomainMiddleware implements MiddlewareInterface, RequestMethodInterface { @@ -16,15 +16,15 @@ class CrossDomainMiddleware implements MiddlewareInterface, RequestMethodInterfa * to the next middleware component to create the response. * * @param Request $request - * @param DelegateInterface $delegate + * @param RequestHandlerInterface $handler * * @return Response * @throws \InvalidArgumentException */ - public function process(Request $request, DelegateInterface $delegate) + public function process(Request $request, RequestHandlerInterface $handler): Response { /** @var Response $response */ - $response = $delegate->process($request); + $response = $handler->handle($request); if (! $request->hasHeader('Origin')) { return $response; } diff --git a/module/Rest/src/Middleware/PathVersionMiddleware.php b/module/Rest/src/Middleware/PathVersionMiddleware.php index 18cfc3949..f8fc01137 100644 --- a/module/Rest/src/Middleware/PathVersionMiddleware.php +++ b/module/Rest/src/Middleware/PathVersionMiddleware.php @@ -3,10 +3,10 @@ namespace Shlinkio\Shlink\Rest\Middleware; -use Interop\Http\ServerMiddleware\DelegateInterface; -use Interop\Http\ServerMiddleware\MiddlewareInterface; use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; +use Psr\Http\Server\MiddlewareInterface; +use Psr\Http\Server\RequestHandlerInterface; class PathVersionMiddleware implements MiddlewareInterface { @@ -15,18 +15,18 @@ class PathVersionMiddleware implements MiddlewareInterface * to the next middleware component to create the response. * * @param Request $request - * @param DelegateInterface $delegate + * @param RequestHandlerInterface $handler * * @return Response */ - public function process(Request $request, DelegateInterface $delegate) + public function process(Request $request, RequestHandlerInterface $handler): Response { $uri = $request->getUri(); $path = $uri->getPath(); // TODO Workaround... Do not process the request if it does not start with rest if (\strpos($path, '/rest') !== 0) { - return $delegate->process($request); + return $handler->handle($request); } // If the path does not begin with the version number, prepend v1 by default for BC compatibility purposes @@ -41,6 +41,6 @@ public function process(Request $request, DelegateInterface $delegate) $request = $request->withUri($uri->withPath(\implode('/', $parts))); } - return $delegate->process($request); + return $handler->handle($request); } } diff --git a/module/Rest/src/Util/RestUtils.php b/module/Rest/src/Util/RestUtils.php index b9d968910..1d6976761 100644 --- a/module/Rest/src/Util/RestUtils.php +++ b/module/Rest/src/Util/RestUtils.php @@ -9,16 +9,16 @@ class RestUtils { - const INVALID_SHORTCODE_ERROR = 'INVALID_SHORTCODE'; - const INVALID_URL_ERROR = 'INVALID_URL'; - const INVALID_ARGUMENT_ERROR = 'INVALID_ARGUMENT'; - const INVALID_SLUG_ERROR = 'INVALID_SLUG'; - const INVALID_CREDENTIALS_ERROR = 'INVALID_CREDENTIALS'; - const INVALID_AUTH_TOKEN_ERROR = 'INVALID_AUTH_TOKEN'; - const INVALID_AUTHORIZATION_ERROR = 'INVALID_AUTHORIZATION'; - const INVALID_API_KEY_ERROR = 'INVALID_API_KEY'; - const NOT_FOUND_ERROR = 'NOT_FOUND'; - const UNKNOWN_ERROR = 'UNKNOWN_ERROR'; + public const INVALID_SHORTCODE_ERROR = 'INVALID_SHORTCODE'; + public const INVALID_URL_ERROR = 'INVALID_URL'; + public const INVALID_ARGUMENT_ERROR = 'INVALID_ARGUMENT'; + public const INVALID_SLUG_ERROR = 'INVALID_SLUG'; + public const INVALID_CREDENTIALS_ERROR = 'INVALID_CREDENTIALS'; + public const INVALID_AUTH_TOKEN_ERROR = 'INVALID_AUTH_TOKEN'; + public const INVALID_AUTHORIZATION_ERROR = 'INVALID_AUTHORIZATION'; + public const INVALID_API_KEY_ERROR = 'INVALID_API_KEY'; + public const NOT_FOUND_ERROR = 'NOT_FOUND'; + public const UNKNOWN_ERROR = 'UNKNOWN_ERROR'; public static function getRestErrorCodeFromException(\Throwable $e) { diff --git a/module/Rest/test/Action/AuthenticateActionTest.php b/module/Rest/test/Action/AuthenticateActionTest.php index 4fb2518f0..4825a1006 100644 --- a/module/Rest/test/Action/AuthenticateActionTest.php +++ b/module/Rest/test/Action/AuthenticateActionTest.php @@ -10,7 +10,6 @@ use Shlinkio\Shlink\Rest\Authentication\JWTService; use Shlinkio\Shlink\Rest\Entity\ApiKey; use Shlinkio\Shlink\Rest\Service\ApiKeyService; -use ShlinkioTest\Shlink\Common\Util\TestUtils; use Zend\Diactoros\ServerRequestFactory; use Zend\I18n\Translator\Translator; @@ -47,7 +46,7 @@ public function setUp() */ public function notProvidingAuthDataReturnsError() { - $resp = $this->action->process(ServerRequestFactory::fromGlobals(), TestUtils::createDelegateMock()->reveal()); + $resp = $this->action->handle(ServerRequestFactory::fromGlobals()); $this->assertEquals(400, $resp->getStatusCode()); } @@ -62,7 +61,7 @@ public function properApiKeyReturnsTokenInResponse() $request = ServerRequestFactory::fromGlobals()->withParsedBody([ 'apiKey' => 'foo', ]); - $response = $this->action->process($request, TestUtils::createDelegateMock()->reveal()); + $response = $this->action->handle($request); $this->assertEquals(200, $response->getStatusCode()); $response->getBody()->rewind(); @@ -80,7 +79,7 @@ public function invalidApiKeyReturnsErrorResponse() $request = ServerRequestFactory::fromGlobals()->withParsedBody([ 'apiKey' => 'foo', ]); - $response = $this->action->process($request, TestUtils::createDelegateMock()->reveal()); + $response = $this->action->handle($request); $this->assertEquals(401, $response->getStatusCode()); } } diff --git a/module/Rest/test/Action/CreateShortcodeActionTest.php b/module/Rest/test/Action/CreateShortcodeActionTest.php index 2c92f0304..c9d8ff194 100644 --- a/module/Rest/test/Action/CreateShortcodeActionTest.php +++ b/module/Rest/test/Action/CreateShortcodeActionTest.php @@ -11,7 +11,6 @@ use Shlinkio\Shlink\Core\Service\UrlShortener; use Shlinkio\Shlink\Rest\Action\CreateShortcodeAction; use Shlinkio\Shlink\Rest\Util\RestUtils; -use ShlinkioTest\Shlink\Common\Util\TestUtils; use Zend\Diactoros\ServerRequestFactory; use Zend\Diactoros\Uri; use Zend\I18n\Translator\Translator; @@ -41,10 +40,7 @@ public function setUp() */ public function missingLongUrlParamReturnsError() { - $response = $this->action->process( - ServerRequestFactory::fromGlobals(), - TestUtils::createDelegateMock()->reveal() - ); + $response = $this->action->handle(ServerRequestFactory::fromGlobals()); $this->assertEquals(400, $response->getStatusCode()); } @@ -60,7 +56,7 @@ public function properShortcodeConversionReturnsData() $request = ServerRequestFactory::fromGlobals()->withParsedBody([ 'longUrl' => 'http://www.domain.com/foo/bar', ]); - $response = $this->action->process($request, TestUtils::createDelegateMock()->reveal()); + $response = $this->action->handle($request); $this->assertEquals(200, $response->getStatusCode()); $this->assertTrue(strpos($response->getBody()->getContents(), 'http://foo.com/abc123') > 0); } @@ -77,7 +73,7 @@ public function anInvalidUrlReturnsError() $request = ServerRequestFactory::fromGlobals()->withParsedBody([ 'longUrl' => 'http://www.domain.com/foo/bar', ]); - $response = $this->action->process($request, TestUtils::createDelegateMock()->reveal()); + $response = $this->action->handle($request); $this->assertEquals(400, $response->getStatusCode()); $this->assertTrue(strpos($response->getBody()->getContents(), RestUtils::INVALID_URL_ERROR) > 0); } @@ -100,7 +96,7 @@ public function nonUniqueSlugReturnsError() 'longUrl' => 'http://www.domain.com/foo/bar', 'customSlug' => 'foo', ]); - $response = $this->action->process($request, TestUtils::createDelegateMock()->reveal()); + $response = $this->action->handle($request); $this->assertEquals(400, $response->getStatusCode()); $this->assertContains(RestUtils::INVALID_SLUG_ERROR, (string) $response->getBody()); } @@ -117,7 +113,7 @@ public function aGenericExceptionWillReturnError() $request = ServerRequestFactory::fromGlobals()->withParsedBody([ 'longUrl' => 'http://www.domain.com/foo/bar', ]); - $response = $this->action->process($request, TestUtils::createDelegateMock()->reveal()); + $response = $this->action->handle($request); $this->assertEquals(500, $response->getStatusCode()); $this->assertTrue(strpos($response->getBody()->getContents(), RestUtils::UNKNOWN_ERROR) > 0); } diff --git a/module/Rest/test/Action/EditShortCodeActionTest.php b/module/Rest/test/Action/EditShortCodeActionTest.php index 2690811ab..5a4e6b2f0 100644 --- a/module/Rest/test/Action/EditShortCodeActionTest.php +++ b/module/Rest/test/Action/EditShortCodeActionTest.php @@ -3,7 +3,6 @@ namespace ShlinkioTest\Shlink\Rest\Action; -use Interop\Http\ServerMiddleware\DelegateInterface; use PHPUnit\Framework\TestCase; use Prophecy\Argument; use Prophecy\Prophecy\ObjectProphecy; @@ -43,7 +42,7 @@ public function invalidDataReturnsError() ]); /** @var JsonResponse $resp */ - $resp = $this->action->process($request, $this->prophesize(DelegateInterface::class)->reveal()); + $resp = $this->action->handle($request); $payload = $resp->getPayload(); $this->assertEquals(400, $resp->getStatusCode()); @@ -65,7 +64,7 @@ public function incorrectShortCodeReturnsError() ); /** @var JsonResponse $resp */ - $resp = $this->action->process($request, $this->prophesize(DelegateInterface::class)->reveal()); + $resp = $this->action->handle($request); $payload = $resp->getPayload(); $this->assertEquals(404, $resp->getStatusCode()); @@ -85,7 +84,7 @@ public function correctShortCodeReturnsSuccess() ]); $updateMeta = $this->shortUrlService->updateMetadataByShortCode(Argument::cetera())->willReturn(new ShortUrl()); - $resp = $this->action->process($request, $this->prophesize(DelegateInterface::class)->reveal()); + $resp = $this->action->handle($request); $this->assertEquals(204, $resp->getStatusCode()); $updateMeta->shouldHaveBeenCalled(); diff --git a/module/Rest/test/Action/EditShortcodeTagsActionTest.php b/module/Rest/test/Action/EditShortcodeTagsActionTest.php index f90c73f09..a2bcfb383 100644 --- a/module/Rest/test/Action/EditShortcodeTagsActionTest.php +++ b/module/Rest/test/Action/EditShortcodeTagsActionTest.php @@ -9,7 +9,6 @@ use Shlinkio\Shlink\Core\Exception\InvalidShortCodeException; use Shlinkio\Shlink\Core\Service\ShortUrlService; use Shlinkio\Shlink\Rest\Action\EditShortcodeTagsAction; -use ShlinkioTest\Shlink\Common\Util\TestUtils; use Zend\Diactoros\ServerRequestFactory; use Zend\I18n\Translator\Translator; @@ -35,10 +34,7 @@ public function setUp() */ public function notProvidingTagsReturnsError() { - $response = $this->action->process( - ServerRequestFactory::fromGlobals()->withAttribute('shortCode', 'abc123'), - TestUtils::createDelegateMock()->reveal() - ); + $response = $this->action->handle(ServerRequestFactory::fromGlobals()->withAttribute('shortCode', 'abc123')); $this->assertEquals(400, $response->getStatusCode()); } @@ -51,10 +47,9 @@ public function anInvalidShortCodeReturnsNotFound() $this->shortUrlService->setTagsByShortCode($shortCode, [])->willThrow(InvalidShortCodeException::class) ->shouldBeCalledTimes(1); - $response = $this->action->process( + $response = $this->action->handle( ServerRequestFactory::fromGlobals()->withAttribute('shortCode', 'abc123') - ->withParsedBody(['tags' => []]), - TestUtils::createDelegateMock()->reveal() + ->withParsedBody(['tags' => []]) ); $this->assertEquals(404, $response->getStatusCode()); } @@ -68,10 +63,9 @@ public function tagsListIsReturnedIfCorrectShortCodeIsProvided() $this->shortUrlService->setTagsByShortCode($shortCode, [])->willReturn(new ShortUrl()) ->shouldBeCalledTimes(1); - $response = $this->action->process( + $response = $this->action->handle( ServerRequestFactory::fromGlobals()->withAttribute('shortCode', 'abc123') - ->withParsedBody(['tags' => []]), - TestUtils::createDelegateMock()->reveal() + ->withParsedBody(['tags' => []]) ); $this->assertEquals(200, $response->getStatusCode()); } diff --git a/module/Rest/test/Action/GetVisitsActionTest.php b/module/Rest/test/Action/GetVisitsActionTest.php index eb892e74d..1ac988ba5 100644 --- a/module/Rest/test/Action/GetVisitsActionTest.php +++ b/module/Rest/test/Action/GetVisitsActionTest.php @@ -10,7 +10,6 @@ use Shlinkio\Shlink\Common\Util\DateRange; use Shlinkio\Shlink\Core\Service\VisitsTracker; use Shlinkio\Shlink\Rest\Action\GetVisitsAction; -use ShlinkioTest\Shlink\Common\Util\TestUtils; use Zend\Diactoros\ServerRequestFactory; use Zend\I18n\Translator\Translator; @@ -40,10 +39,7 @@ public function providingCorrectShortCodeReturnsVisits() $this->visitsTracker->info($shortCode, Argument::type(DateRange::class))->willReturn([]) ->shouldBeCalledTimes(1); - $response = $this->action->process( - ServerRequestFactory::fromGlobals()->withAttribute('shortCode', $shortCode), - TestUtils::createDelegateMock()->reveal() - ); + $response = $this->action->handle(ServerRequestFactory::fromGlobals()->withAttribute('shortCode', $shortCode)); $this->assertEquals(200, $response->getStatusCode()); } @@ -57,10 +53,7 @@ public function providingInvalidShortCodeReturnsError() InvalidArgumentException::class )->shouldBeCalledTimes(1); - $response = $this->action->process( - ServerRequestFactory::fromGlobals()->withAttribute('shortCode', $shortCode), - TestUtils::createDelegateMock()->reveal() - ); + $response = $this->action->handle(ServerRequestFactory::fromGlobals()->withAttribute('shortCode', $shortCode)); $this->assertEquals(404, $response->getStatusCode()); } @@ -74,10 +67,7 @@ public function unexpectedExceptionWillReturnError() \Exception::class )->shouldBeCalledTimes(1); - $response = $this->action->process( - ServerRequestFactory::fromGlobals()->withAttribute('shortCode', $shortCode), - TestUtils::createDelegateMock()->reveal() - ); + $response = $this->action->handle(ServerRequestFactory::fromGlobals()->withAttribute('shortCode', $shortCode)); $this->assertEquals(500, $response->getStatusCode()); } @@ -91,10 +81,9 @@ public function datesAreReadFromQuery() ->willReturn([]) ->shouldBeCalledTimes(1); - $response = $this->action->process( + $response = $this->action->handle( ServerRequestFactory::fromGlobals()->withAttribute('shortCode', $shortCode) - ->withQueryParams(['endDate' => '2016-01-01 00:00:00']), - TestUtils::createDelegateMock()->reveal() + ->withQueryParams(['endDate' => '2016-01-01 00:00:00']) ); $this->assertEquals(200, $response->getStatusCode()); } diff --git a/module/Rest/test/Action/ListShortcodesActionTest.php b/module/Rest/test/Action/ListShortCodesActionTest.php similarity index 75% rename from module/Rest/test/Action/ListShortcodesActionTest.php rename to module/Rest/test/Action/ListShortCodesActionTest.php index 1867d15a3..85e6737aa 100644 --- a/module/Rest/test/Action/ListShortcodesActionTest.php +++ b/module/Rest/test/Action/ListShortCodesActionTest.php @@ -7,7 +7,6 @@ use Prophecy\Prophecy\ObjectProphecy; use Shlinkio\Shlink\Core\Service\ShortUrlService; use Shlinkio\Shlink\Rest\Action\ListShortcodesAction; -use ShlinkioTest\Shlink\Common\Util\TestUtils; use Zend\Diactoros\ServerRequestFactory; use Zend\I18n\Translator\Translator; use Zend\Paginator\Adapter\ArrayAdapter; @@ -39,12 +38,9 @@ public function properListReturnsSuccessResponse() $this->service->listShortUrls($page, null, [], null)->willReturn(new Paginator(new ArrayAdapter())) ->shouldBeCalledTimes(1); - $response = $this->action->process( - ServerRequestFactory::fromGlobals()->withQueryParams([ - 'page' => $page, - ]), - TestUtils::createDelegateMock()->reveal() - ); + $response = $this->action->handle(ServerRequestFactory::fromGlobals()->withQueryParams([ + 'page' => $page, + ])); $this->assertEquals(200, $response->getStatusCode()); } @@ -57,12 +53,9 @@ public function anExceptionsReturnsErrorResponse() $this->service->listShortUrls($page, null, [], null)->willThrow(\Exception::class) ->shouldBeCalledTimes(1); - $response = $this->action->process( - ServerRequestFactory::fromGlobals()->withQueryParams([ - 'page' => $page, - ]), - TestUtils::createDelegateMock()->reveal() - ); + $response = $this->action->handle(ServerRequestFactory::fromGlobals()->withQueryParams([ + 'page' => $page, + ])); $this->assertEquals(500, $response->getStatusCode()); } } diff --git a/module/Rest/test/Action/ResolveUrlActionTest.php b/module/Rest/test/Action/ResolveUrlActionTest.php index 884fae55d..feafc4254 100644 --- a/module/Rest/test/Action/ResolveUrlActionTest.php +++ b/module/Rest/test/Action/ResolveUrlActionTest.php @@ -10,7 +10,6 @@ use Shlinkio\Shlink\Core\Service\UrlShortener; use Shlinkio\Shlink\Rest\Action\ResolveUrlAction; use Shlinkio\Shlink\Rest\Util\RestUtils; -use ShlinkioTest\Shlink\Common\Util\TestUtils; use Zend\Diactoros\ServerRequestFactory; use Zend\I18n\Translator\Translator; @@ -41,7 +40,7 @@ public function incorrectShortCodeReturnsError() ->shouldBeCalledTimes(1); $request = ServerRequestFactory::fromGlobals()->withAttribute('shortCode', $shortCode); - $response = $this->action->process($request, TestUtils::createDelegateMock()->reveal()); + $response = $this->action->handle($request); $this->assertEquals(404, $response->getStatusCode()); $this->assertTrue(strpos($response->getBody()->getContents(), RestUtils::INVALID_ARGUMENT_ERROR) > 0); } @@ -56,7 +55,7 @@ public function correctShortCodeReturnsSuccess() ->shouldBeCalledTimes(1); $request = ServerRequestFactory::fromGlobals()->withAttribute('shortCode', $shortCode); - $response = $this->action->process($request, TestUtils::createDelegateMock()->reveal()); + $response = $this->action->handle($request); $this->assertEquals(200, $response->getStatusCode()); $this->assertTrue(strpos($response->getBody()->getContents(), 'http://domain.com/foo/bar') > 0); } @@ -71,7 +70,7 @@ public function invalidShortCodeExceptionReturnsError() ->shouldBeCalledTimes(1); $request = ServerRequestFactory::fromGlobals()->withAttribute('shortCode', $shortCode); - $response = $this->action->process($request, TestUtils::createDelegateMock()->reveal()); + $response = $this->action->handle($request); $this->assertEquals(400, $response->getStatusCode()); $this->assertTrue(strpos($response->getBody()->getContents(), RestUtils::INVALID_SHORTCODE_ERROR) > 0); } @@ -86,7 +85,7 @@ public function unexpectedExceptionWillReturnError() ->shouldBeCalledTimes(1); $request = ServerRequestFactory::fromGlobals()->withAttribute('shortCode', $shortCode); - $response = $this->action->process($request, TestUtils::createDelegateMock()->reveal()); + $response = $this->action->handle($request); $this->assertEquals(500, $response->getStatusCode()); $this->assertTrue(strpos($response->getBody()->getContents(), RestUtils::UNKNOWN_ERROR) > 0); } diff --git a/module/Rest/test/Action/Tag/CreateTagsActionTest.php b/module/Rest/test/Action/Tag/CreateTagsActionTest.php index 795827fa5..e94a0ea87 100644 --- a/module/Rest/test/Action/Tag/CreateTagsActionTest.php +++ b/module/Rest/test/Action/Tag/CreateTagsActionTest.php @@ -4,7 +4,6 @@ namespace ShlinkioTest\Shlink\Rest\Action\Tag; use Doctrine\Common\Collections\ArrayCollection; -use Interop\Http\ServerMiddleware\DelegateInterface; use PHPUnit\Framework\TestCase; use Prophecy\Prophecy\MethodProphecy; use Prophecy\Prophecy\ObjectProphecy; @@ -40,7 +39,7 @@ public function processDelegatesIntoService($tags) /** @var MethodProphecy $deleteTags */ $deleteTags = $this->tagService->createTags($tags ?: [])->willReturn(new ArrayCollection()); - $response = $this->action->process($request, $this->prophesize(DelegateInterface::class)->reveal()); + $response = $this->action->handle($request); $this->assertEquals(200, $response->getStatusCode()); $deleteTags->shouldHaveBeenCalled(); diff --git a/module/Rest/test/Action/Tag/DeleteTagsActionTest.php b/module/Rest/test/Action/Tag/DeleteTagsActionTest.php index 0a0657bf2..fc376576d 100644 --- a/module/Rest/test/Action/Tag/DeleteTagsActionTest.php +++ b/module/Rest/test/Action/Tag/DeleteTagsActionTest.php @@ -3,7 +3,6 @@ namespace ShlinkioTest\Shlink\Rest\Action\Tag; -use Interop\Http\ServerMiddleware\DelegateInterface; use PHPUnit\Framework\TestCase; use Prophecy\Prophecy\MethodProphecy; use Prophecy\Prophecy\ObjectProphecy; @@ -39,7 +38,7 @@ public function processDelegatesIntoService($tags) /** @var MethodProphecy $deleteTags */ $deleteTags = $this->tagService->deleteTags($tags ?: []); - $response = $this->action->process($request, $this->prophesize(DelegateInterface::class)->reveal()); + $response = $this->action->handle($request); $this->assertEquals(204, $response->getStatusCode()); $deleteTags->shouldHaveBeenCalled(); diff --git a/module/Rest/test/Action/Tag/ListTagsActionTest.php b/module/Rest/test/Action/Tag/ListTagsActionTest.php index 67e395b11..7fb73404e 100644 --- a/module/Rest/test/Action/Tag/ListTagsActionTest.php +++ b/module/Rest/test/Action/Tag/ListTagsActionTest.php @@ -3,7 +3,6 @@ namespace ShlinkioTest\Shlink\Rest\Action\Tag; -use Interop\Http\ServerMiddleware\DelegateInterface; use PHPUnit\Framework\TestCase; use Prophecy\Prophecy\MethodProphecy; use Prophecy\Prophecy\ObjectProphecy; @@ -37,10 +36,7 @@ public function returnsDataFromService() /** @var MethodProphecy $listTags */ $listTags = $this->tagService->listTags()->willReturn([new Tag('foo'), new Tag('bar')]); - $resp = $this->action->process( - ServerRequestFactory::fromGlobals(), - $this->prophesize(DelegateInterface::class)->reveal() - ); + $resp = $this->action->handle(ServerRequestFactory::fromGlobals()); $this->assertEquals([ 'tags' => [ diff --git a/module/Rest/test/Action/Tag/UpdateTagActionTest.php b/module/Rest/test/Action/Tag/UpdateTagActionTest.php index fbbd7c609..c073f2706 100644 --- a/module/Rest/test/Action/Tag/UpdateTagActionTest.php +++ b/module/Rest/test/Action/Tag/UpdateTagActionTest.php @@ -3,7 +3,6 @@ namespace ShlinkioTest\Shlink\Rest\Action\Tag; -use Interop\Http\ServerMiddleware\DelegateInterface; use PHPUnit\Framework\TestCase; use Prophecy\Prophecy\MethodProphecy; use Prophecy\Prophecy\ObjectProphecy; @@ -39,7 +38,7 @@ public function setUp() public function whenInvalidParamsAreProvidedAnErrorIsReturned(array $bodyParams) { $request = ServerRequestFactory::fromGlobals()->withParsedBody($bodyParams); - $resp = $this->action->process($request, $this->prophesize(DelegateInterface::class)->reveal()); + $resp = $this->action->handle($request); $this->assertEquals(400, $resp->getStatusCode()); } @@ -65,7 +64,7 @@ public function requestingInvalidTagReturnsError() /** @var MethodProphecy $rename */ $rename = $this->tagService->renameTag('foo', 'bar')->willThrow(EntityDoesNotExistException::class); - $resp = $this->action->process($request, $this->prophesize(DelegateInterface::class)->reveal()); + $resp = $this->action->handle($request); $this->assertEquals(404, $resp->getStatusCode()); $rename->shouldHaveBeenCalled(); @@ -83,7 +82,7 @@ public function correctInvocationRenamesTag() /** @var MethodProphecy $rename */ $rename = $this->tagService->renameTag('foo', 'bar')->willReturn(new Tag()); - $resp = $this->action->process($request, $this->prophesize(DelegateInterface::class)->reveal()); + $resp = $this->action->handle($request); $this->assertEquals(204, $resp->getStatusCode()); $rename->shouldHaveBeenCalled(); diff --git a/module/Rest/test/Middleware/BodyParserMiddlewareTest.php b/module/Rest/test/Middleware/BodyParserMiddlewareTest.php index 1c927f4f3..e433322ba 100644 --- a/module/Rest/test/Middleware/BodyParserMiddlewareTest.php +++ b/module/Rest/test/Middleware/BodyParserMiddlewareTest.php @@ -3,11 +3,11 @@ namespace ShlinkioTest\Shlink\Rest\Middleware; -use Interop\Http\ServerMiddleware\DelegateInterface; use PHPUnit\Framework\TestCase; use Prophecy\Argument; use Prophecy\Prophecy\MethodProphecy; use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Server\RequestHandlerInterface; use Shlinkio\Shlink\Rest\Middleware\BodyParserMiddleware; use Zend\Diactoros\Response; use Zend\Diactoros\ServerRequestFactory; @@ -31,9 +31,9 @@ public function setUp() public function requestsFromOtherMethodsJustFallbackToNextMiddleware() { $request = ServerRequestFactory::fromGlobals()->withMethod('GET'); - $delegate = $this->prophesize(DelegateInterface::class); + $delegate = $this->prophesize(RequestHandlerInterface::class); /** @var MethodProphecy $process */ - $process = $delegate->process($request)->willReturn(new Response()); + $process = $delegate->handle($request)->willReturn(new Response()); $this->middleware->process($request, $delegate->reveal()); @@ -51,9 +51,9 @@ public function jsonRequestsAreJsonDecoded() $request = ServerRequestFactory::fromGlobals()->withMethod('PUT') ->withBody($body) ->withHeader('content-type', 'application/json'); - $delegate = $this->prophesize(DelegateInterface::class); + $delegate = $this->prophesize(RequestHandlerInterface::class); /** @var MethodProphecy $process */ - $process = $delegate->process(Argument::type(ServerRequestInterface::class))->will( + $process = $delegate->handle(Argument::type(ServerRequestInterface::class))->will( function (array $args) use ($test) { /** @var ServerRequestInterface $req */ $req = array_shift($args); @@ -82,9 +82,9 @@ public function regularRequestsAreUrlDecoded() $body->write('foo=bar&bar[]=one&bar[]=5'); $request = ServerRequestFactory::fromGlobals()->withMethod('PUT') ->withBody($body); - $delegate = $this->prophesize(DelegateInterface::class); + $delegate = $this->prophesize(RequestHandlerInterface::class); /** @var MethodProphecy $process */ - $process = $delegate->process(Argument::type(ServerRequestInterface::class))->will( + $process = $delegate->handle(Argument::type(ServerRequestInterface::class))->will( function (array $args) use ($test) { /** @var ServerRequestInterface $req */ $req = array_shift($args); diff --git a/module/Rest/test/Middleware/CheckAuthenticationMiddlewareTest.php b/module/Rest/test/Middleware/CheckAuthenticationMiddlewareTest.php index 9c805d1b4..fa7f7d063 100644 --- a/module/Rest/test/Middleware/CheckAuthenticationMiddlewareTest.php +++ b/module/Rest/test/Middleware/CheckAuthenticationMiddlewareTest.php @@ -3,10 +3,10 @@ namespace ShlinkioTest\Shlink\Rest\Middleware; -use Interop\Http\ServerMiddleware\DelegateInterface; use PHPUnit\Framework\TestCase; use Prophecy\Prophecy\MethodProphecy; use Prophecy\Prophecy\ObjectProphecy; +use Psr\Http\Server\RequestHandlerInterface; use Shlinkio\Shlink\Rest\Action\AuthenticateAction; use Shlinkio\Shlink\Rest\Authentication\JWTService; use Shlinkio\Shlink\Rest\Middleware\CheckAuthenticationMiddleware; @@ -16,7 +16,6 @@ use Zend\Expressive\Router\Route; use Zend\Expressive\Router\RouteResult; use Zend\I18n\Translator\Translator; - use function Zend\Stratigility\middleware; class CheckAuthenticationMiddlewareTest extends TestCase @@ -50,9 +49,9 @@ public function setUp() public function someWhiteListedSituationsFallbackToNextMiddleware() { $request = ServerRequestFactory::fromGlobals(); - $delegate = $this->prophesize(DelegateInterface::class); + $delegate = $this->prophesize(RequestHandlerInterface::class); /** @var MethodProphecy $process */ - $process = $delegate->process($request)->willReturn(new Response()); + $process = $delegate->handle($request)->willReturn(new Response()); $this->middleware->process($request, $delegate->reveal()); $process->shouldHaveBeenCalledTimes(1); @@ -61,9 +60,9 @@ public function someWhiteListedSituationsFallbackToNextMiddleware() RouteResult::class, RouteResult::fromRouteFailure(['GET']) ); - $delegate = $this->prophesize(DelegateInterface::class); + $delegate = $this->prophesize(RequestHandlerInterface::class); /** @var MethodProphecy $process */ - $process = $delegate->process($request)->willReturn(new Response()); + $process = $delegate->handle($request)->willReturn(new Response()); $this->middleware->process($request, $delegate->reveal()); $process->shouldHaveBeenCalledTimes(1); @@ -76,9 +75,9 @@ public function someWhiteListedSituationsFallbackToNextMiddleware() AuthenticateAction::class )) ); - $delegate = $this->prophesize(DelegateInterface::class); + $delegate = $this->prophesize(RequestHandlerInterface::class); /** @var MethodProphecy $process */ - $process = $delegate->process($request)->willReturn(new Response()); + $process = $delegate->handle($request)->willReturn(new Response()); $this->middleware->process($request, $delegate->reveal()); $process->shouldHaveBeenCalledTimes(1); @@ -86,9 +85,9 @@ public function someWhiteListedSituationsFallbackToNextMiddleware() RouteResult::class, RouteResult::fromRoute(new Route('bar', $this->dummyMiddleware), []) )->withMethod('OPTIONS'); - $delegate = $this->prophesize(DelegateInterface::class); + $delegate = $this->prophesize(RequestHandlerInterface::class); /** @var MethodProphecy $process */ - $process = $delegate->process($request)->willReturn(new Response()); + $process = $delegate->handle($request)->willReturn(new Response()); $this->middleware->process($request, $delegate->reveal()); $process->shouldHaveBeenCalledTimes(1); } @@ -102,7 +101,7 @@ public function noHeaderReturnsError() RouteResult::class, RouteResult::fromRoute(new Route('bar', $this->dummyMiddleware), []) ); - $response = $this->middleware->process($request, TestUtils::createDelegateMock()->reveal()); + $response = $this->middleware->process($request, TestUtils::createReqHandlerMock()->reveal()); $this->assertEquals(401, $response->getStatusCode()); } @@ -117,7 +116,7 @@ public function provideAnAuthorizationWithoutTypeReturnsError() RouteResult::fromRoute(new Route('bar', $this->dummyMiddleware), []) )->withHeader(CheckAuthenticationMiddleware::AUTHORIZATION_HEADER, $authToken); - $response = $this->middleware->process($request, TestUtils::createDelegateMock()->reveal()); + $response = $this->middleware->process($request, TestUtils::createReqHandlerMock()->reveal()); $this->assertEquals(401, $response->getStatusCode()); $this->assertTrue(strpos($response->getBody()->getContents(), 'You need to provide the Bearer type') > 0); @@ -134,7 +133,7 @@ public function provideAnAuthorizationWithWrongTypeReturnsError() RouteResult::fromRoute(new Route('bar', $this->dummyMiddleware), []) )->withHeader(CheckAuthenticationMiddleware::AUTHORIZATION_HEADER, 'Basic ' . $authToken); - $response = $this->middleware->process($request, TestUtils::createDelegateMock()->reveal()); + $response = $this->middleware->process($request, TestUtils::createReqHandlerMock()->reveal()); $this->assertEquals(401, $response->getStatusCode()); $this->assertTrue( @@ -154,7 +153,7 @@ public function provideAnExpiredTokenReturnsError() )->withHeader(CheckAuthenticationMiddleware::AUTHORIZATION_HEADER, 'Bearer ' . $authToken); $this->jwtService->verify($authToken)->willReturn(false)->shouldBeCalledTimes(1); - $response = $this->middleware->process($request, TestUtils::createDelegateMock()->reveal()); + $response = $this->middleware->process($request, TestUtils::createReqHandlerMock()->reveal()); $this->assertEquals(401, $response->getStatusCode()); } @@ -171,9 +170,9 @@ public function provideCorrectTokenUpdatesExpirationAndFallsBackToNextMiddleware $this->jwtService->verify($authToken)->willReturn(true)->shouldBeCalledTimes(1); $this->jwtService->refresh($authToken)->willReturn($authToken)->shouldBeCalledTimes(1); - $delegate = $this->prophesize(DelegateInterface::class); + $delegate = $this->prophesize(RequestHandlerInterface::class); /** @var MethodProphecy $process */ - $process = $delegate->process($request)->willReturn(new Response()); + $process = $delegate->handle($request)->willReturn(new Response()); $resp = $this->middleware->process($request, $delegate->reveal()); $process->shouldHaveBeenCalledTimes(1); diff --git a/module/Rest/test/Middleware/CrossDomainMiddlewareTest.php b/module/Rest/test/Middleware/CrossDomainMiddlewareTest.php index dcc7e878b..478113ff4 100644 --- a/module/Rest/test/Middleware/CrossDomainMiddlewareTest.php +++ b/module/Rest/test/Middleware/CrossDomainMiddlewareTest.php @@ -3,10 +3,10 @@ namespace ShlinkioTest\Shlink\Rest\Middleware; -use Interop\Http\ServerMiddleware\DelegateInterface; use PHPUnit\Framework\TestCase; use Prophecy\Argument; use Prophecy\Prophecy\ObjectProphecy; +use Psr\Http\Server\RequestHandlerInterface; use Shlinkio\Shlink\Rest\Middleware\CrossDomainMiddleware; use Zend\Diactoros\Response; use Zend\Diactoros\ServerRequestFactory; @@ -25,7 +25,7 @@ class CrossDomainMiddlewareTest extends TestCase public function setUp() { $this->middleware = new CrossDomainMiddleware(); - $this->delegate = $this->prophesize(DelegateInterface::class); + $this->delegate = $this->prophesize(RequestHandlerInterface::class); } /** @@ -34,7 +34,7 @@ public function setUp() public function nonCrossDomainRequestsAreNotAffected() { $originalResponse = new Response(); - $this->delegate->process(Argument::any())->willReturn($originalResponse)->shouldbeCalledTimes(1); + $this->delegate->handle(Argument::any())->willReturn($originalResponse)->shouldbeCalledTimes(1); $response = $this->middleware->process(ServerRequestFactory::fromGlobals(), $this->delegate->reveal()); $this->assertSame($originalResponse, $response); @@ -50,7 +50,7 @@ public function nonCrossDomainRequestsAreNotAffected() public function anyRequestIncludesTheAllowAccessHeader() { $originalResponse = new Response(); - $this->delegate->process(Argument::any())->willReturn($originalResponse)->shouldbeCalledTimes(1); + $this->delegate->handle(Argument::any())->willReturn($originalResponse)->shouldbeCalledTimes(1); $response = $this->middleware->process( ServerRequestFactory::fromGlobals()->withHeader('Origin', 'local'), @@ -70,7 +70,7 @@ public function optionsRequestIncludesMoreHeaders() { $originalResponse = new Response(); $request = ServerRequestFactory::fromGlobals()->withMethod('OPTIONS')->withHeader('Origin', 'local'); - $this->delegate->process(Argument::any())->willReturn($originalResponse)->shouldbeCalledTimes(1); + $this->delegate->handle(Argument::any())->willReturn($originalResponse)->shouldbeCalledTimes(1); $response = $this->middleware->process($request, $this->delegate->reveal()); $this->assertNotSame($originalResponse, $response); diff --git a/module/Rest/test/Middleware/PathVersionMiddlewareTest.php b/module/Rest/test/Middleware/PathVersionMiddlewareTest.php index 4c98d4f22..e024c1285 100644 --- a/module/Rest/test/Middleware/PathVersionMiddlewareTest.php +++ b/module/Rest/test/Middleware/PathVersionMiddlewareTest.php @@ -3,11 +3,11 @@ namespace ShlinkioTest\Shlink\Rest\Middleware; -use Interop\Http\ServerMiddleware\DelegateInterface; use PHPUnit\Framework\Assert; use PHPUnit\Framework\TestCase; use Prophecy\Argument; use Psr\Http\Message\ServerRequestInterface as Request; +use Psr\Http\Server\RequestHandlerInterface; use Shlinkio\Shlink\Rest\Middleware\PathVersionMiddleware; use Zend\Diactoros\Response; use Zend\Diactoros\ServerRequestFactory; @@ -32,8 +32,8 @@ public function whenVersionIsProvidedRequestRemainsUnchanged() { $request = ServerRequestFactory::fromGlobals()->withUri(new Uri('/rest/v2/foo')); - $delegate = $this->prophesize(DelegateInterface::class); - $process = $delegate->process($request)->willReturn(new Response()); + $delegate = $this->prophesize(RequestHandlerInterface::class); + $process = $delegate->handle($request)->willReturn(new Response()); $this->middleware->process($request, $delegate->reveal()); @@ -47,8 +47,8 @@ public function whenPathDoesNotStartWithRestRemainsUnchanged() { $request = ServerRequestFactory::fromGlobals()->withUri(new Uri('/foo')); - $delegate = $this->prophesize(DelegateInterface::class); - $process = $delegate->process($request)->willReturn(new Response()); + $delegate = $this->prophesize(RequestHandlerInterface::class); + $process = $delegate->handle($request)->willReturn(new Response()); $this->middleware->process($request, $delegate->reveal()); @@ -62,8 +62,8 @@ public function versionOneIsPrependedWhenNoVersionIsDefined() { $request = ServerRequestFactory::fromGlobals()->withUri(new Uri('/rest/bar/baz')); - $delegate = $this->prophesize(DelegateInterface::class); - $delegate->process(Argument::type(Request::class))->will(function (array $args) use ($request) { + $delegate = $this->prophesize(RequestHandlerInterface::class); + $delegate->handle(Argument::type(Request::class))->will(function (array $args) use ($request) { $req = \array_shift($args); Assert::assertNotSame($request, $req); diff --git a/phpstan.neon b/phpstan.neon index 77e32e1e8..00a81049a 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,3 +1,4 @@ parameters: excludes_analyse: - module/Common/src/Template/Extension/TranslatorExtension.php + - module/Rest/src/Util/RestUtils.php diff --git a/public/index.php b/public/index.php index 3f2c0f849..fa5d778c1 100644 --- a/public/index.php +++ b/public/index.php @@ -1,9 +1,9 @@ get(Application::class)->run(); +$container->get(Application::class)->run();