From d767c415d1fa03ea849df83656c06e1118649db6 Mon Sep 17 00:00:00 2001
From: Alejandro Celaya <alejandro@alejandrocelaya.com>
Date: Mon, 12 Aug 2019 18:34:52 +0200
Subject: [PATCH] Deleted local Common module and used external one

---
 composer.json                                 |  6 +-
 module/Common/LICENSE                         | 21 -----
 module/Common/README.md                       | 89 -------------------
 module/Common/config/cache.config.php         | 17 ----
 module/Common/config/dependencies.config.php  | 48 ----------
 module/Common/config/doctrine.config.php      | 35 --------
 module/Common/config/templates.config.php     | 14 ---
 module/Common/functions/functions.php         | 72 ---------------
 module/Common/src/Cache/CacheFactory.php      | 51 -----------
 module/Common/src/Cache/RedisFactory.php      | 28 ------
 module/Common/src/ConfigProvider.php          | 12 ---
 .../Common/src/Doctrine/ConnectionFactory.php | 17 ----
 .../src/Doctrine/EntityManagerFactory.php     | 52 -----------
 .../Doctrine/NoDbNameConnectionFactory.php    | 21 -----
 .../src/Doctrine/ReopeningEntityManager.php   | 57 ------------
 .../ReopeningEntityManagerDelegator.php       | 15 ----
 .../src/Doctrine/Type/ChronosDateTimeType.php | 53 -----------
 module/Common/src/Entity/AbstractEntity.php   | 24 -----
 .../src/Exception/ExceptionInterface.php      | 10 ---
 .../Exception/InvalidArgumentException.php    | 10 ---
 .../DottedAccessConfigAbstractFactory.php     | 86 ------------------
 module/Common/src/I18n/TranslatorFactory.php  | 16 ----
 .../Lock/RetryLockStoreDelegatorFactory.php   | 18 ----
 .../Logger/LoggerAwareDelegatorFactory.php    | 20 -----
 module/Common/src/Logger/LoggerFactory.php    | 29 ------
 .../ExceptionWithNewLineProcessor.php         | 30 -------
 .../CloseDbConnectionMiddleware.php           | 31 -------
 .../Middleware/IpAddressMiddlewareFactory.php | 19 ----
 .../src/Middleware/LocaleMiddleware.php       | 61 -------------
 .../Paginator/Util/PaginatorUtilsTrait.php    | 43 ---------
 module/Common/src/Response/PixelResponse.php  | 36 --------
 module/Common/src/Response/QrCodeResponse.php | 32 -------
 .../src/Response/ResponseUtilsTrait.php       | 30 -------
 .../src/Rest/DataTransformerInterface.php     |  9 --
 .../Extension/TranslatorExtension.php         | 25 ------
 module/Common/src/Util/DateRange.php          | 35 --------
 module/Common/src/Util/IpAddress.php          | 72 ---------------
 module/Common/src/Util/StringUtilsTrait.php   | 46 ----------
 .../src/Validation/InputFactoryTrait.php      | 35 --------
 .../Common/src/Validation/SluggerFilter.php   | 31 -------
 module/Common/test/Cache/CacheFactoryTest.php | 62 -------------
 module/Common/test/Cache/RedisFactoryTest.php | 79 ----------------
 module/Common/test/ConfigProviderTest.php     | 27 ------
 .../test/Doctrine/ConnectionFactoryTest.php   | 44 ---------
 .../Doctrine/EntityManagerFactoryTest.php     | 44 ---------
 .../NoDbNameConnectionFactoryTest.php         | 56 ------------
 .../ReopeningEntityManagerDelegatorTest.php   | 28 ------
 .../Doctrine/ReopeningEntityManagerTest.php   | 80 -----------------
 .../Doctrine/Type/ChronosDateTimeTypeTest.php | 88 ------------------
 .../DottedAccessConfigAbstractFactoryTest.php | 78 ----------------
 .../test/I18n/TranslatorFactoryTest.php       | 29 ------
 .../RetryLockStoreDelegatorFactoryTest.php    | 41 ---------
 .../LoggerAwareDelegatorFactoryTest.php       | 55 ------------
 .../Common/test/Logger/LoggerFactoryTest.php  | 48 ----------
 .../ExceptionWithNewLineProcessorTest.php     | 67 --------------
 .../CloseDbConnectionMiddlewareTest.php       | 72 ---------------
 .../IpAddressMiddlewareFactoryTest.php        | 85 ------------------
 .../test/Middleware/LocaleMiddlewareTest.php  | 63 -------------
 .../test/Response/PixelResponseTest.php       | 25 ------
 .../test/Response/QrCodeResponseTest.php      | 21 -----
 .../Extension/TranslatorExtensionTest.php     | 36 --------
 module/Common/test/Util/DateRangeTest.php     | 52 -----------
 .../Common/test/Util/StringUtilsTraitTest.php | 44 ---------
 module/Common/test/Util/TestUtils.php         | 37 --------
 .../test/Validation/SluggerFilterTest.php     | 44 ---------
 module/Core/test/Action/PixelActionTest.php   |  6 +-
 module/Core/test/Action/PreviewActionTest.php |  9 +-
 .../Core/test/Action/RedirectActionTest.php   | 13 ++-
 phpstan.neon                                  |  1 -
 phpunit.xml.dist                              |  3 -
 70 files changed, 15 insertions(+), 2678 deletions(-)
 delete mode 100644 module/Common/LICENSE
 delete mode 100644 module/Common/README.md
 delete mode 100644 module/Common/config/cache.config.php
 delete mode 100644 module/Common/config/dependencies.config.php
 delete mode 100644 module/Common/config/doctrine.config.php
 delete mode 100644 module/Common/config/templates.config.php
 delete mode 100644 module/Common/functions/functions.php
 delete mode 100644 module/Common/src/Cache/CacheFactory.php
 delete mode 100644 module/Common/src/Cache/RedisFactory.php
 delete mode 100644 module/Common/src/ConfigProvider.php
 delete mode 100644 module/Common/src/Doctrine/ConnectionFactory.php
 delete mode 100644 module/Common/src/Doctrine/EntityManagerFactory.php
 delete mode 100644 module/Common/src/Doctrine/NoDbNameConnectionFactory.php
 delete mode 100644 module/Common/src/Doctrine/ReopeningEntityManager.php
 delete mode 100644 module/Common/src/Doctrine/ReopeningEntityManagerDelegator.php
 delete mode 100644 module/Common/src/Doctrine/Type/ChronosDateTimeType.php
 delete mode 100644 module/Common/src/Entity/AbstractEntity.php
 delete mode 100644 module/Common/src/Exception/ExceptionInterface.php
 delete mode 100644 module/Common/src/Exception/InvalidArgumentException.php
 delete mode 100644 module/Common/src/Factory/DottedAccessConfigAbstractFactory.php
 delete mode 100644 module/Common/src/I18n/TranslatorFactory.php
 delete mode 100644 module/Common/src/Lock/RetryLockStoreDelegatorFactory.php
 delete mode 100644 module/Common/src/Logger/LoggerAwareDelegatorFactory.php
 delete mode 100644 module/Common/src/Logger/LoggerFactory.php
 delete mode 100644 module/Common/src/Logger/Processor/ExceptionWithNewLineProcessor.php
 delete mode 100644 module/Common/src/Middleware/CloseDbConnectionMiddleware.php
 delete mode 100644 module/Common/src/Middleware/IpAddressMiddlewareFactory.php
 delete mode 100644 module/Common/src/Middleware/LocaleMiddleware.php
 delete mode 100644 module/Common/src/Paginator/Util/PaginatorUtilsTrait.php
 delete mode 100644 module/Common/src/Response/PixelResponse.php
 delete mode 100644 module/Common/src/Response/QrCodeResponse.php
 delete mode 100644 module/Common/src/Response/ResponseUtilsTrait.php
 delete mode 100644 module/Common/src/Rest/DataTransformerInterface.php
 delete mode 100644 module/Common/src/Template/Extension/TranslatorExtension.php
 delete mode 100644 module/Common/src/Util/DateRange.php
 delete mode 100644 module/Common/src/Util/IpAddress.php
 delete mode 100644 module/Common/src/Util/StringUtilsTrait.php
 delete mode 100644 module/Common/src/Validation/InputFactoryTrait.php
 delete mode 100644 module/Common/src/Validation/SluggerFilter.php
 delete mode 100644 module/Common/test/Cache/CacheFactoryTest.php
 delete mode 100644 module/Common/test/Cache/RedisFactoryTest.php
 delete mode 100644 module/Common/test/ConfigProviderTest.php
 delete mode 100644 module/Common/test/Doctrine/ConnectionFactoryTest.php
 delete mode 100644 module/Common/test/Doctrine/EntityManagerFactoryTest.php
 delete mode 100644 module/Common/test/Doctrine/NoDbNameConnectionFactoryTest.php
 delete mode 100644 module/Common/test/Doctrine/ReopeningEntityManagerDelegatorTest.php
 delete mode 100644 module/Common/test/Doctrine/ReopeningEntityManagerTest.php
 delete mode 100644 module/Common/test/Doctrine/Type/ChronosDateTimeTypeTest.php
 delete mode 100644 module/Common/test/Factory/DottedAccessConfigAbstractFactoryTest.php
 delete mode 100644 module/Common/test/I18n/TranslatorFactoryTest.php
 delete mode 100644 module/Common/test/Lock/RetryLockStoreDelegatorFactoryTest.php
 delete mode 100644 module/Common/test/Logger/LoggerAwareDelegatorFactoryTest.php
 delete mode 100644 module/Common/test/Logger/LoggerFactoryTest.php
 delete mode 100644 module/Common/test/Logger/Processor/ExceptionWithNewLineProcessorTest.php
 delete mode 100644 module/Common/test/Middleware/CloseDbConnectionMiddlewareTest.php
 delete mode 100644 module/Common/test/Middleware/IpAddressMiddlewareFactoryTest.php
 delete mode 100644 module/Common/test/Middleware/LocaleMiddlewareTest.php
 delete mode 100644 module/Common/test/Response/PixelResponseTest.php
 delete mode 100644 module/Common/test/Response/QrCodeResponseTest.php
 delete mode 100644 module/Common/test/Template/Extension/TranslatorExtensionTest.php
 delete mode 100644 module/Common/test/Util/DateRangeTest.php
 delete mode 100644 module/Common/test/Util/StringUtilsTraitTest.php
 delete mode 100644 module/Common/test/Util/TestUtils.php
 delete mode 100644 module/Common/test/Validation/SluggerFilterTest.php

diff --git a/composer.json b/composer.json
index bfdaa59b..7f2677c2 100644
--- a/composer.json
+++ b/composer.json
@@ -32,6 +32,7 @@
         "ocramius/proxy-manager": "~2.2.2",
         "phly/phly-event-dispatcher": "^1.0",
         "predis/predis": "^1.1",
+        "shlinkio/shlink-common": "^1.0",
         "shlinkio/shlink-installer": "^1.2.1",
         "symfony/console": "^4.3",
         "symfony/filesystem": "^4.3",
@@ -56,7 +57,7 @@
         "devster/ubench": "^2.0",
         "eaglewu/swoole-ide-helper": "dev-master",
         "filp/whoops": "^2.4",
-        "infection/infection": "^0.12.2",
+        "infection/infection": "^0.13.4",
         "phpstan/phpstan": "^0.11.2",
         "phpunit/phpcov": "^6.0",
         "phpunit/phpunit": "^8.3",
@@ -73,13 +74,11 @@
             "Shlinkio\\Shlink\\CLI\\": "module/CLI/src",
             "Shlinkio\\Shlink\\Rest\\": "module/Rest/src",
             "Shlinkio\\Shlink\\Core\\": "module/Core/src",
-            "Shlinkio\\Shlink\\Common\\": "module/Common/src",
             "Shlinkio\\Shlink\\EventDispatcher\\": "module/EventDispatcher/src",
             "Shlinkio\\Shlink\\IpGeolocation\\": "module/IpGeolocation/src/",
             "Shlinkio\\Shlink\\PreviewGenerator\\": "module/PreviewGenerator/src/"
         },
         "files": [
-            "module/Common/functions/functions.php",
             "module/EventDispatcher/functions/functions.php"
         ]
     },
@@ -92,7 +91,6 @@
                 "module/Core/test",
                 "module/Core/test-db"
             ],
-            "ShlinkioTest\\Shlink\\Common\\": "module/Common/test",
             "ShlinkioTest\\Shlink\\EventDispatcher\\": "module/EventDispatcher/test",
             "ShlinkioTest\\Shlink\\IpGeolocation\\": "module/IpGeolocation/test",
             "ShlinkioTest\\Shlink\\PreviewGenerator\\": "module/PreviewGenerator/test"
