From 96dca89e06ed735751ae3ac5c67e403553e3bfa5 Mon Sep 17 00:00:00 2001 From: Artem Onyshchenko Date: Mon, 1 Feb 2021 17:49:47 +0200 Subject: [PATCH] - Update dependencies - Add RedisFactory for testing - Add RedisInMemory for testing - Add HttpRequestInterface for adapters - Add monolog CustomTagProcessor - Fix coding standards --- .docker/{php7.3-dev => php-dev}/Dockerfile | 23 ++- .travis.yml | 3 +- Makefile | 16 +- composer.json | 19 +- docker-compose.yml | 5 +- ecs.php | 15 ++ phpstan.neon | 4 +- psalm.xml | 5 +- src/Domain/Adapter/HttpRequestInterface.php | 32 ++++ src/Domain/Command/CommandInterface.php | 2 - .../Exception/ParentExceptionInterface.php | 3 - src/Domain/Exception/ParentExceptionTrait.php | 4 - .../Factory/CommandFactoryInterface.php | 4 +- .../Service/NormalizableServiceInterface.php | 4 - .../Service/SerializableServiceInterface.php | 2 - .../Service/Monolog/CustomTagProcessor.php | 170 ++++++++++++++++++ src/Utils/LoggerTrait.php | 15 -- .../Infrastructure/Factory/RedisFactory.php | 47 +++++ .../Repository/RedisInMemory.php | 83 +++++++++ 19 files changed, 390 insertions(+), 66 deletions(-) rename .docker/{php7.3-dev => php-dev}/Dockerfile (53%) create mode 100644 ecs.php create mode 100644 src/Domain/Adapter/HttpRequestInterface.php create mode 100644 src/Infrastructure/Service/Monolog/CustomTagProcessor.php create mode 100644 tests/unit/Infrastructure/Factory/RedisFactory.php create mode 100644 tests/unit/Infrastructure/Repository/RedisInMemory.php diff --git a/.docker/php7.3-dev/Dockerfile b/.docker/php-dev/Dockerfile similarity index 53% rename from .docker/php7.3-dev/Dockerfile rename to .docker/php-dev/Dockerfile index 3d5e25d..e594a2b 100644 --- a/.docker/php7.3-dev/Dockerfile +++ b/.docker/php-dev/Dockerfile @@ -1,16 +1,25 @@ -FROM php:7.3-cli +FROM php:8.0-cli-alpine -RUN apt-get update && apt-get install -y git unzip +RUN apk update +RUN apk add --no-cache bash +RUN apk add --no-cache build-base +RUN apk add --no-cache autoconf +RUN apk add --no-cache automake ENV COMPOSER_ALLOW_SUPERUSER 1 ENV COMPOSER_MEMORY_LIMIT -1 -RUN mkdir /.composer_cache -ENV COMPOSER_CACHE_DIR /.composer_cache - -RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer - # php extensions +# intl +RUN apk add --no-cache icu-dev +RUN docker-php-ext-install intl +RUN docker-php-ext-enable intl +# xdebug RUN pecl install xdebug RUN docker-php-ext-enable xdebug + +RUN mkdir /.composer_cache +ENV COMPOSER_CACHE_DIR /.composer_cache + +RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer diff --git a/.travis.yml b/.travis.yml index 270a07b..2436a3e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,8 @@ language: php matrix: include: - - php: 7.3 + - php: 7.4 + - php: 8.0 fast_finish: true env: diff --git a/Makefile b/Makefile index 04a87a5..ea90b6c 100644 --- a/Makefile +++ b/Makefile @@ -38,19 +38,17 @@ composer: ## Execute composer command phpunit: ## execute project unit tests docker-compose run --rm --no-deps php sh -lc "./vendor/bin/phpunit $(conf)" -.PHONY: style -style: ## executes php analizers +.PHONY: phpstan +phpstan: ## executes phpstan analizer docker-compose run --rm --no-deps php sh -lc './vendor/bin/phpstan analyse -l 6 -c phpstan.neon src tests' + +psalm: ## execute psalm analizer docker-compose run --rm --no-deps php sh -lc './vendor/bin/psalm --config=psalm.xml' .PHONY: lint lint: ## checks syntax of PHP files docker-compose run --rm --no-deps php sh -lc './vendor/bin/parallel-lint ./ --exclude vendor --exclude bin/.phpunit' -.PHONY: layer -layer: ## Check issues with layers (deptrac tool) - docker-compose run --rm --no-deps php sh -lc './vendor/bin/deptrac analyze --formatter-graphviz=0' - .PHONY: logs logs: ## look for service logs docker-compose logs -f $(RUN_ARGS) @@ -66,7 +64,7 @@ php-shell: ## PHP shell unit-tests: ## Run unit-tests suite docker-compose run --rm php sh -lc 'vendor/bin/phpunit --testsuite unit-tests' -static-analysis: style layer coding-standards ## Run phpstan, easycoding standarts code static analysis +static-analysis: psalm phpstan coding-standards ## Run phpstan, psalm, easycoding standarts code static analysis coding-standards: ## Run check and validate code standards tests docker-compose run --rm --no-deps php sh -lc 'vendor/bin/ecs check src tests' @@ -78,5 +76,5 @@ coding-standards-fixer: ## Run code standards fixer security-tests: ## The SensioLabs Security Checker docker-compose run --rm --no-deps php sh -lc 'vendor/bin/security-checker security:check --end-point=http://security.sensiolabs.org/check_lock' -.PHONY: test lint static-analysis phpunit coding-standards composer-validate -test: build lint static-analysis phpunit coding-standards composer-validate stop ## Run all test suites +.PHONY: test lint static-analysis coding-standards composer-validate phpunit +test: build lint static-analysis coding-standards composer-validate phpunit stop ## Run all test suites diff --git a/composer.json b/composer.json index 48d7527..57b7c86 100644 --- a/composer.json +++ b/composer.json @@ -4,25 +4,26 @@ "description": "Micro module Base common library", "license": "proprietary", "require": { - "php": "^7.3 || ^8.0", + "php": "^7.4 || ^8.0", "ext-json": "*", - "beberlei/assert": "^3.2", + "ext-intl": "*", + "beberlei/assert": "^3.3", "psr/log": "^1.1", "ramsey/uuid": "^3.8 || ^4.0", "monolog/monolog": "~1.22 || ~2.0" }, "require-dev": { - "php-parallel-lint/php-console-highlighter": "^0.4", - "php-parallel-lint/php-parallel-lint": "^1.0", - "mockery/mockery": "^1.3", - "phpmd/phpmd": "^2.8", + "php-parallel-lint/php-console-highlighter": "^0.5", + "php-parallel-lint/php-parallel-lint": "^1.2", + "mockery/mockery": "^1.4", + "phpmd/phpmd": "^2.9", "phpstan/phpstan": "^0.12", "phpstan/phpstan-mockery": "^0.12", "phpstan/phpstan-phpunit": "^0.12", - "phpunit/phpunit": "^9.4", + "phpunit/phpunit": "^9.3", "roave/security-advisories": "dev-master", - "symplify/easy-coding-standard": "^7.2", - "vimeo/psalm": "^4.2" + "symplify/easy-coding-standard": "^9.0", + "vimeo/psalm": "^4.4" }, "config": { "preferred-install": { diff --git a/docker-compose.yml b/docker-compose.yml index f29c43f..17d5696 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,9 +3,10 @@ version: "3.7" services: php: container_name: ${MICROBASE_COMPOSE_PROJECT_NAME}_php - user: 1000:1000 build: - context: .docker/php7.3-dev + context: .docker/php-dev + env_file: + - .env volumes: - ~/.composer/cache/:/.composer_cache/:rw - .:/app:rw diff --git a/ecs.php b/ecs.php new file mode 100644 index 0000000..c9bc96a --- /dev/null +++ b/ecs.php @@ -0,0 +1,15 @@ +import(__DIR__ . '/vendor/symplify/easy-coding-standard/config/set/clean-code.php'); + $containerConfigurator->import(__DIR__ . '/vendor/symplify/easy-coding-standard/config/set/symfony.php'); + $containerConfigurator->import(__DIR__ . '/vendor/symplify/easy-coding-standard/config/set/php71.php'); + $containerConfigurator->import(__DIR__ . '/vendor/symplify/easy-coding-standard/config/set/psr12.php'); + $parameters = $containerConfigurator->parameters(); + $parameters->set('skip', [ + ]); +}; diff --git a/phpstan.neon b/phpstan.neon index c1c0981..ca39598 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -3,5 +3,5 @@ includes: parameters: excludes_analyse: - - src/Infrastructure/Testing/RedisInMemory.php - - src/Infrastructure/Testing/RedisFactory.php + - tests/unit/Infrastructure/Repository/RedisInMemory.php + - tests/unit/Infrastructure/Factory/RedisFactory.php diff --git a/psalm.xml b/psalm.xml index 39b4cb3..51e3269 100644 --- a/psalm.xml +++ b/psalm.xml @@ -9,8 +9,8 @@ - - + + @@ -34,7 +34,6 @@ - diff --git a/src/Domain/Adapter/HttpRequestInterface.php b/src/Domain/Adapter/HttpRequestInterface.php new file mode 100644 index 0000000..be3e0c4 --- /dev/null +++ b/src/Domain/Adapter/HttpRequestInterface.php @@ -0,0 +1,32 @@ + + */ + protected array $tags; + + /** + * Global logging tags from application and environment. + * + * @var array + */ + protected array $globalTags; + + /** + * Additional tags. + * + * @var array + */ + protected array $additionalTags; + + /** + * CustomTagProcessor constructor. + * + * @param mixed[] $globalTags + * @param string[] $additionalTags + */ + public function __construct(string $environment, string $release, array $globalTags = [], array $additionalTags = []) + { + $this->environment = $environment; + $this->release = $release; + $this->globalTags = $globalTags; + $this->additionalTags = $additionalTags; + } + + /** + * Add custom tags to log tags. Method called by Monolog. + * + * @param mixed[] $record + * + * @return mixed[] + */ + public function __invoke(array $record): array + { + $this->addAdditonalTags($record); + $this->addGlobalTags($record); + $record['extra']['tags'] = $this->tags; + $record['extra']['release'] = $this->release; + $record['extra']['environment'] = $this->environment; + + return $record; + } + + /** + * Add global tags, such exception level, version of php, application name etc. + * + * @param mixed[] $record + */ + protected function addGlobalTags(array $record): void + { + $context = $record['context']; + + if (isset($context['exception'])) { + $this->addTag('exception_type', $this->resolveExceptionLevelType($context['exception'])); + } + $this->addTag('php_version', (string) phpversion()); + + foreach ($this->globalTags as $k => $v) { + $this->addTag($k, $v); + } + } + + /** + * Add logging additional tags. + * + * @param mixed[] $record + */ + protected function addAdditonalTags(array $record): void + { + $context = $record['context']; + + foreach ($this->additionalTags as $key) { + if (isset($context[$key])) { + $this->addTag($key, $context[$key]); + } + } + } + + /** + * Add logging tag. + * + * @param object|mixed[]|string|int $value + */ + protected function addTag(string $key, $value): void + { + if (is_object($value)) { + $value = method_exists($value, 'normalize') ? json_encode($value->normalize()) : var_export($value, true); + } + $this->tags[$key] = $value; + } + + /** + * Resolve exception level type based on exception. + */ + protected function resolveExceptionLevelType(Throwable $e): string + { + switch (true) { + case $e instanceof AlertException: + return self::EXCEPTION_NAME_ALERT; + + case $e instanceof CriticalException: + return self::EXCEPTION_NAME_CRITICAL; + + case $e instanceof EmergencyException: + return self::EXCEPTION_NAME_EMERGENCY; + + case $e instanceof RunTimeException: + return self::EXCEPTION_NAME_RUNTIME; + + case $e instanceof TypeError: + return self::ERROR_NAME_TYPE; + + case $e instanceof Error: + return self::ERROR_BASE_NAME; + + default: + return self::EXCEPTION_NAME_DEFAULT; + } + } +} diff --git a/src/Utils/LoggerTrait.php b/src/Utils/LoggerTrait.php index 81f0d06..6bc5bfb 100644 --- a/src/Utils/LoggerTrait.php +++ b/src/Utils/LoggerTrait.php @@ -40,8 +40,6 @@ trait LoggerTrait /** * ExceptionListener constructor. * - * @param LoggerInterface $logger - * * @return $this * * @required @@ -56,8 +54,6 @@ public function setLogger(LoggerInterface $logger): self /** * Log an regular message or warning. * - * @param string $message - * @param int $level * @param mixed[] $context * * @return $this @@ -91,7 +87,6 @@ public function logMessage(string $message, int $level, array $context = []): se default: throw new LoggerException(sprintf("Try to log invalid message level type '%s'", $level)); - break; } @@ -102,7 +97,6 @@ public function logMessage(string $message, int $level, array $context = []): se * Log an exception. * * @param Throwable $exception The \Throwable instance - * @param int $level * @param string $message The error message to log * * @return $this @@ -140,7 +134,6 @@ public function logException(Throwable $exception, int $level, string $message): default: throw new LoggerException(sprintf("Try to log invalid error level type '%s'", $level)); - break; } @@ -149,10 +142,6 @@ public function logException(Throwable $exception, int $level, string $message): /** * Define exception level from exception type. - * - * @param Throwable $exception - * - * @return int */ public function getExceptionLevel(Throwable $exception): int { @@ -175,10 +164,6 @@ public function getExceptionLevel(Throwable $exception): int /** * Generate exception message. - * - * @param Throwable $exception - * - * @return string */ public function getExceptionMessage(Throwable $exception): string { diff --git a/tests/unit/Infrastructure/Factory/RedisFactory.php b/tests/unit/Infrastructure/Factory/RedisFactory.php new file mode 100644 index 0000000..b340a31 --- /dev/null +++ b/tests/unit/Infrastructure/Factory/RedisFactory.php @@ -0,0 +1,47 @@ +shouldReceive('get'); + $redisGetMethod->andReturnUsing( + function ($key) { + return $key; + } + ); + $redisSetMethod = $redis->shouldReceive('set'); + $redisSetMethod->andReturnUsing( + function ($key, $value, $timeout = 0) { + return true; + } + ); + $redisSaveMethod = $redis->shouldReceive('save'); + $redisSaveMethod->andReturnUsing( + function () { + return true; + } + ); + + return $redis; + } +} diff --git a/tests/unit/Infrastructure/Repository/RedisInMemory.php b/tests/unit/Infrastructure/Repository/RedisInMemory.php new file mode 100644 index 0000000..a55462d --- /dev/null +++ b/tests/unit/Infrastructure/Repository/RedisInMemory.php @@ -0,0 +1,83 @@ +get('key'); + */ + public function get($key) + { + return $this->storage[$key] ?? false; + } + + /** + * Set the string value in argument as value of the key. + * + * @param string $key + * @param string $value + * @param int|mixed[] $timeout [optional] Calling setex() is preferred if you want a timeout.
+ * + * @return bool TRUE if the command is successful + * + * @example $redis->set('key', 'value'); + */ + public function set($key, $value, $timeout = 0): bool + { + $this->storage[$key] = $value; + + return true; + } + + /** + * Performs a synchronous save. + * + * @return bool + * + * @example $redis->save(); + */ + public function save() + { + return true; + } +}