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 - 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 - [ - '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 @@ - [ - '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 @@ - [ - '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 @@ - [ - '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 @@ - [ - '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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ - 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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ - $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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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" > - - ./module/Common/test - ./module/Core/test