diff --git a/module/Common/LICENSE b/module/Common/LICENSE
deleted file mode 100644
index 31778387..00000000
--- a/module/Common/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2019 Alejandro Celaya
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/module/Common/README.md b/module/Common/README.md
deleted file mode 100644
index d4dc4815..00000000
--- a/module/Common/README.md
+++ /dev/null
@@ -1,89 +0,0 @@
-# Shlink Common
-
-This library provides some utils and conventions for web apps. It's main purpose is to be used on [Shlink](https://github.com/shlinkio/shlink) project, but any PHP project can take advantage.
-
-Most of the elements it provides require a [PSR-11] container, and it's easy to integrate on [expressive] applications thanks to the `ConfigProvider` it includes.
-
-## Install
-
-Install this library using composer:
-
-    composer require shlinkio/shlink-common
-
-> This library is also an expressive module which provides its own `ConfigProvider`. Add it to your configuration to get everything automatically set up.
-
-## Cache
-
-A [doctrine cache] adapter is registered, which returns different instances depending on your configuration:
- 
- * An `ArrayCache` instance when the `debug` config is set to true or when the APUc extension is not installed and the `cache.redis` config is not defined.
- * An `ApcuCache`instance when no `cache.redis` is defined and the APCu extension is installed.
- * A `PredisCache` instance when the `cache.redis` config is defined.
- 
- Any of the adapters will use the namespace defined in `cache.namespace` config entry.
- 
- ```php
-<?php
-declare(strict_types=1);
-
-return [
-
-    'debug' => false,
-
-    'cache' => [
-        'namespace' => 'my_namespace',
-        'redis' => [
-            'servers' => [
-                'tcp://1.1.1.1:6379',
-                'tcp://2.2.2.2:6379',
-                'tcp://3.3.3.3:6379',
-            ],
-        ],
-    ],
-
-];
-```
-
-When the `cache.redis` config is provided, a set of servers is expected. If only one server is provided, this library will treat it as a regular server, but if several servers are defined, it will treat them as a redis cluster and expect the servers to be configured as such.
-
-## Middlewares
-
-This module provides a set of useful middlewares, all registered as services in the container:
-
-* **CloseDatabaseConnectionMiddleware**:
-
-    Should be an early middleware in the pipeline. It makes use of the EntityManager that ensure the database connection is closed at the end of the request.
-
-    It should be used when serving an app with a non-blocking IO server (like Swoole or ReactPHP), which persist services between requests.
-
-* **LocaleMiddleware**:
-
-    Sets the locale in the translator, based on the `Accapt-Language` header.
-
-* **IpAddress** (from [akrabat/ip-address-middleware] package):
-
-    Improves detection of the remote IP address.
-
-    The set of headers which are inspected in order to search for the address can be customized using this configuration:
-
-    ```php
-    <?php
-    declare(strict_types=1);
-
-    return [
-
-        'ip_address_resolution' => [
-            'headers_to_inspect' => [
-                'CF-Connecting-IP',
-                'True-Client-IP',
-                'X-Real-IP',
-                'Forwarded',
-                'X-Forwarded-For',
-                'X-Forwarded',
-                'X-Cluster-Client-Ip',
-                'Client-Ip',
-            ],
-        ],
-
-    ];
-    ```
diff --git a/module/Common/config/cache.config.php b/module/Common/config/cache.config.php
deleted file mode 100644
index 26f547d6..00000000
--- a/module/Common/config/cache.config.php
+++ /dev/null
@@ -1,17 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace Shlinkio\Shlink\Common;
-
-use Doctrine\Common\Cache as DoctrineCache;
-
-return [
-
-    'dependencies' => [
-        'factories' => [
-            DoctrineCache\Cache::class => Cache\CacheFactory::class,
-            Cache\RedisFactory::SERVICE_NAME => Cache\RedisFactory::class,
-        ],
-    ],
-
-];
diff --git a/module/Common/config/dependencies.config.php b/module/Common/config/dependencies.config.php
deleted file mode 100644
index d4d3110d..00000000
--- a/module/Common/config/dependencies.config.php
+++ /dev/null
@@ -1,48 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace Shlinkio\Shlink\Common;
-
-use GuzzleHttp\Client as GuzzleClient;
-use Monolog\Logger;
-use Psr\Log\LoggerInterface;
-use RKA\Middleware\IpAddress;
-use Symfony\Component\Filesystem\Filesystem;
-use Zend\I18n\Translator\Translator;
-use Zend\ServiceManager\AbstractFactory\ConfigAbstractFactory;
-use Zend\ServiceManager\Factory\InvokableFactory;
-
-return [
-
-    'dependencies' => [
-        'factories' => [
-            GuzzleClient::class => InvokableFactory::class,
-            Filesystem::class => InvokableFactory::class,
-
-            Translator::class => I18n\TranslatorFactory::class,
-            Template\Extension\TranslatorExtension::class => ConfigAbstractFactory::class,
-
-            Middleware\LocaleMiddleware::class => ConfigAbstractFactory::class,
-            Middleware\CloseDbConnectionMiddleware::class => ConfigAbstractFactory::class,
-            IpAddress::class => Middleware\IpAddressMiddlewareFactory::class,
-        ],
-        'aliases' => [
-            'httpClient' => GuzzleClient::class,
-            'translator' => Translator::class,
-
-            'logger' => LoggerInterface::class,
-            Logger::class => 'Logger_Shlink',
-            LoggerInterface::class => 'Logger_Shlink',
-        ],
-        'abstract_factories' => [
-            Factory\DottedAccessConfigAbstractFactory::class,
-        ],
-    ],
-
-    ConfigAbstractFactory::class => [
-        Template\Extension\TranslatorExtension::class => ['translator'],
-        Middleware\LocaleMiddleware::class => ['translator'],
-        Middleware\CloseDbConnectionMiddleware::class => ['em'],
-    ],
-
-];
diff --git a/module/Common/config/doctrine.config.php b/module/Common/config/doctrine.config.php
deleted file mode 100644
index d85ef8e8..00000000
--- a/module/Common/config/doctrine.config.php
+++ /dev/null
@@ -1,35 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace Shlinkio\Shlink\Common;
-
-use Doctrine\DBAL\Connection;
-use Doctrine\ORM\EntityManager;
-
-return [
-
-    'entity_manager' => [
-        'orm' => [
-            'types' => [
-                Doctrine\Type\ChronosDateTimeType::CHRONOS_DATETIME => Doctrine\Type\ChronosDateTimeType::class,
-            ],
-        ],
-    ],
-
-    'dependencies' => [
-        'factories' => [
-            EntityManager::class => Doctrine\EntityManagerFactory::class,
-            Connection::class => Doctrine\ConnectionFactory::class,
-            Doctrine\NoDbNameConnectionFactory::SERVICE_NAME => Doctrine\NoDbNameConnectionFactory::class,
-        ],
-        'aliases' => [
-            'em' => EntityManager::class,
-        ],
-        'delegators' => [
-            EntityManager::class => [
-                Doctrine\ReopeningEntityManagerDelegator::class,
-            ],
-        ],
-    ],
-
-];
diff --git a/module/Common/config/templates.config.php b/module/Common/config/templates.config.php
deleted file mode 100644
index eb25ef78..00000000
--- a/module/Common/config/templates.config.php
+++ /dev/null
@@ -1,14 +0,0 @@
-<?php
-declare(strict_types=1);
-
-use Shlinkio\Shlink\Common\Template\Extension\TranslatorExtension;
-
-return [
-
-    'plates' => [
-        'extensions' => [
-            TranslatorExtension::class,
-        ],
-    ],
-
-];
diff --git a/module/Common/functions/functions.php b/module/Common/functions/functions.php
deleted file mode 100644
index aab0ef26..00000000
--- a/module/Common/functions/functions.php
+++ /dev/null
@@ -1,72 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace Shlinkio\Shlink\Common;
-
-use Zend\Config\Factory;
-use Zend\Stdlib\Glob;
-
-use function getenv;
-use function json_decode as spl_json_decode;
-use function json_last_error;
-use function json_last_error_msg;
-use function sprintf;
-use function strtolower;
-use function trim;
-
-use const JSON_ERROR_NONE;
-
-/**
- * Gets the value of an environment variable. Supports boolean, empty and null.
- * This is basically Laravel's env helper
- *
- * @param string $key
- * @param mixed $default
- * @return mixed
- * @link https://github.com/laravel/framework/blob/5.2/src/Illuminate/Foundation/helpers.php#L369
- */
-function env($key, $default = null)
-{
-    $value = getenv($key);
-    if ($value === false) {
-        return $default;
-    }
-
-    switch (strtolower($value)) {
-        case 'true':
-        case '(true)':
-            return true;
-        case 'false':
-        case '(false)':
-            return false;
-        case 'empty':
-        case '(empty)':
-            return '';
-        case 'null':
-        case '(null)':
-            return null;
-    }
-
-    return trim($value);
-}
-
-/**
- * @throws Exception\InvalidArgumentException
- */
-function json_decode(string $json, int $depth = 512, int $options = 0): array
-{
-    $data = spl_json_decode($json, true, $depth, $options);
-    if (JSON_ERROR_NONE !== json_last_error()) {
-        throw new Exception\InvalidArgumentException(sprintf('Error decoding JSON: %s', json_last_error_msg()));
-    }
-
-    return $data;
-}
-
-/**
- * Loads configuration files which match provided glob pattern, and returns the merged result as array
- */
-function loadConfigFromGlob(string $globPattern): array
-{
-    return Factory::fromFiles(Glob::glob($globPattern, Glob::GLOB_BRACE));
-}
diff --git a/module/Common/src/Cache/CacheFactory.php b/module/Common/src/Cache/CacheFactory.php
deleted file mode 100644
index 12676dd8..00000000
--- a/module/Common/src/Cache/CacheFactory.php
+++ /dev/null
@@ -1,51 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace Shlinkio\Shlink\Common\Cache;
-
-use Doctrine\Common\Cache;
-use Predis\Client as PredisClient;
-use Psr\Container\ContainerInterface;
-
-use function extension_loaded;
-
-class CacheFactory
-{
-    /** @var callable|null */
-    private $apcuEnabled;
-
-    public function __construct(?callable $apcuEnabled = null)
-    {
-        $this->apcuEnabled = $apcuEnabled ?? function () {
-            return extension_loaded('apcu');
-        };
-    }
-
-    public function __invoke(ContainerInterface $container): Cache\CacheProvider
-    {
-        $config = $container->get('config');
-        $adapter = $this->buildAdapter($config, $container);
-        $adapter->setNamespace($config['cache']['namespace'] ?? '');
-
-        return $adapter;
-    }
-
-    private function buildAdapter(array $config, ContainerInterface $container): Cache\CacheProvider
-    {
-        $isDebug = (bool) ($config['debug'] ?? false);
-        $redisConfig = $config['cache']['redis'] ?? null;
-        $apcuEnabled = ($this->apcuEnabled)();
-
-        if ($isDebug || (! $apcuEnabled && $redisConfig === null)) {
-            return new Cache\ArrayCache();
-        }
-
-        if ($redisConfig === null) {
-            return new Cache\ApcuCache();
-        }
-
-        /** @var PredisClient $predis */
-        $predis = $container->get(RedisFactory::SERVICE_NAME);
-        return new Cache\PredisCache($predis);
-    }
-}
diff --git a/module/Common/src/Cache/RedisFactory.php b/module/Common/src/Cache/RedisFactory.php
deleted file mode 100644
index f1a2d693..00000000
--- a/module/Common/src/Cache/RedisFactory.php
+++ /dev/null
@@ -1,28 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace Shlinkio\Shlink\Common\Cache;
-
-use Predis\Client as PredisClient;
-use Psr\Container\ContainerInterface;
-
-use function count;
-use function explode;
-use function is_string;
-
-class RedisFactory
-{
-    public const SERVICE_NAME = 'Shlinkio\Shlink\Common\Cache\Redis';
-
-    public function __invoke(ContainerInterface $container): PredisClient
-    {
-        $config = $container->get('config');
-        $redisConfig = $config['cache']['redis'] ?? $config['redis'] ?? [];
-
-        $servers = $redisConfig['servers'] ?? [];
-        $servers = is_string($servers) ? explode(',', $servers) : $servers;
-        $options = count($servers) <= 1 ? null : ['cluster' => 'redis'];
-
-        return new PredisClient($servers, $options);
-    }
-}
diff --git a/module/Common/src/ConfigProvider.php b/module/Common/src/ConfigProvider.php
deleted file mode 100644
index 7d900823..00000000
--- a/module/Common/src/ConfigProvider.php
+++ /dev/null
@@ -1,12 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace Shlinkio\Shlink\Common;
-
-class ConfigProvider
-{
-    public function __invoke(): array
-    {
-        return loadConfigFromGlob(__DIR__ . '/../config/{,*.}config.php');
-    }
-}
diff --git a/module/Common/src/Doctrine/ConnectionFactory.php b/module/Common/src/Doctrine/ConnectionFactory.php
deleted file mode 100644
index f0c1a561..00000000
--- a/module/Common/src/Doctrine/ConnectionFactory.php
+++ /dev/null
@@ -1,17 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace Shlinkio\Shlink\Common\Doctrine;
-
-use Doctrine\DBAL\Connection;
-use Doctrine\ORM\EntityManager;
-use Psr\Container\ContainerInterface;
-
-class ConnectionFactory
-{
-    public function __invoke(ContainerInterface $container): Connection
-    {
-        $em = $container->get(EntityManager::class);
-        return $em->getConnection();
-    }
-}
diff --git a/module/Common/src/Doctrine/EntityManagerFactory.php b/module/Common/src/Doctrine/EntityManagerFactory.php
deleted file mode 100644
index 43847645..00000000
--- a/module/Common/src/Doctrine/EntityManagerFactory.php
+++ /dev/null
@@ -1,52 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace Shlinkio\Shlink\Common\Doctrine;
-
-use Doctrine\Common\Cache\ArrayCache;
-use Doctrine\Common\Cache\Cache;
-use Doctrine\Common\Persistence\Mapping\Driver\PHPDriver;
-use Doctrine\DBAL\DBALException;
-use Doctrine\DBAL\Types\Type;
-use Doctrine\ORM\EntityManager;
-use Doctrine\ORM\ORMException;
-use Doctrine\ORM\Tools\Setup;
-use Psr\Container\ContainerInterface;
-
-class EntityManagerFactory
-{
-    /**
-     * @throws ORMException
-     * @throws DBALException
-     */
-    public function __invoke(ContainerInterface $container): EntityManager
-    {
-        $globalConfig = $container->get('config');
-        $isDevMode = (bool) ($globalConfig['debug'] ?? false);
-        $cache = $container->has(Cache::class) ? $container->get(Cache::class) : new ArrayCache();
-        $emConfig = $globalConfig['entity_manager'] ?? [];
-        $connectionConfig = $emConfig['connection'] ?? [];
-        $ormConfig = $emConfig['orm'] ?? [];
-
-        $this->registerTypes($ormConfig);
-
-        $config = Setup::createConfiguration($isDevMode, $ormConfig['proxies_dir'] ?? null, $cache);
-        $config->setMetadataDriverImpl(new PHPDriver($ormConfig['entities_mappings'] ?? []));
-
-        return EntityManager::create($connectionConfig, $config);
-    }
-
-    /**
-     * @throws DBALException
-     */
-    private function registerTypes(array $ormConfig): void
-    {
-        $types = $ormConfig['types'] ?? [];
-
-        foreach ($types as $name => $className) {
-            if (! Type::hasType($name)) {
-                Type::addType($name, $className);
-            }
-        }
-    }
-}
diff --git a/module/Common/src/Doctrine/NoDbNameConnectionFactory.php b/module/Common/src/Doctrine/NoDbNameConnectionFactory.php
deleted file mode 100644
index fdf470e0..00000000
--- a/module/Common/src/Doctrine/NoDbNameConnectionFactory.php
+++ /dev/null
@@ -1,21 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace Shlinkio\Shlink\Common\Doctrine;
-
-use Doctrine\DBAL\Connection;
-use Psr\Container\ContainerInterface;
-
-class NoDbNameConnectionFactory
-{
-    public const SERVICE_NAME = 'Shlinkio\Shlink\Common\Doctrine\NoDbNameConnection';
-
-    public function __invoke(ContainerInterface $container): Connection
-    {
-        $conn = $container->get(Connection::class);
-        $params = $conn->getParams();
-        unset($params['dbname']);
-
-        return new Connection($params, $conn->getDriver(), $conn->getConfiguration(), $conn->getEventManager());
-    }
-}
diff --git a/module/Common/src/Doctrine/ReopeningEntityManager.php b/module/Common/src/Doctrine/ReopeningEntityManager.php
deleted file mode 100644
index d9a80e2e..00000000
--- a/module/Common/src/Doctrine/ReopeningEntityManager.php
+++ /dev/null
@@ -1,57 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace Shlinkio\Shlink\Common\Doctrine;
-
-use Doctrine\ORM\Decorator\EntityManagerDecorator;
-use Doctrine\ORM\EntityManagerInterface;
-
-class ReopeningEntityManager extends EntityManagerDecorator
-{
-    /** @var callable */
-    private $emFactory;
-
-    public function __construct(EntityManagerInterface $wrapped, callable $emFactory)
-    {
-        parent::__construct($wrapped);
-        $this->emFactory = $emFactory;
-    }
-
-    protected function getWrappedEntityManager(): EntityManagerInterface
-    {
-        if (! $this->wrapped->isOpen()) {
-            $this->wrapped = ($this->emFactory)(
-                $this->wrapped->getConnection(),
-                $this->wrapped->getConfiguration(),
-                $this->wrapped->getEventManager()
-            );
-        }
-
-        return $this->wrapped;
-    }
-
-    public function flush($entity = null): void
-    {
-        $this->getWrappedEntityManager()->flush($entity);
-    }
-
-    public function persist($object): void
-    {
-        $this->getWrappedEntityManager()->persist($object);
-    }
-
-    public function remove($object): void
-    {
-        $this->getWrappedEntityManager()->remove($object);
-    }
-
-    public function refresh($object): void
-    {
-        $this->getWrappedEntityManager()->refresh($object);
-    }
-
-    public function merge($object)
-    {
-        return $this->getWrappedEntityManager()->merge($object);
-    }
-}
diff --git a/module/Common/src/Doctrine/ReopeningEntityManagerDelegator.php b/module/Common/src/Doctrine/ReopeningEntityManagerDelegator.php
deleted file mode 100644
index 3ea6a2f1..00000000
--- a/module/Common/src/Doctrine/ReopeningEntityManagerDelegator.php
+++ /dev/null
@@ -1,15 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace Shlinkio\Shlink\Common\Doctrine;
-
-use Doctrine\ORM\EntityManager;
-use Psr\Container\ContainerInterface;
-
-class ReopeningEntityManagerDelegator
-{
-    public function __invoke(ContainerInterface $container, string $name, callable $callback): ReopeningEntityManager
-    {
-        return new ReopeningEntityManager($callback(), [EntityManager::class, 'create']);
-    }
-}
diff --git a/module/Common/src/Doctrine/Type/ChronosDateTimeType.php b/module/Common/src/Doctrine/Type/ChronosDateTimeType.php
deleted file mode 100644
index 210eb03a..00000000
--- a/module/Common/src/Doctrine/Type/ChronosDateTimeType.php
+++ /dev/null
@@ -1,53 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace Shlinkio\Shlink\Common\Doctrine\Type;
-
-use Cake\Chronos\Chronos;
-use DateTimeInterface;
-use Doctrine\DBAL\Platforms\AbstractPlatform;
-use Doctrine\DBAL\Types\ConversionException;
-use Doctrine\DBAL\Types\DateTimeImmutableType;
-
-class ChronosDateTimeType extends DateTimeImmutableType
-{
-    public const CHRONOS_DATETIME = 'chronos_datetime';
-
-    public function getName(): string
-    {
-        return self::CHRONOS_DATETIME;
-    }
-
-    /**
-     * @throws ConversionException
-     */
-    public function convertToPHPValue($value, AbstractPlatform $platform): ?Chronos
-    {
-        if ($value === null) {
-            return null;
-        }
-
-        $dateTime = parent::convertToPHPValue($value, $platform);
-        return Chronos::instance($dateTime);
-    }
-
-    /**
-     * @throws ConversionException
-     */
-    public function convertToDatabaseValue($value, AbstractPlatform $platform): ?string
-    {
-        if (null === $value) {
-            return $value;
-        }
-
-        if ($value instanceof DateTimeInterface) {
-            return $value->format($platform->getDateTimeFormatString());
-        }
-
-        throw ConversionException::conversionFailedInvalidType(
-            $value,
-            $this->getName(),
-            ['null', DateTimeInterface::class]
-        );
-    }
-}
diff --git a/module/Common/src/Entity/AbstractEntity.php b/module/Common/src/Entity/AbstractEntity.php
deleted file mode 100644
index dc3b84bc..00000000
--- a/module/Common/src/Entity/AbstractEntity.php
+++ /dev/null
@@ -1,24 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace Shlinkio\Shlink\Common\Entity;
-
-abstract class AbstractEntity
-{
-    /** @var string */
-    protected $id;
-
-    public function getId(): string
-    {
-        return $this->id;
-    }
-
-    /**
-     * @internal
-     */
-    public function setId(string $id): self
-    {
-        $this->id = $id;
-        return $this;
-    }
-}
diff --git a/module/Common/src/Exception/ExceptionInterface.php b/module/Common/src/Exception/ExceptionInterface.php
deleted file mode 100644
index 9f2eca48..00000000
--- a/module/Common/src/Exception/ExceptionInterface.php
+++ /dev/null
@@ -1,10 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace Shlinkio\Shlink\Common\Exception;
-
-use Throwable;
-
-interface ExceptionInterface extends Throwable
-{
-}
diff --git a/module/Common/src/Exception/InvalidArgumentException.php b/module/Common/src/Exception/InvalidArgumentException.php
deleted file mode 100644
index 52e6b365..00000000
--- a/module/Common/src/Exception/InvalidArgumentException.php
+++ /dev/null
@@ -1,10 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace Shlinkio\Shlink\Common\Exception;
-
-use InvalidArgumentException as SplInvalidArgumentException;
-
-class InvalidArgumentException extends SplInvalidArgumentException implements ExceptionInterface
-{
-}
diff --git a/module/Common/src/Factory/DottedAccessConfigAbstractFactory.php b/module/Common/src/Factory/DottedAccessConfigAbstractFactory.php
deleted file mode 100644
index 64c4d2f8..00000000
--- a/module/Common/src/Factory/DottedAccessConfigAbstractFactory.php
+++ /dev/null
@@ -1,86 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace Shlinkio\Shlink\Common\Factory;
-
-use ArrayAccess;
-use Interop\Container\ContainerInterface;
-use Interop\Container\Exception\ContainerException;
-use Shlinkio\Shlink\Common\Exception\InvalidArgumentException;
-use Zend\ServiceManager\Exception\ServiceNotCreatedException;
-use Zend\ServiceManager\Exception\ServiceNotFoundException;
-use Zend\ServiceManager\Factory\AbstractFactoryInterface;
-
-use function array_shift;
-use function explode;
-use function is_array;
-use function sprintf;
-use function substr_count;
-
-class DottedAccessConfigAbstractFactory implements AbstractFactoryInterface
-{
-    /**
-     * Can the factory create an instance for the service?
-     *
-     * @param  string $requestedName
-     */
-    public function canCreate(ContainerInterface $container, $requestedName): bool
-    {
-        return substr_count($requestedName, '.') > 0;
-    }
-
-    /**
-     * Create an object
-     *
-     * @param  ContainerInterface $container
-     * @param  string $requestedName
-     * @param  null|array $options
-     * @return object
-     * @throws InvalidArgumentException
-     * @throws ServiceNotFoundException if unable to resolve the service.
-     * @throws ServiceNotCreatedException if an exception is raised when
-     *     creating a service.
-     * @throws ContainerException if any other error occurs
-     */
-    public function __invoke(ContainerInterface $container, $requestedName, ?array $options = null)
-    {
-        $parts = explode('.', $requestedName);
-        $serviceName = array_shift($parts);
-        if (! $container->has($serviceName)) {
-            throw new ServiceNotCreatedException(sprintf(
-                'Defined service "%s" could not be found in container after resolving dotted expression "%s".',
-                $serviceName,
-                $requestedName
-            ));
-        }
-
-        $array = $container->get($serviceName);
-        return $this->readKeysFromArray($parts, $array);
-    }
-
-    /**
-     * @param array $keys
-     * @param array|\ArrayAccess $array
-     * @return mixed|null
-     * @throws  InvalidArgumentException
-     */
-    private function readKeysFromArray(array $keys, $array)
-    {
-        $key = array_shift($keys);
-
-        // When one of the provided keys is not found, throw an exception
-        if (! isset($array[$key])) {
-            throw new InvalidArgumentException(sprintf(
-                'The key "%s" provided in the dotted notation could not be found in the array service',
-                $key
-            ));
-        }
-
-        $value = $array[$key];
-        if (! empty($keys) && (is_array($value) || $value instanceof ArrayAccess)) {
-            $value = $this->readKeysFromArray($keys, $value);
-        }
-
-        return $value;
-    }
-}
diff --git a/module/Common/src/I18n/TranslatorFactory.php b/module/Common/src/I18n/TranslatorFactory.php
deleted file mode 100644
index 942dad07..00000000
--- a/module/Common/src/I18n/TranslatorFactory.php
+++ /dev/null
@@ -1,16 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace Shlinkio\Shlink\Common\I18n;
-
-use Interop\Container\ContainerInterface;
-use Zend\I18n\Translator\Translator;
-
-class TranslatorFactory
-{
-    public function __invoke(ContainerInterface $container): Translator
-    {
-        $config = $container->get('config');
-        return Translator::factory($config['translator'] ?? []);
-    }
-}
diff --git a/module/Common/src/Lock/RetryLockStoreDelegatorFactory.php b/module/Common/src/Lock/RetryLockStoreDelegatorFactory.php
deleted file mode 100644
index 7828e24f..00000000
--- a/module/Common/src/Lock/RetryLockStoreDelegatorFactory.php
+++ /dev/null
@@ -1,18 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace Shlinkio\Shlink\Common\Lock;
-
-use Interop\Container\ContainerInterface;
-use Symfony\Component\Lock\Store\RetryTillSaveStore;
-use Symfony\Component\Lock\StoreInterface;
-
-class RetryLockStoreDelegatorFactory
-{
-    public function __invoke(ContainerInterface $container, $name, callable $callback): RetryTillSaveStore
-    {
-        /** @var StoreInterface $originalStore */
-        $originalStore = $callback();
-        return new RetryTillSaveStore($originalStore);
-    }
-}
diff --git a/module/Common/src/Logger/LoggerAwareDelegatorFactory.php b/module/Common/src/Logger/LoggerAwareDelegatorFactory.php
deleted file mode 100644
index 8cb04499..00000000
--- a/module/Common/src/Logger/LoggerAwareDelegatorFactory.php
+++ /dev/null
@@ -1,20 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace Shlinkio\Shlink\Common\Logger;
-
-use Psr\Container\ContainerInterface;
-use Psr\Log;
-
-class LoggerAwareDelegatorFactory
-{
-    public function __invoke(ContainerInterface $container, $name, callable $callback)
-    {
-        $instance = $callback();
-        if ($instance instanceof Log\LoggerAwareInterface) {
-            $instance->setLogger($container->get(Log\LoggerInterface::class));
-        }
-
-        return $instance;
-    }
-}
diff --git a/module/Common/src/Logger/LoggerFactory.php b/module/Common/src/Logger/LoggerFactory.php
deleted file mode 100644
index 7e896108..00000000
--- a/module/Common/src/Logger/LoggerFactory.php
+++ /dev/null
@@ -1,29 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace Shlinkio\Shlink\Common\Logger;
-
-use Cascade\Cascade;
-use Interop\Container\ContainerInterface;
-use Monolog\Logger;
-
-use function count;
-use function explode;
-
-class LoggerFactory
-{
-    public function __invoke(ContainerInterface $container, string $requestedName, ?array $options = null): Logger
-    {
-        $config = $container->has('config') ? $container->get('config') : [];
-        Cascade::fileConfig($config['logger'] ?? ['loggers' => []]);
-
-        // Compose requested logger name
-        $loggerName = $options['logger_name'] ?? 'Logger';
-        $nameParts = explode('_', $requestedName);
-        if (count($nameParts) > 1) {
-            $loggerName = $nameParts[1];
-        }
-
-        return Cascade::getLogger($loggerName);
-    }
-}
diff --git a/module/Common/src/Logger/Processor/ExceptionWithNewLineProcessor.php b/module/Common/src/Logger/Processor/ExceptionWithNewLineProcessor.php
deleted file mode 100644
index 91c0a657..00000000
--- a/module/Common/src/Logger/Processor/ExceptionWithNewLineProcessor.php
+++ /dev/null
@@ -1,30 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace Shlinkio\Shlink\Common\Logger\Processor;
-
-use function str_replace;
-use function strpos;
-
-use const PHP_EOL;
-
-final class ExceptionWithNewLineProcessor
-{
-    private const EXCEPTION_PLACEHOLDER = '{e}';
-
-    public function __invoke(array $record)
-    {
-        $message = $record['message'];
-        $messageHasExceptionPlaceholder = strpos($message, self::EXCEPTION_PLACEHOLDER) !== false;
-
-        if ($messageHasExceptionPlaceholder) {
-            $record['message'] = str_replace(
-                self::EXCEPTION_PLACEHOLDER,
-                PHP_EOL . self::EXCEPTION_PLACEHOLDER,
-                $message
-            );
-        }
-
-        return $record;
-    }
-}
diff --git a/module/Common/src/Middleware/CloseDbConnectionMiddleware.php b/module/Common/src/Middleware/CloseDbConnectionMiddleware.php
deleted file mode 100644
index 1294848d..00000000
--- a/module/Common/src/Middleware/CloseDbConnectionMiddleware.php
+++ /dev/null
@@ -1,31 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace Shlinkio\Shlink\Common\Middleware;
-
-use Doctrine\ORM\EntityManagerInterface;
-use Psr\Http\Message\ResponseInterface;
-use Psr\Http\Message\ServerRequestInterface;
-use Psr\Http\Server\MiddlewareInterface;
-use Psr\Http\Server\RequestHandlerInterface;
-
-class CloseDbConnectionMiddleware implements MiddlewareInterface
-{
-    /** @var EntityManagerInterface */
-    private $em;
-
-    public function __construct(EntityManagerInterface $em)
-    {
-        $this->em = $em;
-    }
-
-    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
-    {
-        try {
-            return $handler->handle($request);
-        } finally {
-            $this->em->getConnection()->close();
-            $this->em->clear();
-        }
-    }
-}
diff --git a/module/Common/src/Middleware/IpAddressMiddlewareFactory.php b/module/Common/src/Middleware/IpAddressMiddlewareFactory.php
deleted file mode 100644
index 73d643b4..00000000
--- a/module/Common/src/Middleware/IpAddressMiddlewareFactory.php
+++ /dev/null
@@ -1,19 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace Shlinkio\Shlink\Common\Middleware;
-
-use Psr\Container\ContainerInterface;
-use RKA\Middleware\IpAddress;
-
-class IpAddressMiddlewareFactory
-{
-    public const REQUEST_ATTR = 'remote_address';
-
-    public function __invoke(ContainerInterface $container): IpAddress
-    {
-        $config = $container->get('config');
-        $headersToInspect = $config['ip_address_resolution']['headers_to_inspect'] ?? [];
-        return new IpAddress(true, [], self::REQUEST_ATTR, $headersToInspect);
-    }
-}
diff --git a/module/Common/src/Middleware/LocaleMiddleware.php b/module/Common/src/Middleware/LocaleMiddleware.php
deleted file mode 100644
index 12ba084b..00000000
--- a/module/Common/src/Middleware/LocaleMiddleware.php
+++ /dev/null
@@ -1,61 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace Shlinkio\Shlink\Common\Middleware;
-
-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;
-
-use function count;
-use function explode;
-
-class LocaleMiddleware implements MiddlewareInterface
-{
-    private const ACCEPT_LANGUAGE = 'Accept-Language';
-
-    /** @var Translator */
-    private $translator;
-
-    public function __construct(Translator $translator)
-    {
-        $this->translator = $translator;
-    }
-
-    /**
-     * 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): Response
-    {
-        if (! $request->hasHeader(self::ACCEPT_LANGUAGE)) {
-            return $delegate->handle($request);
-        }
-
-        $locale = $request->getHeaderLine(self::ACCEPT_LANGUAGE);
-        $this->translator->setLocale($this->normalizeLocale($locale));
-        return $delegate->handle($request);
-    }
-
-    private function normalizeLocale(string $locale): string
-    {
-        $parts = explode('_', $locale);
-        if (count($parts) > 1) {
-            return $parts[0];
-        }
-
-        $parts = explode('-', $locale);
-        if (count($parts) > 1) {
-            return $parts[0];
-        }
-
-        return $locale;
-    }
-}
diff --git a/module/Common/src/Paginator/Util/PaginatorUtilsTrait.php b/module/Common/src/Paginator/Util/PaginatorUtilsTrait.php
deleted file mode 100644
index 2009164d..00000000
--- a/module/Common/src/Paginator/Util/PaginatorUtilsTrait.php
+++ /dev/null
@@ -1,43 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace Shlinkio\Shlink\Common\Paginator\Util;
-
-use Shlinkio\Shlink\Common\Rest\DataTransformerInterface;
-use Zend\Paginator\Paginator;
-use Zend\Stdlib\ArrayUtils;
-
-use function array_map;
-use function sprintf;
-
-trait PaginatorUtilsTrait
-{
-    private function serializePaginator(Paginator $paginator, ?DataTransformerInterface $transformer = null): array
-    {
-        return [
-            'data' => $this->serializeItems(ArrayUtils::iteratorToArray($paginator->getCurrentItems()), $transformer),
-            'pagination' => [
-                'currentPage' => $paginator->getCurrentPageNumber(),
-                'pagesCount' => $paginator->count(),
-                'itemsPerPage' => $paginator->getItemCountPerPage(),
-                'itemsInCurrentPage' => $paginator->getCurrentItemCount(),
-                'totalItems' => $paginator->getTotalItemCount(),
-            ],
-        ];
-    }
-
-    private function serializeItems(array $items, ?DataTransformerInterface $transformer = null): array
-    {
-        return $transformer === null ? $items : array_map([$transformer, 'transform'], $items);
-    }
-
-    private function isLastPage(Paginator $paginator): bool
-    {
-        return $paginator->getCurrentPageNumber() >= $paginator->count();
-    }
-
-    private function formatCurrentPageMessage(Paginator $paginator, string $pattern): string
-    {
-        return sprintf($pattern, $paginator->getCurrentPageNumber(), $paginator->count());
-    }
-}
diff --git a/module/Common/src/Response/PixelResponse.php b/module/Common/src/Response/PixelResponse.php
deleted file mode 100644
index 94a81cfc..00000000
--- a/module/Common/src/Response/PixelResponse.php
+++ /dev/null
@@ -1,36 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace Shlinkio\Shlink\Common\Response;
-
-use Fig\Http\Message\StatusCodeInterface as StatusCode;
-use Psr\Http\Message\StreamInterface;
-use Zend\Diactoros\Response;
-use Zend\Diactoros\Stream;
-
-use function base64_decode;
-
-class PixelResponse extends Response
-{
-    private const BASE_64_IMAGE = 'R0lGODlhAQABAJAAAP8AAAAAACH5BAUQAAAALAAAAAABAAEAAAICBAEAOw==';
-    private const CONTENT_TYPE = 'image/gif';
-
-    public function __construct(int $status = StatusCode::STATUS_OK, array $headers = [])
-    {
-        $headers['content-type'] = self::CONTENT_TYPE;
-        parent::__construct($this->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/src/Response/QrCodeResponse.php b/module/Common/src/Response/QrCodeResponse.php
deleted file mode 100644
index 230ae08f..00000000
--- a/module/Common/src/Response/QrCodeResponse.php
+++ /dev/null
@@ -1,32 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace Shlinkio\Shlink\Common\Response;
-
-use Endroid\QrCode\QrCode;
-use Fig\Http\Message\StatusCodeInterface as StatusCode;
-use Psr\Http\Message\StreamInterface;
-use Zend\Diactoros\Response;
-use Zend\Diactoros\Stream;
-
-class QrCodeResponse extends Response
-{
-    use Response\InjectContentTypeTrait;
-
-    public function __construct(QrCode $qrCode, int $status = StatusCode::STATUS_OK, array $headers = [])
-    {
-        parent::__construct(
-            $this->createBody($qrCode),
-            $status,
-            $this->injectContentType($qrCode->getContentType(), $headers)
-        );
-    }
-
-    private function createBody(QrCode $qrCode): StreamInterface
-    {
-        $body = new Stream('php://temp', 'wb+');
-        $body->write($qrCode->get());
-        $body->rewind();
-        return $body;
-    }
-}
diff --git a/module/Common/src/Response/ResponseUtilsTrait.php b/module/Common/src/Response/ResponseUtilsTrait.php
deleted file mode 100644
index dee426fc..00000000
--- a/module/Common/src/Response/ResponseUtilsTrait.php
+++ /dev/null
@@ -1,30 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace Shlinkio\Shlink\Common\Response;
-
-use Fig\Http\Message\StatusCodeInterface as StatusCode;
-use finfo;
-use Psr\Http\Message\ResponseInterface;
-use Zend\Diactoros\Response;
-use Zend\Diactoros\Stream;
-use Zend\Stdlib\ArrayUtils;
-
-use const FILEINFO_MIME;
-
-trait ResponseUtilsTrait
-{
-    private function generateImageResponse(string $imagePath): ResponseInterface
-    {
-        return $this->generateBinaryResponse($imagePath);
-    }
-
-    private function generateBinaryResponse(string $path, array $extraHeaders = []): ResponseInterface
-    {
-        $body = new Stream($path);
-        return new Response($body, StatusCode::STATUS_OK, ArrayUtils::merge([
-            'Content-Type' => (new finfo(FILEINFO_MIME))->file($path),
-            'Content-Length' => (string) $body->getSize(),
-        ], $extraHeaders));
-    }
-}
diff --git a/module/Common/src/Rest/DataTransformerInterface.php b/module/Common/src/Rest/DataTransformerInterface.php
deleted file mode 100644
index 933f6cce..00000000
--- a/module/Common/src/Rest/DataTransformerInterface.php
+++ /dev/null
@@ -1,9 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace Shlinkio\Shlink\Common\Rest;
-
-interface DataTransformerInterface
-{
-    public function transform($value): array;
-}
diff --git a/module/Common/src/Template/Extension/TranslatorExtension.php b/module/Common/src/Template/Extension/TranslatorExtension.php
deleted file mode 100644
index 775bd909..00000000
--- a/module/Common/src/Template/Extension/TranslatorExtension.php
+++ /dev/null
@@ -1,25 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace Shlinkio\Shlink\Common\Template\Extension;
-
-use League\Plates\Engine;
-use League\Plates\Extension\ExtensionInterface;
-use Zend\I18n\Translator\TranslatorInterface;
-
-class TranslatorExtension implements ExtensionInterface
-{
-    /** @var TranslatorInterface */
-    private $translator;
-
-    public function __construct(TranslatorInterface $translator)
-    {
-        $this->translator = $translator;
-    }
-
-    public function register(Engine $engine): void
-    {
-        $engine->registerFunction('translate', [$this->translator, 'translate']);
-        $engine->registerFunction('locale', [$this->translator, 'getLocale']);
-    }
-}
diff --git a/module/Common/src/Util/DateRange.php b/module/Common/src/Util/DateRange.php
deleted file mode 100644
index 34c7b865..00000000
--- a/module/Common/src/Util/DateRange.php
+++ /dev/null
@@ -1,35 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace Shlinkio\Shlink\Common\Util;
-
-use Cake\Chronos\Chronos;
-
-final class DateRange
-{
-    /** @var Chronos|null */
-    private $startDate;
-    /** @var Chronos|null */
-    private $endDate;
-
-    public function __construct(?Chronos $startDate = null, ?Chronos $endDate = null)
-    {
-        $this->startDate = $startDate;
-        $this->endDate = $endDate;
-    }
-
-    public function getStartDate(): ?Chronos
-    {
-        return $this->startDate;
-    }
-
-    public function getEndDate(): ?Chronos
-    {
-        return $this->endDate;
-    }
-
-    public function isEmpty(): bool
-    {
-        return $this->startDate === null && $this->endDate === null;
-    }
-}
diff --git a/module/Common/src/Util/IpAddress.php b/module/Common/src/Util/IpAddress.php
deleted file mode 100644
index a71bac14..00000000
--- a/module/Common/src/Util/IpAddress.php
+++ /dev/null
@@ -1,72 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace Shlinkio\Shlink\Common\Util;
-
-use Shlinkio\Shlink\Common\Exception\InvalidArgumentException;
-
-use function count;
-use function explode;
-use function implode;
-use function sprintf;
-use function trim;
-
-final class IpAddress
-{
-    private const IPV4_PARTS_COUNT = 4;
-    private const OBFUSCATED_OCTET = '0';
-    public const LOCALHOST = '127.0.0.1';
-
-    /** @var string */
-    private $firstOctet;
-    /** @var string */
-    private $secondOctet;
-    /** @var string */
-    private $thirdOctet;
-    /** @var string */
-    private $fourthOctet;
-
-    private function __construct(string $firstOctet, string $secondOctet, string $thirdOctet, string $fourthOctet)
-    {
-        $this->firstOctet = $firstOctet;
-        $this->secondOctet = $secondOctet;
-        $this->thirdOctet = $thirdOctet;
-        $this->fourthOctet = $fourthOctet;
-    }
-
-    /**
-     * @param string $address
-     * @return IpAddress
-     * @throws InvalidArgumentException
-     */
-    public static function fromString(string $address): self
-    {
-        $address = trim($address);
-        $parts = explode('.', $address);
-        if (count($parts) !== self::IPV4_PARTS_COUNT) {
-            throw new InvalidArgumentException(sprintf('Provided IP "%s" is invalid', $address));
-        }
-
-        return new self(...$parts);
-    }
-
-    public function getObfuscatedCopy(): self
-    {
-        return new self(
-            $this->firstOctet,
-            $this->secondOctet,
-            $this->thirdOctet,
-            self::OBFUSCATED_OCTET
-        );
-    }
-
-    public function __toString(): string
-    {
-        return implode('.', [
-            $this->firstOctet,
-            $this->secondOctet,
-            $this->thirdOctet,
-            $this->fourthOctet,
-        ]);
-    }
-}
diff --git a/module/Common/src/Util/StringUtilsTrait.php b/module/Common/src/Util/StringUtilsTrait.php
deleted file mode 100644
index 853ba7b8..00000000
--- a/module/Common/src/Util/StringUtilsTrait.php
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace Shlinkio\Shlink\Common\Util;
-
-use function random_int;
-use function sprintf;
-use function strlen;
-
-trait StringUtilsTrait
-{
-    private function generateRandomString(int $length = 10): string
-    {
-        $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
-        $charactersLength = strlen($characters);
-        $randomString = '';
-        for ($i = 0; $i < $length; $i++) {
-            $randomString .= $characters[random_int(0, $charactersLength - 1)];
-        }
-
-        return $randomString;
-    }
-
-    private function generateV4Uuid(): string
-    {
-        return sprintf(
-            '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
-            // 32 bits for "time_low"
-            random_int(0, 0xffff),
-            random_int(0, 0xffff),
-            // 16 bits for "time_mid"
-            random_int(0, 0xffff),
-            // 16 bits for "time_hi_and_version",
-            // four most significant bits holds version number 4
-            random_int(0, 0x0fff) | 0x4000,
-            // 16 bits, 8 bits for "clk_seq_hi_res",
-            // 8 bits for "clk_seq_low",
-            // two most significant bits holds zero and one for variant DCE1.1
-            random_int(0, 0x3fff) | 0x8000,
-            // 48 bits for "node"
-            random_int(0, 0xffff),
-            random_int(0, 0xffff),
-            random_int(0, 0xffff)
-        );
-    }
-}
diff --git a/module/Common/src/Validation/InputFactoryTrait.php b/module/Common/src/Validation/InputFactoryTrait.php
deleted file mode 100644
index 71d92818..00000000
--- a/module/Common/src/Validation/InputFactoryTrait.php
+++ /dev/null
@@ -1,35 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace Shlinkio\Shlink\Common\Validation;
-
-use Zend\Filter;
-use Zend\InputFilter\Input;
-use Zend\Validator;
-
-trait InputFactoryTrait
-{
-    private function createInput($name, $required = true): Input
-    {
-        $input = new Input($name);
-        $input->setRequired($required)
-              ->getFilterChain()->attach(new Filter\StripTags())
-                                ->attach(new Filter\StringTrim());
-        return $input;
-    }
-
-    private function createBooleanInput(string $name, bool $required = true): Input
-    {
-        $input = $this->createInput($name, $required);
-        $input->getFilterChain()->attach(new Filter\Boolean());
-        $input->getValidatorChain()->attach(new Validator\NotEmpty(['type' => [
-            Validator\NotEmpty::OBJECT,
-            Validator\NotEmpty::SPACE,
-            Validator\NotEmpty::NULL,
-            Validator\NotEmpty::EMPTY_ARRAY,
-            Validator\NotEmpty::STRING,
-        ]]));
-
-        return $input;
-    }
-}
diff --git a/module/Common/src/Validation/SluggerFilter.php b/module/Common/src/Validation/SluggerFilter.php
deleted file mode 100644
index 9387e85a..00000000
--- a/module/Common/src/Validation/SluggerFilter.php
+++ /dev/null
@@ -1,31 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace Shlinkio\Shlink\Common\Validation;
-
-use Cocur\Slugify;
-use Zend\Filter\Exception;
-use Zend\Filter\FilterInterface;
-
-class SluggerFilter implements FilterInterface
-{
-    /** @var Slugify\SlugifyInterface */
-    private $slugger;
-
-    public function __construct(?Slugify\SlugifyInterface $slugger = null)
-    {
-        $this->slugger = $slugger ?: new Slugify\Slugify(['lowercase' => false]);
-    }
-
-    /**
-     * Returns the result of filtering $value
-     *
-     * @param  mixed $value
-     * @throws Exception\RuntimeException If filtering $value is impossible
-     * @return mixed
-     */
-    public function filter($value)
-    {
-        return ! empty($value) ? $this->slugger->slugify($value) : null;
-    }
-}
diff --git a/module/Common/test/Cache/CacheFactoryTest.php b/module/Common/test/Cache/CacheFactoryTest.php
deleted file mode 100644
index 9575befc..00000000
--- a/module/Common/test/Cache/CacheFactoryTest.php
+++ /dev/null
@@ -1,62 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace ShlinkioTest\Shlink\Common\Cache;
-
-use Doctrine\Common\Cache;
-use PHPUnit\Framework\TestCase;
-use Predis\ClientInterface;
-use Prophecy\Prophecy\ObjectProphecy;
-use Psr\Container\ContainerInterface;
-use Shlinkio\Shlink\Common\Cache\CacheFactory;
-use Shlinkio\Shlink\Common\Cache\RedisFactory;
-
-class CacheFactoryTest extends TestCase
-{
-    /** @var ObjectProphecy */
-    private $container;
-
-    public function setUp(): void
-    {
-        $this->container = $this->prophesize(ContainerInterface::class);
-    }
-
-    /**
-     * @test
-     * @dataProvider provideCacheConfig
-     */
-    public function expectedCacheAdapterIsReturned(
-        array $config,
-        string $expectedAdapterClass,
-        string $expectedNamespace,
-        ?callable $apcuEnabled = null
-    ): void {
-        $factory = new CacheFactory($apcuEnabled);
-
-        $getConfig = $this->container->get('config')->willReturn($config);
-        $getRedis = $this->container->get(RedisFactory::SERVICE_NAME)->willReturn(
-            $this->prophesize(ClientInterface::class)->reveal()
-        );
-
-        $cache = $factory($this->container->reveal());
-
-        $this->assertInstanceOf($expectedAdapterClass, $cache);
-        $this->assertEquals($expectedNamespace, $cache->getNamespace());
-        $getConfig->shouldHaveBeenCalledOnce();
-        $getRedis->shouldHaveBeenCalledTimes($expectedAdapterClass === Cache\PredisCache::class ? 1 :0);
-    }
-
-    public function provideCacheConfig(): iterable
-    {
-        yield 'debug true' => [['debug' => true], Cache\ArrayCache::class, ''];
-        yield 'debug false' => [['debug' => false], Cache\ApcuCache::class, ''];
-        yield 'no debug' => [[], Cache\ApcuCache::class, ''];
-        yield 'with redis' => [['cache' => [
-            'namespace' => $namespace = 'some_namespace',
-            'redis' => [],
-        ]], Cache\PredisCache::class, $namespace];
-        yield 'debug false and no apcu' => [['debug' => false], Cache\ArrayCache::class, '', function () {
-            return false;
-        }];
-    }
-}
diff --git a/module/Common/test/Cache/RedisFactoryTest.php b/module/Common/test/Cache/RedisFactoryTest.php
deleted file mode 100644
index 67acba2c..00000000
--- a/module/Common/test/Cache/RedisFactoryTest.php
+++ /dev/null
@@ -1,79 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace ShlinkioTest\Shlink\Common\Cache;
-
-use PHPUnit\Framework\TestCase;
-use Predis\Connection\Aggregate\PredisCluster;
-use Predis\Connection\Aggregate\RedisCluster;
-use Prophecy\Prophecy\ObjectProphecy;
-use Psr\Container\ContainerInterface;
-use Shlinkio\Shlink\Common\Cache\RedisFactory;
-
-class RedisFactoryTest extends TestCase
-{
-    /** @var RedisFactory */
-    private $factory;
-    /** @var ObjectProphecy */
-    private $container;
-
-    public function setUp(): void
-    {
-        $this->container = $this->prophesize(ContainerInterface::class);
-        $this->factory = new RedisFactory();
-    }
-
-    /**
-     * @test
-     * @dataProvider provideRedisConfig
-     */
-    public function createsRedisClientBasedOnRedisConfig(?array $config, string $expectedCluster): void
-    {
-        $getConfig = $this->container->get('config')->willReturn([
-            'redis' => $config,
-        ]);
-
-        $client = ($this->factory)($this->container->reveal());
-
-        $getConfig->shouldHaveBeenCalledOnce();
-        $this->assertInstanceOf($expectedCluster, $client->getOptions()->cluster);
-    }
-
-    /**
-     * @test
-     * @dataProvider provideRedisConfig
-     */
-    public function createsRedisClientBasedOnCacheConfig(?array $config, string $expectedCluster): void
-    {
-        $getConfig = $this->container->get('config')->willReturn([
-            'cache' => [
-                'redis' => $config,
-            ],
-        ]);
-
-        $client = ($this->factory)($this->container->reveal());
-
-        $getConfig->shouldHaveBeenCalledOnce();
-        $this->assertInstanceOf($expectedCluster, $client->getOptions()->cluster);
-    }
-
-    public function provideRedisConfig(): iterable
-    {
-        yield 'no config' => [null, PredisCluster::class];
-        yield 'single server as string' => [[
-            'servers' => 'tcp://127.0.0.1:6379',
-        ], PredisCluster::class];
-        yield 'single server as array' => [[
-            'servers' => ['tcp://127.0.0.1:6379'],
-        ], PredisCluster::class];
-        yield 'cluster of servers' => [[
-            'servers' => ['tcp://1.1.1.1:6379', 'tcp://2.2.2.2:6379'],
-        ], RedisCluster::class];
-        yield 'empty cluster of servers' => [[
-            'servers' => [],
-        ], PredisCluster::class];
-        yield 'cluster of servers as string' => [[
-            'servers' => 'tcp://1.1.1.1:6379,tcp://2.2.2.2:6379',
-        ], RedisCluster::class];
-    }
-}
diff --git a/module/Common/test/ConfigProviderTest.php b/module/Common/test/ConfigProviderTest.php
deleted file mode 100644
index c253483e..00000000
--- a/module/Common/test/ConfigProviderTest.php
+++ /dev/null
@@ -1,27 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace ShlinkioTest\Shlink\Common;
-
-use PHPUnit\Framework\TestCase;
-use Shlinkio\Shlink\Common\ConfigProvider;
-
-class ConfigProviderTest extends TestCase
-{
-    /** @var ConfigProvider */
-    private $configProvider;
-
-    public function setUp(): void
-    {
-        $this->configProvider = new ConfigProvider();
-    }
-
-    /** @test */
-    public function configIsReturned()
-    {
-        $config = $this->configProvider->__invoke();
-
-        $this->assertArrayHasKey('dependencies', $config);
-        $this->assertArrayHasKey('plates', $config);
-    }
-}
diff --git a/module/Common/test/Doctrine/ConnectionFactoryTest.php b/module/Common/test/Doctrine/ConnectionFactoryTest.php
deleted file mode 100644
index a89ef79c..00000000
--- a/module/Common/test/Doctrine/ConnectionFactoryTest.php
+++ /dev/null
@@ -1,44 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace ShlinkioTest\Shlink\Common\Doctrine;
-
-use Doctrine\DBAL\Connection;
-use Doctrine\ORM\EntityManager;
-use Doctrine\ORM\EntityManagerInterface;
-use PHPUnit\Framework\TestCase;
-use Prophecy\Prophecy\ObjectProphecy;
-use Psr\Container\ContainerInterface;
-use Shlinkio\Shlink\Common\Doctrine\ConnectionFactory;
-
-class ConnectionFactoryTest extends TestCase
-{
-    /** @var ConnectionFactory */
-    private $factory;
-    /** @var ObjectProphecy */
-    private $container;
-    /** @var ObjectProphecy */
-    private $em;
-
-    public function setUp(): void
-    {
-        $this->container = $this->prophesize(ContainerInterface::class);
-        $this->em = $this->prophesize(EntityManagerInterface::class);
-        $this->container->get(EntityManager::class)->willReturn($this->em->reveal());
-
-        $this->factory = new ConnectionFactory();
-    }
-
-    /** @test */
-    public function properServiceFallbackOccursWhenInvoked(): void
-    {
-        $connection = $this->prophesize(Connection::class)->reveal();
-        $getConnection = $this->em->getConnection()->willReturn($connection);
-
-        $result = ($this->factory)($this->container->reveal());
-
-        $this->assertSame($connection, $result);
-        $getConnection->shouldHaveBeenCalledOnce();
-        $this->container->get(EntityManager::class)->shouldHaveBeenCalledOnce();
-    }
-}
diff --git a/module/Common/test/Doctrine/EntityManagerFactoryTest.php b/module/Common/test/Doctrine/EntityManagerFactoryTest.php
deleted file mode 100644
index 419c7ffd..00000000
--- a/module/Common/test/Doctrine/EntityManagerFactoryTest.php
+++ /dev/null
@@ -1,44 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace ShlinkioTest\Shlink\Common\Doctrine;
-
-use Doctrine\ORM\EntityManager;
-use PHPUnit\Framework\TestCase;
-use Shlinkio\Shlink\Common\Doctrine\EntityManagerFactory;
-use Shlinkio\Shlink\Common\Doctrine\Type\ChronosDateTimeType;
-use Zend\ServiceManager\ServiceManager;
-
-class EntityManagerFactoryTest extends TestCase
-{
-    /** @var EntityManagerFactory */
-    private $factory;
-
-    public function setUp(): void
-    {
-        $this->factory = new EntityManagerFactory();
-    }
-
-    /** @test */
-    public function serviceIsCreated(): void
-    {
-        $sm = new ServiceManager(['services' => [
-            'config' => [
-                'debug' => true,
-                'entity_manager' => [
-                    'orm' => [
-                        'types' => [
-                            ChronosDateTimeType::CHRONOS_DATETIME => ChronosDateTimeType::class,
-                        ],
-                    ],
-                    'connection' => [
-                        'driver' => 'pdo_sqlite',
-                    ],
-                ],
-            ],
-        ]]);
-
-        $em = ($this->factory)($sm, EntityManager::class);
-        $this->assertInstanceOf(EntityManager::class, $em);
-    }
-}
diff --git a/module/Common/test/Doctrine/NoDbNameConnectionFactoryTest.php b/module/Common/test/Doctrine/NoDbNameConnectionFactoryTest.php
deleted file mode 100644
index d8f58f8e..00000000
--- a/module/Common/test/Doctrine/NoDbNameConnectionFactoryTest.php
+++ /dev/null
@@ -1,56 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace ShlinkioTest\Shlink\Common\Doctrine;
-
-use Doctrine\DBAL\Connection;
-use Doctrine\DBAL\Driver;
-use PHPUnit\Framework\TestCase;
-use Prophecy\Prophecy\ObjectProphecy;
-use Psr\Container\ContainerInterface;
-use Shlinkio\Shlink\Common\Doctrine\NoDbNameConnectionFactory;
-
-class NoDbNameConnectionFactoryTest extends TestCase
-{
-    /** @var NoDbNameConnectionFactory */
-    private $factory;
-    /** @var ObjectProphecy */
-    private $container;
-    /** @var ObjectProphecy */
-    private $originalConn;
-
-    public function setUp(): void
-    {
-        $this->container = $this->prophesize(ContainerInterface::class);
-        $this->originalConn = $this->prophesize(Connection::class);
-        $this->container->get(Connection::class)->willReturn($this->originalConn->reveal());
-
-        $this->factory = new NoDbNameConnectionFactory();
-    }
-
-    /** @test */
-    public function createsNewConnectionRemovingDbNameFromOriginalConnectionParams(): void
-    {
-        $params = [
-            'username' => 'foo',
-            'password' => 'bar',
-            'dbname' => 'something',
-        ];
-        $getOriginalParams = $this->originalConn->getParams()->willReturn($params);
-        $getOriginalDriver = $this->originalConn->getDriver()->willReturn($this->prophesize(Driver::class)->reveal());
-        $getOriginalConfig = $this->originalConn->getConfiguration()->willReturn(null);
-        $getOriginalEvents = $this->originalConn->getEventManager()->willReturn(null);
-
-        $conn = ($this->factory)($this->container->reveal());
-
-        $this->assertEquals([
-            'username' => 'foo',
-            'password' => 'bar',
-        ], $conn->getParams());
-        $getOriginalParams->shouldHaveBeenCalledOnce();
-        $getOriginalDriver->shouldHaveBeenCalledOnce();
-        $getOriginalConfig->shouldHaveBeenCalledOnce();
-        $getOriginalEvents->shouldHaveBeenCalledOnce();
-        $this->container->get(Connection::class)->shouldHaveBeenCalledOnce();
-    }
-}
diff --git a/module/Common/test/Doctrine/ReopeningEntityManagerDelegatorTest.php b/module/Common/test/Doctrine/ReopeningEntityManagerDelegatorTest.php
deleted file mode 100644
index 1193541b..00000000
--- a/module/Common/test/Doctrine/ReopeningEntityManagerDelegatorTest.php
+++ /dev/null
@@ -1,28 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace ShlinkioTest\Shlink\Common\Doctrine;
-
-use Doctrine\ORM\EntityManagerInterface;
-use PHPUnit\Framework\TestCase;
-use ReflectionObject;
-use Shlinkio\Shlink\Common\Doctrine\ReopeningEntityManagerDelegator;
-use Zend\ServiceManager\ServiceManager;
-
-class ReopeningEntityManagerDelegatorTest extends TestCase
-{
-    /** @test */
-    public function decoratesEntityManagerFromCallback(): void
-    {
-        $em = $this->prophesize(EntityManagerInterface::class)->reveal();
-        $result = (new ReopeningEntityManagerDelegator())(new ServiceManager(), '', function () use ($em) {
-            return $em;
-        });
-
-        $ref = new ReflectionObject($result);
-        $prop = $ref->getProperty('wrapped');
-        $prop->setAccessible(true);
-
-        $this->assertSame($em, $prop->getValue($result));
-    }
-}
diff --git a/module/Common/test/Doctrine/ReopeningEntityManagerTest.php b/module/Common/test/Doctrine/ReopeningEntityManagerTest.php
deleted file mode 100644
index 74e8d260..00000000
--- a/module/Common/test/Doctrine/ReopeningEntityManagerTest.php
+++ /dev/null
@@ -1,80 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace ShlinkioTest\Shlink\Common\Doctrine;
-
-use Doctrine\Common\EventManager;
-use Doctrine\DBAL\Connection;
-use Doctrine\ORM\Configuration;
-use Doctrine\ORM\EntityManagerInterface;
-use PHPUnit\Framework\TestCase;
-use Prophecy\Argument;
-use Prophecy\Prophecy\ObjectProphecy;
-use Shlinkio\Shlink\Common\Doctrine\ReopeningEntityManager;
-use stdClass;
-
-class ReopeningEntityManagerTest extends TestCase
-{
-    /** @var ReopeningEntityManager */
-    private $decoratorEm;
-    /** @var ObjectProphecy */
-    private $wrapped;
-
-    public function setUp(): void
-    {
-        $this->wrapped = $this->prophesize(EntityManagerInterface::class);
-        $this->wrapped->getConnection()->willReturn($this->prophesize(Connection::class));
-        $this->wrapped->getConfiguration()->willReturn($this->prophesize(Configuration::class));
-        $this->wrapped->getEventManager()->willReturn($this->prophesize(EventManager::class));
-
-        $wrappedMock = $this->wrapped->reveal();
-        $this->decoratorEm = new ReopeningEntityManager($wrappedMock, function () use ($wrappedMock) {
-            return $wrappedMock;
-        });
-    }
-
-    /**
-     * @test
-     * @dataProvider provideMethodNames
-     */
-    public function wrappedInstanceIsTransparentlyCalledWhenItIsNotClosed(string $methodName): void
-    {
-        $method = $this->wrapped->__call($methodName, [Argument::cetera()])->willReturnArgument();
-        $isOpen = $this->wrapped->isOpen()->willReturn(true);
-
-        $this->decoratorEm->{$methodName}(new stdClass());
-
-        $method->shouldHaveBeenCalledOnce();
-        $isOpen->shouldHaveBeenCalledOnce();
-        $this->wrapped->getConnection()->shouldNotHaveBeenCalled();
-        $this->wrapped->getConfiguration()->shouldNotHaveBeenCalled();
-        $this->wrapped->getEventManager()->shouldNotHaveBeenCalled();
-    }
-
-    /**
-     * @test
-     * @dataProvider provideMethodNames
-     */
-    public function wrappedInstanceIsRecreatedWhenItIsClosed(string $methodName): void
-    {
-        $method = $this->wrapped->__call($methodName, [Argument::cetera()])->willReturnArgument();
-        $isOpen = $this->wrapped->isOpen()->willReturn(false);
-
-        $this->decoratorEm->{$methodName}(new stdClass());
-
-        $method->shouldHaveBeenCalledOnce();
-        $isOpen->shouldHaveBeenCalledOnce();
-        $this->wrapped->getConnection()->shouldHaveBeenCalledOnce();
-        $this->wrapped->getConfiguration()->shouldHaveBeenCalledOnce();
-        $this->wrapped->getEventManager()->shouldHaveBeenCalledOnce();
-    }
-
-    public function provideMethodNames(): iterable
-    {
-        yield 'flush' => ['flush'];
-        yield 'persist' => ['persist'];
-        yield 'remove' => ['remove'];
-        yield 'refresh' => ['refresh'];
-        yield 'merge' => ['merge'];
-    }
-}
diff --git a/module/Common/test/Doctrine/Type/ChronosDateTimeTypeTest.php b/module/Common/test/Doctrine/Type/ChronosDateTimeTypeTest.php
deleted file mode 100644
index b86547cd..00000000
--- a/module/Common/test/Doctrine/Type/ChronosDateTimeTypeTest.php
+++ /dev/null
@@ -1,88 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace ShlinkioTest\Shlink\Common\Doctrine\Type;
-
-use Cake\Chronos\Chronos;
-use DateTime;
-use DateTimeImmutable;
-use DateTimeInterface;
-use Doctrine\DBAL\Platforms\AbstractPlatform;
-use Doctrine\DBAL\Types\ConversionException;
-use Doctrine\DBAL\Types\Type;
-use PHPUnit\Framework\TestCase;
-use Shlinkio\Shlink\Common\Doctrine\Type\ChronosDateTimeType;
-use stdClass;
-
-class ChronosDateTimeTypeTest extends TestCase
-{
-    /** @var ChronosDateTimeType */
-    private $type;
-
-    public function setUp(): void
-    {
-        if (! Type::hasType(ChronosDateTimeType::CHRONOS_DATETIME)) {
-            Type::addType(ChronosDateTimeType::CHRONOS_DATETIME, ChronosDateTimeType::class);
-        }
-
-        $this->type = Type::getType(ChronosDateTimeType::CHRONOS_DATETIME);
-    }
-
-    /** @test */
-    public function nameIsReturned(): void
-    {
-        $this->assertEquals(ChronosDateTimeType::CHRONOS_DATETIME, $this->type->getName());
-    }
-
-    /**
-     * @test
-     * @dataProvider provideValues
-     */
-    public function valueIsConverted(?string $value, ?string $expected): void
-    {
-        $platform = $this->prophesize(AbstractPlatform::class);
-        $platform->getDateTimeFormatString()->willReturn('Y-m-d H:i:s');
-
-        $result = $this->type->convertToPHPValue($value, $platform->reveal());
-
-        if ($expected === null) {
-            $this->assertNull($result);
-        } else {
-            $this->assertInstanceOf($expected, $result);
-        }
-    }
-
-    public function provideValues(): iterable
-    {
-        yield 'null date' => [null, null];
-        yield 'human friendly date' => ['now', Chronos::class];
-        yield 'numeric date' => ['2017-01-01', Chronos::class];
-    }
-
-    /**
-     * @test
-     * @dataProvider providePhpValues
-     */
-    public function valueIsConvertedToDatabaseFormat(?DateTimeInterface $value, ?string $expected): void
-    {
-        $platform = $this->prophesize(AbstractPlatform::class);
-        $platform->getDateTimeFormatString()->willReturn('Y-m-d');
-
-        $this->assertEquals($expected, $this->type->convertToDatabaseValue($value, $platform->reveal()));
-    }
-
-    public function providePhpValues(): iterable
-    {
-        yield 'null date' => [null, null];
-        yield 'DateTimeImmutable date' => [new DateTimeImmutable('2017-01-01'), '2017-01-01'];
-        yield 'Chronos date' => [Chronos::parse('2017-02-01'), '2017-02-01'];
-        yield 'DateTime date' => [new DateTime('2017-03-01'), '2017-03-01'];
-    }
-
-    /** @test */
-    public function exceptionIsThrownIfInvalidValueIsParsedToDatabase(): void
-    {
-        $this->expectException(ConversionException::class);
-        $this->type->convertToDatabaseValue(new stdClass(), $this->prophesize(AbstractPlatform::class)->reveal());
-    }
-}
diff --git a/module/Common/test/Factory/DottedAccessConfigAbstractFactoryTest.php b/module/Common/test/Factory/DottedAccessConfigAbstractFactoryTest.php
deleted file mode 100644
index f9d2c80c..00000000
--- a/module/Common/test/Factory/DottedAccessConfigAbstractFactoryTest.php
+++ /dev/null
@@ -1,78 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace ShlinkioTest\Shlink\Common\Factory;
-
-use PHPUnit\Framework\TestCase;
-use Shlinkio\Shlink\Common\Exception\InvalidArgumentException;
-use Shlinkio\Shlink\Common\Factory\DottedAccessConfigAbstractFactory;
-use Zend\ServiceManager\Exception\ServiceNotCreatedException;
-use Zend\ServiceManager\ServiceManager;
-
-class DottedAccessConfigAbstractFactoryTest extends TestCase
-{
-    /** @var DottedAccessConfigAbstractFactory */
-    private $factory;
-
-    public function setUp(): void
-    {
-        $this->factory = new DottedAccessConfigAbstractFactory();
-    }
-
-    /**
-     * @test
-     * @dataProvider provideDotNames
-     */
-    public function canCreateOnlyServicesWithDot(string $serviceName, bool $canCreate): void
-    {
-        $this->assertEquals($canCreate, $this->factory->canCreate(new ServiceManager(), $serviceName));
-    }
-
-    public function provideDotNames(): iterable
-    {
-        yield 'with a valid service' => ['foo.bar', true];
-        yield 'with another valid service' => ['config.something', true];
-        yield 'with an invalid service' => ['config_something', false];
-        yield 'with another invalid service' => ['foo', false];
-    }
-
-    /** @test */
-    public function throwsExceptionWhenFirstPartOfTheServiceIsNotRegistered()
-    {
-        $this->expectException(ServiceNotCreatedException::class);
-        $this->expectExceptionMessage(
-            'Defined service "foo" could not be found in container after resolving dotted expression "foo.bar"'
-        );
-
-        $this->factory->__invoke(new ServiceManager(), 'foo.bar');
-    }
-
-    /** @test */
-    public function dottedNotationIsRecursivelyResolvedUntilLastValueIsFoundAndReturned()
-    {
-        $expected = 'this is the result';
-
-        $result = $this->factory->__invoke(new ServiceManager(['services' => [
-            'foo' => [
-                'bar' => ['baz' => $expected],
-            ],
-        ]]), 'foo.bar.baz');
-
-        $this->assertEquals($expected, $result);
-    }
-
-    /** @test */
-    public function exceptionIsThrownIfAnyStepCannotBeResolved()
-    {
-        $this->expectException(InvalidArgumentException::class);
-        $this->expectExceptionMessage(
-            'The key "baz" provided in the dotted notation could not be found in the array service'
-        );
-
-        $this->factory->__invoke(new ServiceManager(['services' => [
-            'foo' => [
-                'bar' => ['something' => 123],
-            ],
-        ]]), 'foo.bar.baz');
-    }
-}
diff --git a/module/Common/test/I18n/TranslatorFactoryTest.php b/module/Common/test/I18n/TranslatorFactoryTest.php
deleted file mode 100644
index 756a3991..00000000
--- a/module/Common/test/I18n/TranslatorFactoryTest.php
+++ /dev/null
@@ -1,29 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace ShlinkioTest\Shlink\Common\I18n;
-
-use PHPUnit\Framework\TestCase;
-use Shlinkio\Shlink\Common\I18n\TranslatorFactory;
-use Zend\I18n\Translator\Translator;
-use Zend\ServiceManager\ServiceManager;
-
-class TranslatorFactoryTest extends TestCase
-{
-    /** @var TranslatorFactory */
-    private $factory;
-
-    public function setUp(): void
-    {
-        $this->factory = new TranslatorFactory();
-    }
-
-    /** @test */
-    public function serviceIsCreated(): void
-    {
-        $instance = ($this->factory)(new ServiceManager(['services' => [
-            'config' => [],
-        ]]));
-        $this->assertInstanceOf(Translator::class, $instance);
-    }
-}
diff --git a/module/Common/test/Lock/RetryLockStoreDelegatorFactoryTest.php b/module/Common/test/Lock/RetryLockStoreDelegatorFactoryTest.php
deleted file mode 100644
index 4f98c47c..00000000
--- a/module/Common/test/Lock/RetryLockStoreDelegatorFactoryTest.php
+++ /dev/null
@@ -1,41 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace ShlinkioTest\Shlink\Common\Lock;
-
-use PHPUnit\Framework\TestCase;
-use Prophecy\Prophecy\ObjectProphecy;
-use ReflectionObject;
-use Shlinkio\Shlink\Common\Lock\RetryLockStoreDelegatorFactory;
-use Symfony\Component\Lock\StoreInterface;
-use Zend\ServiceManager\ServiceManager;
-
-class RetryLockStoreDelegatorFactoryTest extends TestCase
-{
-    /** @var RetryLockStoreDelegatorFactory */
-    private $delegator;
-    /** @var ObjectProphecy */
-    private $originalStore;
-
-    public function setUp(): void
-    {
-        $this->originalStore = $this->prophesize(StoreInterface::class)->reveal();
-        $this->delegator = new RetryLockStoreDelegatorFactory();
-    }
-
-    /** @test */
-    public function originalStoreIsWrappedInRetryStore(): void
-    {
-        $callback = function () {
-            return $this->originalStore;
-        };
-
-        $result = ($this->delegator)(new ServiceManager(), '', $callback);
-
-        $ref = new ReflectionObject($result);
-        $prop = $ref->getProperty('decorated');
-        $prop->setAccessible(true);
-
-        $this->assertSame($this->originalStore, $prop->getValue($result));
-    }
-}
diff --git a/module/Common/test/Logger/LoggerAwareDelegatorFactoryTest.php b/module/Common/test/Logger/LoggerAwareDelegatorFactoryTest.php
deleted file mode 100644
index 8723077b..00000000
--- a/module/Common/test/Logger/LoggerAwareDelegatorFactoryTest.php
+++ /dev/null
@@ -1,55 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace ShlinkioTest\Shlink\Common\Logger;
-
-use PHPUnit\Framework\Assert;
-use PHPUnit\Framework\TestCase;
-use Prophecy\Prophecy\ObjectProphecy;
-use Psr\Container\ContainerInterface;
-use Psr\Log;
-use Psr\Log\LoggerInterface;
-use Shlinkio\Shlink\Common\Logger\LoggerAwareDelegatorFactory;
-use stdClass;
-
-class LoggerAwareDelegatorFactoryTest extends TestCase
-{
-    /** @var LoggerAwareDelegatorFactory */
-    private $delegator;
-    /** @var ObjectProphecy */
-    private $container;
-
-    public function setUp(): void
-    {
-        $this->container = $this->prophesize(ContainerInterface::class);
-        $this->delegator = new LoggerAwareDelegatorFactory();
-    }
-
-    /**
-     * @test
-     * @dataProvider provideInstances
-     */
-    public function injectsLoggerOnInstanceWhenImplementingLoggerAware($instance, int $expectedCalls): void
-    {
-        $callback = function () use ($instance) {
-            return $instance;
-        };
-        $getLogger = $this->container->get(Log\LoggerInterface::class)->willReturn(new Log\NullLogger());
-
-        $result = ($this->delegator)($this->container->reveal(), '', $callback);
-
-        $this->assertSame($instance, $result);
-        $getLogger->shouldHaveBeenCalledTimes($expectedCalls);
-    }
-
-    public function provideInstances(): iterable
-    {
-        yield 'no logger aware' => [new stdClass(), 0];
-        yield 'logger aware' => [new class implements Log\LoggerAwareInterface {
-            public function setLogger(LoggerInterface $logger): void
-            {
-                Assert::assertInstanceOf(Log\NullLogger::class, $logger);
-            }
-        }, 1];
-    }
-}
diff --git a/module/Common/test/Logger/LoggerFactoryTest.php b/module/Common/test/Logger/LoggerFactoryTest.php
deleted file mode 100644
index ae20e161..00000000
--- a/module/Common/test/Logger/LoggerFactoryTest.php
+++ /dev/null
@@ -1,48 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace ShlinkioTest\Shlink\Common\Logger;
-
-use Monolog\Logger;
-use PHPUnit\Framework\TestCase;
-use Psr\Log\LoggerInterface;
-use Shlinkio\Shlink\Common\Logger\LoggerFactory;
-use Zend\ServiceManager\ServiceManager;
-
-class LoggerFactoryTest extends TestCase
-{
-    /** @var LoggerFactory */
-    private $factory;
-
-    public function setUp(): void
-    {
-        $this->factory = new LoggerFactory();
-    }
-
-    /** @test */
-    public function serviceIsCreated()
-    {
-        /** @var Logger $instance */
-        $instance = $this->factory->__invoke(new ServiceManager(), '');
-        $this->assertInstanceOf(LoggerInterface::class, $instance);
-        $this->assertEquals('Logger', $instance->getName());
-    }
-
-    /** @test */
-    public function nameIsSetFromOptions()
-    {
-        /** @var Logger $instance */
-        $instance = $this->factory->__invoke(new ServiceManager(), '', ['logger_name' => 'Foo']);
-        $this->assertInstanceOf(LoggerInterface::class, $instance);
-        $this->assertEquals('Foo', $instance->getName());
-    }
-
-    /** @test */
-    public function serviceNameOverwritesOptionsLoggerName()
-    {
-        /** @var Logger $instance */
-        $instance = $this->factory->__invoke(new ServiceManager(), 'Logger_Shlink', ['logger_name' => 'Foo']);
-        $this->assertInstanceOf(LoggerInterface::class, $instance);
-        $this->assertEquals('Shlink', $instance->getName());
-    }
-}
diff --git a/module/Common/test/Logger/Processor/ExceptionWithNewLineProcessorTest.php b/module/Common/test/Logger/Processor/ExceptionWithNewLineProcessorTest.php
deleted file mode 100644
index 60b30ce8..00000000
--- a/module/Common/test/Logger/Processor/ExceptionWithNewLineProcessorTest.php
+++ /dev/null
@@ -1,67 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace ShlinkioTest\Shlink\Common\Logger\Processor;
-
-use PHPUnit\Framework\TestCase;
-use Shlinkio\Shlink\Common\Logger\Processor\ExceptionWithNewLineProcessor;
-use Shlinkio\Shlink\Common\Util\StringUtilsTrait;
-
-use function Functional\map;
-use function range;
-
-use const PHP_EOL;
-
-class ExceptionWithNewLineProcessorTest extends TestCase
-{
-    use StringUtilsTrait;
-
-    /** @var ExceptionWithNewLineProcessor */
-    private $processor;
-
-    public function setUp(): void
-    {
-        $this->processor = new ExceptionWithNewLineProcessor();
-    }
-
-    /**
-     * @test
-     * @dataProvider provideNoPlaceholderRecords
-     */
-    public function keepsRecordAsIsWhenNoPlaceholderExists(array $record): void
-    {
-        $this->assertSame($record, ($this->processor)($record));
-    }
-
-    public function provideNoPlaceholderRecords(): iterable
-    {
-        return map(range(1, 5), function () {
-            return [['message' => $this->generateRandomString()]];
-        });
-    }
-
-    /**
-     * @test
-     * @dataProvider providePlaceholderRecords
-     */
-    public function properlyReplacesExceptionPlaceholderAddingNewLine(array $record, array $expected): void
-    {
-        $this->assertEquals($expected, ($this->processor)($record));
-    }
-
-    public function providePlaceholderRecords(): iterable
-    {
-        yield [
-            ['message' => 'Hello World with placeholder {e}'],
-            ['message' => 'Hello World with placeholder ' . PHP_EOL . '{e}'],
-        ];
-        yield [
-            ['message' => '{e} Shlink'],
-            ['message' => PHP_EOL . '{e} Shlink'],
-        ];
-        yield [
-            ['message' => 'Foo {e} bar'],
-            ['message' => 'Foo ' . PHP_EOL . '{e} bar'],
-        ];
-    }
-}
diff --git a/module/Common/test/Middleware/CloseDbConnectionMiddlewareTest.php b/module/Common/test/Middleware/CloseDbConnectionMiddlewareTest.php
deleted file mode 100644
index 2bf93a85..00000000
--- a/module/Common/test/Middleware/CloseDbConnectionMiddlewareTest.php
+++ /dev/null
@@ -1,72 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace ShlinkioTest\Shlink\Common\Middleware;
-
-use Doctrine\DBAL\Connection;
-use Doctrine\ORM\EntityManagerInterface;
-use PHPUnit\Framework\TestCase;
-use Prophecy\Prophecy\ObjectProphecy;
-use Psr\Http\Server\RequestHandlerInterface;
-use RuntimeException;
-use Shlinkio\Shlink\Common\Middleware\CloseDbConnectionMiddleware;
-use Zend\Diactoros\Response;
-use Zend\Diactoros\ServerRequest;
-
-class CloseDbConnectionMiddlewareTest extends TestCase
-{
-    /** @var CloseDbConnectionMiddleware */
-    private $middleware;
-    /** @var ObjectProphecy */
-    private $handler;
-    /** @var ObjectProphecy */
-    private $em;
-    /** @var ObjectProphecy */
-    private $conn;
-
-    public function setUp(): void
-    {
-        $this->handler = $this->prophesize(RequestHandlerInterface::class);
-        $this->em = $this->prophesize(EntityManagerInterface::class);
-        $this->conn = $this->prophesize(Connection::class);
-        $this->conn->close()->will(function () {
-        });
-        $this->em->getConnection()->willReturn($this->conn->reveal());
-        $this->em->clear()->will(function () {
-        });
-
-        $this->middleware = new CloseDbConnectionMiddleware($this->em->reveal());
-    }
-
-    /** @test */
-    public function connectionIsClosedWhenMiddlewareIsProcessed(): void
-    {
-        $req = new ServerRequest();
-        $resp = new Response();
-        $handle = $this->handler->handle($req)->willReturn($resp);
-
-        $result = $this->middleware->process($req, $this->handler->reveal());
-
-        $this->assertSame($result, $resp);
-        $this->em->getConnection()->shouldHaveBeenCalledOnce();
-        $this->conn->close()->shouldHaveBeenCalledOnce();
-        $this->em->clear()->shouldHaveBeenCalledOnce();
-        $handle->shouldHaveBeenCalledOnce();
-    }
-
-    /** @test */
-    public function connectionIsClosedEvenIfExceptionIsThrownOnInnerMiddlewares(): void
-    {
-        $req = new ServerRequest();
-        $expectedError = new RuntimeException();
-        $this->handler->handle($req)->willThrow($expectedError)
-                                    ->shouldBeCalledOnce();
-
-        $this->em->getConnection()->shouldBeCalledOnce();
-        $this->conn->close()->shouldBeCalledOnce();
-        $this->em->clear()->shouldBeCalledOnce();
-        $this->expectExceptionObject($expectedError);
-
-        $this->middleware->process($req, $this->handler->reveal());
-    }
-}
diff --git a/module/Common/test/Middleware/IpAddressMiddlewareFactoryTest.php b/module/Common/test/Middleware/IpAddressMiddlewareFactoryTest.php
deleted file mode 100644
index fdf81a35..00000000
--- a/module/Common/test/Middleware/IpAddressMiddlewareFactoryTest.php
+++ /dev/null
@@ -1,85 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace ShlinkioTest\Shlink\Common\Middleware;
-
-use PHPUnit\Framework\TestCase;
-use ReflectionObject;
-use Shlinkio\Shlink\Common\Middleware\IpAddressMiddlewareFactory;
-use Zend\ServiceManager\ServiceManager;
-
-class IpAddressMiddlewareFactoryTest extends TestCase
-{
-    private $factory;
-
-    public function setUp(): void
-    {
-        $this->factory = new IpAddressMiddlewareFactory();
-    }
-
-    /**
-     * @test
-     * @dataProvider provideConfigs
-     */
-    public function returnedInstanceIsProperlyConfigured(array $config, array $expectedHeadersToInspect): void
-    {
-        $instance = ($this->factory)(new ServiceManager(['services' => [
-            'config' => $config,
-        ]]));
-
-        $ref = new ReflectionObject($instance);
-        $checkProxyHeaders = $ref->getProperty('checkProxyHeaders');
-        $checkProxyHeaders->setAccessible(true);
-        $trustedProxies = $ref->getProperty('trustedProxies');
-        $trustedProxies->setAccessible(true);
-        $attributeName = $ref->getProperty('attributeName');
-        $attributeName->setAccessible(true);
-        $headersToInspect = $ref->getProperty('headersToInspect');
-        $headersToInspect->setAccessible(true);
-
-        $this->assertTrue($checkProxyHeaders->getValue($instance));
-        $this->assertEquals([], $trustedProxies->getValue($instance));
-        $this->assertEquals(IpAddressMiddlewareFactory::REQUEST_ATTR, $attributeName->getValue($instance));
-        $this->assertEquals($expectedHeadersToInspect, $headersToInspect->getValue($instance));
-    }
-
-    public function provideConfigs(): iterable
-    {
-        $defaultHeadersToInspect = [
-            'Forwarded',
-            'X-Forwarded-For',
-            'X-Forwarded',
-            'X-Cluster-Client-Ip',
-            'Client-Ip',
-        ];
-
-        yield 'no ip_address_resolution config' => [[], $defaultHeadersToInspect];
-        yield 'no headers_to_inspect config' => [['ip_address_resolution' => []], $defaultHeadersToInspect];
-        yield 'null headers_to_inspect' => [['ip_address_resolution' => [
-            'headers_to_inspect' => null,
-        ]], $defaultHeadersToInspect];
-        yield 'empty headers_to_inspect' => [['ip_address_resolution' => [
-            'headers_to_inspect' => [],
-        ]], $defaultHeadersToInspect];
-        yield 'some headers_to_inspect' => [['ip_address_resolution' => [
-            'headers_to_inspect' => [
-                'foo',
-                'bar',
-                'baz',
-            ],
-        ]], [
-            'foo',
-            'bar',
-            'baz',
-        ]];
-        yield 'some other headers_to_inspect' => [['ip_address_resolution' => [
-            'headers_to_inspect' => [
-                'something',
-                'something_else',
-            ],
-        ]], [
-            'something',
-            'something_else',
-        ]];
-    }
-}
diff --git a/module/Common/test/Middleware/LocaleMiddlewareTest.php b/module/Common/test/Middleware/LocaleMiddlewareTest.php
deleted file mode 100644
index e9145cba..00000000
--- a/module/Common/test/Middleware/LocaleMiddlewareTest.php
+++ /dev/null
@@ -1,63 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace ShlinkioTest\Shlink\Common\Middleware;
-
-use PHPUnit\Framework\TestCase;
-use Shlinkio\Shlink\Common\Middleware\LocaleMiddleware;
-use ShlinkioTest\Shlink\Common\Util\TestUtils;
-use Zend\Diactoros\ServerRequest;
-use Zend\I18n\Translator\Translator;
-
-class LocaleMiddlewareTest extends TestCase
-{
-    /** @var LocaleMiddleware */
-    private $middleware;
-    /** @var Translator */
-    private $translator;
-
-    public function setUp(): void
-    {
-        $this->translator = Translator::factory(['locale' => 'ru']);
-        $this->middleware = new LocaleMiddleware($this->translator);
-    }
-
-    /** @test */
-    public function whenNoHeaderIsPresentLocaleIsNotChanged(): void
-    {
-        $this->assertEquals('ru', $this->translator->getLocale());
-        $this->middleware->process(new ServerRequest(), TestUtils::createReqHandlerMock()->reveal());
-        $this->assertEquals('ru', $this->translator->getLocale());
-    }
-
-    /** @test */
-    public function whenTheHeaderIsPresentLocaleIsChanged(): void
-    {
-        $this->assertEquals('ru', $this->translator->getLocale());
-        $request = (new ServerRequest())->withHeader('Accept-Language', 'es');
-        $this->middleware->process($request, TestUtils::createReqHandlerMock()->reveal());
-        $this->assertEquals('es', $this->translator->getLocale());
-    }
-
-    /**
-     * @test
-     * @dataProvider provideLanguages
-     */
-    public function localeGetsNormalized(string $lang, string $expected): void
-    {
-        $handler = TestUtils::createReqHandlerMock();
-
-        $this->assertEquals('ru', $this->translator->getLocale());
-
-        $request = (new ServerRequest())->withHeader('Accept-Language', $lang);
-        $this->middleware->process($request, $handler->reveal());
-        $this->assertEquals($expected, $this->translator->getLocale());
-    }
-
-    public function provideLanguages(): iterable
-    {
-        yield 'language only' => ['ru', 'ru'];
-        yield 'country and language with underscore' => ['es_ES', 'es'];
-        yield 'country and language with dash' => ['en-US', 'en'];
-    }
-}
diff --git a/module/Common/test/Response/PixelResponseTest.php b/module/Common/test/Response/PixelResponseTest.php
deleted file mode 100644
index ae580472..00000000
--- a/module/Common/test/Response/PixelResponseTest.php
+++ /dev/null
@@ -1,25 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace ShlinkioTest\Shlink\Common\Response;
-
-use PHPUnit\Framework\TestCase;
-use Shlinkio\Shlink\Common\Response\PixelResponse;
-
-class PixelResponseTest extends TestCase
-{
-    /** @var PixelResponse */
-    private $resp;
-
-    public function setUp(): void
-    {
-        $this->resp = new PixelResponse();
-    }
-
-    /** @test */
-    public function responseHasGifTypeAndIsNotEmpty()
-    {
-        $this->assertEquals('image/gif', $this->resp->getHeaderLine('Content-Type'));
-        $this->assertNotEmpty((string) $this->resp->getBody());
-    }
-}
diff --git a/module/Common/test/Response/QrCodeResponseTest.php b/module/Common/test/Response/QrCodeResponseTest.php
deleted file mode 100644
index 7b413bc4..00000000
--- a/module/Common/test/Response/QrCodeResponseTest.php
+++ /dev/null
@@ -1,21 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace ShlinkioTest\Shlink\Common\Response;
-
-use Endroid\QrCode\QrCode;
-use PHPUnit\Framework\TestCase;
-use Shlinkio\Shlink\Common\Response\QrCodeResponse;
-
-class QrCodeResponseTest extends TestCase
-{
-    /** @test */
-    public function providedQrCoideIsSetAsBody()
-    {
-        $qrCode = new QrCode('Hello');
-        $resp = new QrCodeResponse($qrCode);
-
-        $this->assertEquals($qrCode->getContentType(), $resp->getHeaderLine('Content-Type'));
-        $this->assertEquals($qrCode->get(), (string) $resp->getBody());
-    }
-}
diff --git a/module/Common/test/Template/Extension/TranslatorExtensionTest.php b/module/Common/test/Template/Extension/TranslatorExtensionTest.php
deleted file mode 100644
index 690daabf..00000000
--- a/module/Common/test/Template/Extension/TranslatorExtensionTest.php
+++ /dev/null
@@ -1,36 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace ShlinkioTest\Shlink\Common\Template\Extension;
-
-use League\Plates\Engine;
-use PHPUnit\Framework\TestCase;
-use Prophecy\Argument;
-use Shlinkio\Shlink\Common\Template\Extension\TranslatorExtension;
-use Zend\I18n\Translator\Translator;
-
-class TranslatorExtensionTest extends TestCase
-{
-    /** @var TranslatorExtension */
-    private $extension;
-
-    public function setUp(): void
-    {
-        $this->extension = new TranslatorExtension($this->prophesize(Translator::class)->reveal());
-    }
-
-    /** @test */
-    public function properFunctionsAreReturned()
-    {
-        $engine = $this->prophesize(Engine::class);
-        $registerTranslate = $engine->registerFunction('translate', Argument::type('callable'))->will(function () {
-        });
-        $registerLocale = $engine->registerFunction('locale', Argument::type('array'))->will(function () {
-        });
-
-        $this->extension->register($engine->reveal());
-
-        $registerTranslate->shouldHaveBeenCalledOnce();
-        $registerLocale->shouldHaveBeenCalledOnce();
-    }
-}
diff --git a/module/Common/test/Util/DateRangeTest.php b/module/Common/test/Util/DateRangeTest.php
deleted file mode 100644
index d1716e8a..00000000
--- a/module/Common/test/Util/DateRangeTest.php
+++ /dev/null
@@ -1,52 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace ShlinkioTest\Shlink\Common\Util;
-
-use Cake\Chronos\Chronos;
-use PHPUnit\Framework\TestCase;
-use Shlinkio\Shlink\Common\Util\DateRange;
-
-class DateRangeTest extends TestCase
-{
-    /** @test */
-    public function defaultConstructorSetDatesToNull()
-    {
-        $range = new DateRange();
-        $this->assertNull($range->getStartDate());
-        $this->assertNull($range->getEndDate());
-        $this->assertTrue($range->isEmpty());
-    }
-
-    /** @test */
-    public function providedDatesAreSet()
-    {
-        $startDate = Chronos::now();
-        $endDate = Chronos::now();
-        $range = new DateRange($startDate, $endDate);
-        $this->assertSame($startDate, $range->getStartDate());
-        $this->assertSame($endDate, $range->getEndDate());
-        $this->assertFalse($range->isEmpty());
-    }
-
-    /**
-     * @test
-     * @dataProvider provideDates
-     */
-    public function isConsideredEmptyOnlyIfNoneOfTheDatesIsSet(
-        ?Chronos $startDate,
-        ?Chronos $endDate,
-        bool $isEmpty
-    ): void {
-        $range = new DateRange($startDate, $endDate);
-        $this->assertEquals($isEmpty, $range->isEmpty());
-    }
-
-    public function provideDates(): iterable
-    {
-        yield 'both are null' => [null, null, true];
-        yield 'start is null' => [null, Chronos::now(), false];
-        yield 'end is null' => [Chronos::now(), null, false];
-        yield 'none are null' => [Chronos::now(), Chronos::now(), false];
-    }
-}
diff --git a/module/Common/test/Util/StringUtilsTraitTest.php b/module/Common/test/Util/StringUtilsTraitTest.php
deleted file mode 100644
index ad1417aa..00000000
--- a/module/Common/test/Util/StringUtilsTraitTest.php
+++ /dev/null
@@ -1,44 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace ShlinkioTest\Shlink\Common\Util;
-
-use PHPUnit\Framework\TestCase;
-use Shlinkio\Shlink\Common\Util\StringUtilsTrait;
-
-use function Functional\map;
-use function range;
-use function strlen;
-
-class StringUtilsTraitTest extends TestCase
-{
-    use StringUtilsTrait;
-
-    /**
-     * @test
-     * @dataProvider provideLengths
-     */
-    public function generateRandomStringGeneratesStringOfProvidedLength(int $length): void
-    {
-        $this->assertEquals($length, strlen($this->generateRandomString($length)));
-    }
-
-    public function provideLengths(): array
-    {
-        return map(range(10, 50, 5), function (int $i) {
-            return [$i];
-        });
-    }
-
-    /** @test */
-    public function generatesUuidV4()
-    {
-        $uuidPattern = '/[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}/';
-
-        $this->assertRegExp($uuidPattern, $this->generateV4Uuid());
-        $this->assertRegExp($uuidPattern, $this->generateV4Uuid());
-        $this->assertRegExp($uuidPattern, $this->generateV4Uuid());
-        $this->assertRegExp($uuidPattern, $this->generateV4Uuid());
-        $this->assertRegExp($uuidPattern, $this->generateV4Uuid());
-    }
-}
diff --git a/module/Common/test/Util/TestUtils.php b/module/Common/test/Util/TestUtils.php
deleted file mode 100644
index aa1e0450..00000000
--- a/module/Common/test/Util/TestUtils.php
+++ /dev/null
@@ -1,37 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace ShlinkioTest\Shlink\Common\Util;
-
-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 createReqHandlerMock(?ResponseInterface $response = null, ?RequestInterface $request = null)
-    {
-        $argument = $request ?: Argument::any();
-        $delegate = static::getProphet()->prophesize(RequestHandlerInterface::class);
-        $delegate->handle($argument)->willReturn($response ?: new Response());
-
-        return $delegate;
-    }
-
-    /**
-     * @return Prophet
-     */
-    private static function getProphet()
-    {
-        if (static::$prophet === null) {
-            static::$prophet = new Prophet();
-        }
-
-        return static::$prophet;
-    }
-}
diff --git a/module/Common/test/Validation/SluggerFilterTest.php b/module/Common/test/Validation/SluggerFilterTest.php
deleted file mode 100644
index 0c02982f..00000000
--- a/module/Common/test/Validation/SluggerFilterTest.php
+++ /dev/null
@@ -1,44 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace ShlinkioTest\Shlink\Common\Validation;
-
-use Cocur\Slugify\SlugifyInterface;
-use PHPUnit\Framework\TestCase;
-use Prophecy\Prophecy\ObjectProphecy;
-use Shlinkio\Shlink\Common\Validation\SluggerFilter;
-
-class SluggerFilterTest extends TestCase
-{
-    /** @var SluggerFilter */
-    private $filter;
-    /** @var ObjectProphecy */
-    private $slugger;
-
-    public function setUp(): void
-    {
-        $this->slugger = $this->prophesize(SlugifyInterface::class);
-        $this->filter = new SluggerFilter($this->slugger->reveal());
-    }
-
-    /**
-     * @test
-     * @dataProvider provideValuesToFilter
-     */
-    public function providedValueIsFilteredAsExpected($providedValue, $expectedValue): void
-    {
-        $slugify = $this->slugger->slugify($providedValue)->willReturn('slug');
-
-        $result = $this->filter->filter($providedValue);
-
-        $this->assertEquals($expectedValue, $result);
-        $slugify->shouldHaveBeenCalledTimes($expectedValue !== null ? 1 : 0);
-    }
-
-    public function provideValuesToFilter(): iterable
-    {
-        yield 'null' => [null, null];
-        yield 'empty string' => ['', null];
-        yield 'not empty string' => ['foo', 'slug'];
-    }
-}
diff --git a/module/Core/test/Action/PixelActionTest.php b/module/Core/test/Action/PixelActionTest.php
index 483f8e4f..9fce8f0e 100644
--- a/module/Core/test/Action/PixelActionTest.php
+++ b/module/Core/test/Action/PixelActionTest.php
@@ -6,6 +6,7 @@ namespace ShlinkioTest\Shlink\Core\Action;
 use PHPUnit\Framework\TestCase;
 use Prophecy\Argument;
 use Prophecy\Prophecy\ObjectProphecy;
+use Psr\Http\Server\RequestHandlerInterface;
 use Shlinkio\Shlink\Common\Response\PixelResponse;
 use Shlinkio\Shlink\Core\Action\PixelAction;
 use Shlinkio\Shlink\Core\Action\RedirectAction;
@@ -13,7 +14,6 @@ use Shlinkio\Shlink\Core\Entity\ShortUrl;
 use Shlinkio\Shlink\Core\Options\AppOptions;
 use Shlinkio\Shlink\Core\Service\UrlShortener;
 use Shlinkio\Shlink\Core\Service\VisitsTracker;
-use ShlinkioTest\Shlink\Common\Util\TestUtils;
 use Zend\Diactoros\ServerRequest;
 
 class PixelActionTest extends TestCase
@@ -38,7 +38,7 @@ class PixelActionTest extends TestCase
     }
 
     /** @test */
-    public function imageIsReturned()
+    public function imageIsReturned(): void
     {
         $shortCode = 'abc123';
         $this->urlShortener->shortCodeToUrl($shortCode)->willReturn(
@@ -47,7 +47,7 @@ class PixelActionTest extends TestCase
         $this->visitTracker->track(Argument::cetera())->shouldBeCalledOnce();
 
         $request = (new ServerRequest())->withAttribute('shortCode', $shortCode);
-        $response = $this->action->process($request, TestUtils::createReqHandlerMock()->reveal());
+        $response = $this->action->process($request, $this->prophesize(RequestHandlerInterface::class)->reveal());
 
         $this->assertInstanceOf(PixelResponse::class, $response);
         $this->assertEquals(200, $response->getStatusCode());
diff --git a/module/Core/test/Action/PreviewActionTest.php b/module/Core/test/Action/PreviewActionTest.php
index f8f74d88..bc2d833d 100644
--- a/module/Core/test/Action/PreviewActionTest.php
+++ b/module/Core/test/Action/PreviewActionTest.php
@@ -14,7 +14,6 @@ use Shlinkio\Shlink\Core\Exception\EntityDoesNotExistException;
 use Shlinkio\Shlink\Core\Exception\InvalidShortCodeException;
 use Shlinkio\Shlink\Core\Service\UrlShortener;
 use Shlinkio\Shlink\PreviewGenerator\Service\PreviewGenerator;
-use ShlinkioTest\Shlink\Common\Util\TestUtils;
 use Zend\Diactoros\Response;
 use Zend\Diactoros\ServerRequest;
 
@@ -39,7 +38,7 @@ class PreviewActionTest extends TestCase
     }
 
     /** @test */
-    public function invalidShortCodeFallsBackToNextMiddleware()
+    public function invalidShortCodeFallsBackToNextMiddleware(): void
     {
         $shortCode = 'abc123';
         $this->urlShortener->shortCodeToUrl($shortCode)->willThrow(EntityDoesNotExistException::class)
@@ -52,7 +51,7 @@ class PreviewActionTest extends TestCase
     }
 
     /** @test */
-    public function correctShortCodeReturnsImageResponse()
+    public function correctShortCodeReturnsImageResponse(): void
     {
         $shortCode = 'abc123';
         $url = 'foobar.com';
@@ -63,7 +62,7 @@ class PreviewActionTest extends TestCase
 
         $resp = $this->action->process(
             (new ServerRequest())->withAttribute('shortCode', $shortCode),
-            TestUtils::createReqHandlerMock()->reveal()
+            $this->prophesize(RequestHandlerInterface::class)->reveal()
         );
 
         $this->assertEquals(filesize($path), $resp->getHeaderLine('Content-length'));
@@ -71,7 +70,7 @@ class PreviewActionTest extends TestCase
     }
 
     /** @test */
-    public function invalidShortCodeExceptionFallsBackToNextMiddleware()
+    public function invalidShortCodeExceptionFallsBackToNextMiddleware(): void
     {
         $shortCode = 'abc123';
         $this->urlShortener->shortCodeToUrl($shortCode)->willThrow(InvalidShortCodeException::class)
diff --git a/module/Core/test/Action/RedirectActionTest.php b/module/Core/test/Action/RedirectActionTest.php
index 9fc13906..da2199e4 100644
--- a/module/Core/test/Action/RedirectActionTest.php
+++ b/module/Core/test/Action/RedirectActionTest.php
@@ -13,7 +13,6 @@ use Shlinkio\Shlink\Core\Exception\EntityDoesNotExistException;
 use Shlinkio\Shlink\Core\Options;
 use Shlinkio\Shlink\Core\Service\UrlShortener;
 use Shlinkio\Shlink\Core\Service\VisitsTracker;
-use ShlinkioTest\Shlink\Common\Util\TestUtils;
 use Zend\Diactoros\Response;
 use Zend\Diactoros\ServerRequest;
 
@@ -43,7 +42,7 @@ class RedirectActionTest extends TestCase
     }
 
     /** @test */
-    public function redirectionIsPerformedToLongUrl()
+    public function redirectionIsPerformedToLongUrl(): void
     {
         $shortCode = 'abc123';
         $expectedUrl = 'http://domain.com/foo/bar';
@@ -53,7 +52,7 @@ class RedirectActionTest extends TestCase
         $this->visitTracker->track(Argument::cetera())->shouldBeCalledOnce();
 
         $request = (new ServerRequest())->withAttribute('shortCode', $shortCode);
-        $response = $this->action->process($request, TestUtils::createReqHandlerMock()->reveal());
+        $response = $this->action->process($request, $this->prophesize(RequestHandlerInterface::class)->reveal());
 
         $this->assertInstanceOf(Response\RedirectResponse::class, $response);
         $this->assertEquals(302, $response->getStatusCode());
@@ -62,7 +61,7 @@ class RedirectActionTest extends TestCase
     }
 
     /** @test */
-    public function nextMiddlewareIsInvokedIfLongUrlIsNotFound()
+    public function nextMiddlewareIsInvokedIfLongUrlIsNotFound(): void
     {
         $shortCode = 'abc123';
         $this->urlShortener->shortCodeToUrl($shortCode)->willThrow(EntityDoesNotExistException::class)
@@ -79,7 +78,7 @@ class RedirectActionTest extends TestCase
     }
 
     /** @test */
-    public function redirectToCustomUrlIsReturnedIfConfiguredSoAndShortUrlIsNotFound()
+    public function redirectToCustomUrlIsReturnedIfConfiguredSoAndShortUrlIsNotFound(): void
     {
         $shortCode = 'abc123';
         $shortCodeToUrl = $this->urlShortener->shortCodeToUrl($shortCode)->willThrow(
@@ -102,7 +101,7 @@ class RedirectActionTest extends TestCase
     }
 
     /** @test */
-    public function visitIsNotTrackedIfDisableParamIsProvided()
+    public function visitIsNotTrackedIfDisableParamIsProvided(): void
     {
         $shortCode = 'abc123';
         $expectedUrl = 'http://domain.com/foo/bar';
@@ -113,7 +112,7 @@ class RedirectActionTest extends TestCase
 
         $request = (new ServerRequest())->withAttribute('shortCode', $shortCode)
                                                       ->withQueryParams(['foobar' => true]);
-        $response = $this->action->process($request, TestUtils::createReqHandlerMock()->reveal());
+        $response = $this->action->process($request, $this->prophesize(RequestHandlerInterface::class)->reveal());
 
         $this->assertInstanceOf(Response\RedirectResponse::class, $response);
         $this->assertEquals(302, $response->getStatusCode());
diff --git a/phpstan.neon b/phpstan.neon
index 85f81e8f..90c8b2ee 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -1,6 +1,5 @@
 parameters:
 	ignoreErrors:
-		- '#League\\Plates\\callback#'
 		- '#is not subtype of Throwable#'
 		- '#ObjectManager::flush()#'
 		- '#\$metadata ClassMetadata#'
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index 03e97254..516a48fc 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -6,9 +6,6 @@
     colors="true"
 >
     <testsuites>
-        <testsuite name="Common">
-            <directory>./module/Common/test</directory>
-        </testsuite>
         <testsuite name="Core">
             <directory>./module/Core/test</directory>
         </testsuite>