From 73f6ad909b5142c37d613b92d548aee5912b881b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=A1=D0=BF=D0=B8?= =?UTF-8?q?=D1=80=D0=BA=D0=BE=D0=B2?= Date: Tue, 27 Jan 2026 16:55:23 +0400 Subject: [PATCH 1/5] configs + deps --- .github/workflows/rector-cs.yml | 28 +++++++++++ .github/workflows/rector.yml | 24 ---------- .gitignore | 4 ++ .php-cs-fixer.dist.php | 22 +++++++++ .styleci.yml | 85 --------------------------------- composer.json | 15 ++++-- tools/.gitignore | 2 + tools/composer.json | 5 ++ 8 files changed, 73 insertions(+), 112 deletions(-) create mode 100644 .github/workflows/rector-cs.yml delete mode 100644 .github/workflows/rector.yml create mode 100644 .php-cs-fixer.dist.php delete mode 100644 .styleci.yml create mode 100644 tools/.gitignore create mode 100644 tools/composer.json diff --git a/.github/workflows/rector-cs.yml b/.github/workflows/rector-cs.yml new file mode 100644 index 00000000..03b7c75c --- /dev/null +++ b/.github/workflows/rector-cs.yml @@ -0,0 +1,28 @@ +name: Rector + PHP CS Fixer + +on: + pull_request_target: + paths: + - 'config/**' + - 'src/**' + - 'tests/**' + - '.github/workflows/rector-cs.yml' + - 'composer.json' + - 'rector.php' + - '.php-cs-fixer.dist.php' + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + rector: + uses: yiisoft/actions/.github/workflows/rector-cs.yml@master + secrets: + token: ${{ secrets.YIISOFT_GITHUB_TOKEN }} + with: + repository: ${{ github.event.pull_request.head.repo.full_name }} + php: '8.1' diff --git a/.github/workflows/rector.yml b/.github/workflows/rector.yml deleted file mode 100644 index 5d6931d5..00000000 --- a/.github/workflows/rector.yml +++ /dev/null @@ -1,24 +0,0 @@ -on: - pull_request_target: - paths-ignore: - - 'docs/**' - - 'README.md' - - 'CHANGELOG.md' - - '.gitignore' - - '.gitattributes' - - 'infection.json.dist' - - 'psalm.xml' - -name: rector - -jobs: - rector: - uses: yiisoft/actions/.github/workflows/rector.yml@master - secrets: - token: ${{ secrets.YIISOFT_GITHUB_TOKEN }} - with: - repository: ${{ github.event.pull_request.head.repo.full_name }} - os: >- - ['ubuntu-latest'] - php: >- - ['8.4'] diff --git a/.gitignore b/.gitignore index c730a03d..1a3fdc62 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,7 @@ phpunit.phar /phpunit.xml # local phpunit cache .phpunit.result.cache + +# PHP CS Fixer +/.php-cs-fixer.cache +/.php-cs-fixer.php diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php new file mode 100644 index 00000000..3cb52f9e --- /dev/null +++ b/.php-cs-fixer.dist.php @@ -0,0 +1,22 @@ +in([ + __DIR__ . '/config', + __DIR__ . '/src', + __DIR__ . '/tests', +]); + +return ConfigBuilder::build() + ->setRiskyAllowed(true) + ->setParallelConfig(ParallelConfigFactory::detect()) + ->setRules([ + '@Yiisoft/Core' => true, + '@Yiisoft/Core:risky' => true, + ]) + ->setFinder($finder); diff --git a/.styleci.yml b/.styleci.yml deleted file mode 100644 index 1ab379b4..00000000 --- a/.styleci.yml +++ /dev/null @@ -1,85 +0,0 @@ -preset: psr12 -risky: true - -version: 8.1 - -finder: - exclude: - - docs - - vendor - -enabled: - - alpha_ordered_traits - - array_indentation - - array_push - - combine_consecutive_issets - - combine_consecutive_unsets - - combine_nested_dirname - - declare_strict_types - - dir_constant - - fully_qualified_strict_types - - function_to_constant - - hash_to_slash_comment - - is_null - - logical_operators - - magic_constant_casing - - magic_method_casing - - method_separation - - modernize_types_casting - - native_function_casing - - native_function_type_declaration_casing - - no_alias_functions - - no_empty_comment - - no_empty_phpdoc - - no_empty_statement - - no_extra_block_blank_lines - - no_short_bool_cast - - no_superfluous_elseif - - no_unneeded_control_parentheses - - no_unneeded_curly_braces - - no_unneeded_final_method - - no_unset_cast - - no_unused_imports - - no_unused_lambda_imports - - no_useless_else - - no_useless_return - - normalize_index_brace - - php_unit_dedicate_assert - - php_unit_dedicate_assert_internal_type - - php_unit_expectation - - php_unit_mock - - php_unit_mock_short_will_return - - php_unit_namespaced - - php_unit_no_expectation_annotation - - phpdoc_no_empty_return - - phpdoc_no_useless_inheritdoc - - phpdoc_order - - phpdoc_property - - phpdoc_scalar - - phpdoc_singular_inheritdoc - - phpdoc_trim - - phpdoc_trim_consecutive_blank_line_separation - - phpdoc_type_to_var - - phpdoc_types - - phpdoc_types_order - - print_to_echo - - regular_callable_call - - return_assignment - - self_accessor - - self_static_accessor - - set_type_to_cast - - short_array_syntax - - short_list_syntax - - simplified_if_return - - single_quote - - standardize_not_equals - - ternary_to_null_coalescing - - trailing_comma_in_multiline_array - - unalign_double_arrow - - unalign_equals - - empty_loop_body_braces - - integer_literal_case - - union_type_without_spaces - -disabled: - - function_declaration diff --git a/composer.json b/composer.json index 4c7f7123..c921e0db 100644 --- a/composer.json +++ b/composer.json @@ -35,13 +35,15 @@ "yiisoft/var-dumper": "^1.0" }, "require-dev": { - "maglnet/composer-require-checker": "^4.4", + "bamarni/composer-bin-plugin": "^1.8.3", + "friendsofphp/php-cs-fixer": "^3.93", "phpbench/phpbench": "^1.0", "phpunit/phpunit": "^9.6.23", "rector/rector": "^2.0.17", "roave/infection-static-analysis-plugin": "^1.25", "spatie/phpunit-watcher": "^1.23.6", - "vimeo/psalm": "^4.30 || ^5.26.1 || ^6.12" + "vimeo/psalm": "^4.30 || ^5.26.1 || ^6.12", + "yiisoft/code-style": "^1.0" }, "provide": { "psr/log-implementation": "1.0.0" @@ -66,6 +68,11 @@ } }, "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": true, + "target-directory": "tools" + }, "config-plugin-options": { "source-directory": "config" }, @@ -77,6 +84,7 @@ "config": { "sort-packages": true, "allow-plugins": { + "bamarni/composer-bin-plugin": true, "infection/extension-installer": true, "composer/package-versions-deprecated": true } @@ -84,6 +92,7 @@ "scripts": { "test": "phpunit --testdox --no-interaction", "test-watch": "phpunit-watcher watch", - "bench": "phpbench run --report=default" + "bench": "phpbench run --report=default", + "cs-fix": "php-cs-fixer fix" } } diff --git a/tools/.gitignore b/tools/.gitignore new file mode 100644 index 00000000..cf452dcf --- /dev/null +++ b/tools/.gitignore @@ -0,0 +1,2 @@ +/*/vendor +/*/composer.lock diff --git a/tools/composer.json b/tools/composer.json new file mode 100644 index 00000000..498425c1 --- /dev/null +++ b/tools/composer.json @@ -0,0 +1,5 @@ +{ + "require-dev": { + "maglnet/composer-require-checker": "^4.4" + } +} From 498533d7812390ef940053035c6210defc7f912e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=A1=D0=BF=D0=B8?= =?UTF-8?q?=D1=80=D0=BA=D0=BE=D0=B2?= Date: Tue, 27 Jan 2026 16:56:33 +0400 Subject: [PATCH 2/5] fix CS --- src/ContextProvider/CommonContextProvider.php | 3 +- .../CompositeContextProvider.php | 2 +- src/ContextProvider/SystemContextProvider.php | 11 +++- src/Logger.php | 20 +++--- src/Message.php | 8 ++- src/Message/CategoryFilter.php | 2 +- src/Message/ContextValueExtractor.php | 10 +-- src/Message/Formatter.php | 5 +- src/PsrTarget.php | 3 +- src/StreamTarget.php | 5 +- src/Target.php | 16 ++--- tests/Benchmark/LoggerBench.php | 2 +- .../CompositeContextProviderTest.php | 2 +- tests/LoggerTest.php | 18 +++--- tests/Message/CategoryFilterTest.php | 2 +- tests/Message/FormatterTest.php | 30 ++++----- tests/PsrTargetTest.php | 10 +-- tests/StreamTargetTest.php | 34 +++++------ tests/TargetTest.php | 61 ++++++++++--------- tests/TestAsset/StringableObject.php | 3 +- tests/TestAsset/StubContextProvider.php | 3 +- 21 files changed, 136 insertions(+), 114 deletions(-) diff --git a/src/ContextProvider/CommonContextProvider.php b/src/ContextProvider/CommonContextProvider.php index 9b08b7ae..8b9a146f 100644 --- a/src/ContextProvider/CommonContextProvider.php +++ b/src/ContextProvider/CommonContextProvider.php @@ -11,8 +11,7 @@ final class CommonContextProvider implements ContextProviderInterface { public function __construct( private array $data, - ) { - } + ) {} public function getContext(): array { diff --git a/src/ContextProvider/CompositeContextProvider.php b/src/ContextProvider/CompositeContextProvider.php index b31ef53f..c9d5d777 100644 --- a/src/ContextProvider/CompositeContextProvider.php +++ b/src/ContextProvider/CompositeContextProvider.php @@ -15,7 +15,7 @@ final class CompositeContextProvider implements ContextProviderInterface private array $providers; public function __construct( - ContextProviderInterface ...$providers + ContextProviderInterface ...$providers, ) { $this->providers = $providers; } diff --git a/src/ContextProvider/SystemContextProvider.php b/src/ContextProvider/SystemContextProvider.php index 0af3ee57..c9cf4fe8 100644 --- a/src/ContextProvider/SystemContextProvider.php +++ b/src/ContextProvider/SystemContextProvider.php @@ -7,6 +7,11 @@ use InvalidArgumentException; use Yiisoft\Log\Message; +use function is_string; +use function sprintf; + +use const DEBUG_BACKTRACE_IGNORE_ARGS; + /** * @psalm-import-type TraceItem from Message */ @@ -79,8 +84,8 @@ public function setExcludedTracePaths(array $excludedTracePaths): self throw new InvalidArgumentException( sprintf( 'The trace path must be a string, %s received.', - get_debug_type($excludedTracePath) - ) + get_debug_type($excludedTracePath), + ), ); } } @@ -109,7 +114,7 @@ private function collectTrace(array $backtrace): array if (isset($trace['file'], $trace['line'])) { $excludedMatch = array_filter( $this->excludedTracePaths, - static fn($path) => str_contains($trace['file'], $path) + static fn($path) => str_contains($trace['file'], $path), ); if (empty($excludedMatch)) { diff --git a/src/Logger.php b/src/Logger.php index af5986f4..01ecd576 100644 --- a/src/Logger.php +++ b/src/Logger.php @@ -57,7 +57,7 @@ final class Logger implements LoggerInterface private array $messages = []; /** - * @var Target[] the log targets. Each array element represents a single {@see \Yiisoft\Log\Target} instance. + * @var Target[] the log targets. Each array element represents a single {@see Target} instance. */ private array $targets = []; @@ -112,7 +112,7 @@ public static function validateLevel(mixed $level): string if (!is_string($level)) { throw new \Psr\Log\InvalidArgumentException(sprintf( 'The log message level must be a string, %s provided.', - get_debug_type($level) + get_debug_type($level), )); } @@ -120,7 +120,7 @@ public static function validateLevel(mixed $level): string throw new \Psr\Log\InvalidArgumentException(sprintf( 'Invalid log message level "%s" provided. The following values are supported: "%s".', $level, - implode('", "', self::LEVELS) + implode('", "', self::LEVELS), )); } @@ -128,7 +128,7 @@ public static function validateLevel(mixed $level): string } /** - * @return Target[] The log targets. Each array element represents a single {@see \Yiisoft\Log\Target} instance. + * @return Target[] The log targets. Each array element represents a single {@see Target} instance. */ public function getTargets(): array { @@ -190,7 +190,7 @@ public function setTraceLevel(int $traceLevel): self { if (!$this->contextProvider instanceof SystemContextProvider) { throw new RuntimeException( - '"Logger::setTraceLevel()" is unavailable when using a custom context provider.' + '"Logger::setTraceLevel()" is unavailable when using a custom context provider.', ); } /** @psalm-suppress DeprecatedMethod */ @@ -212,7 +212,7 @@ public function setExcludedTracePaths(array $excludedTracePaths): self { if (!$this->contextProvider instanceof SystemContextProvider) { throw new RuntimeException( - '"Logger::setExcludedTracePaths()" is unavailable when using a custom context provider.' + '"Logger::setExcludedTracePaths()" is unavailable when using a custom context provider.', ); } /** @psalm-suppress DeprecatedMethod */ @@ -249,7 +249,7 @@ public static function assertLevelIsString(mixed $level): void } throw new \Psr\Log\InvalidArgumentException( - sprintf('The log message level must be a string, %s provided.', get_debug_type($level)) + sprintf('The log message level must be a string, %s provided.', get_debug_type($level)), ); } @@ -270,15 +270,15 @@ public static function assertLevelIsSupported(string $level): void sprintf( 'Invalid log message level "%s" provided. The following values are supported: "%s".', $level, - implode('", "', self::LEVELS) - ) + implode('", "', self::LEVELS), + ), ); } /** * Sets a target to {@see Logger::$targets}. * - * @param Target[] $targets The log targets. Each array element represents a single {@see \Yiisoft\Log\Target} + * @param Target[] $targets The log targets. Each array element represents a single {@see Target} * instance or the configuration for creating the log target instance. * * @throws InvalidArgumentException for non-instance Target. diff --git a/src/Message.php b/src/Message.php index c47fbebc..9d77fd25 100644 --- a/src/Message.php +++ b/src/Message.php @@ -16,6 +16,10 @@ use Yiisoft\VarDumper\VarDumper; use function preg_replace_callback; +use function is_float; +use function is_int; +use function is_scalar; +use function is_string; /** * Message is a data object that stores log message data. @@ -129,7 +133,7 @@ public function category(): string $category = $this->context['category'] ?? self::DEFAULT_CATEGORY; if (!is_string($category)) { throw new LogicException( - 'Invalid category value in log context. Expected "string", got "' . get_debug_type($category) . '".' + 'Invalid category value in log context. Expected "string", got "' . get_debug_type($category) . '".', ); } return $category; @@ -227,7 +231,7 @@ static function (array $matches) use ($context) { } return $matches[0]; }, - $message + $message, ); } } diff --git a/src/Message/CategoryFilter.php b/src/Message/CategoryFilter.php index 2271a975..83da72e1 100644 --- a/src/Message/CategoryFilter.php +++ b/src/Message/CategoryFilter.php @@ -121,7 +121,7 @@ private function checkStructure(array $categories): void if (!is_string($category)) { throw new InvalidArgumentException(sprintf( 'The log message category must be a string, %s received.', - get_debug_type($category) + get_debug_type($category), )); } } diff --git a/src/Message/ContextValueExtractor.php b/src/Message/ContextValueExtractor.php index 5e50965d..88760d25 100644 --- a/src/Message/ContextValueExtractor.php +++ b/src/Message/ContextValueExtractor.php @@ -10,6 +10,8 @@ use function sprintf; use function strlen; +use const PREG_SPLIT_OFFSET_CAPTURE; + /** * @internal */ @@ -55,11 +57,11 @@ private static function parsePath(string $path): array sprintf( '/(?%1$s%1$s)*)%2$s/', preg_quote('\\', '/'), - preg_quote('.', '/') + preg_quote('.', '/'), ), $path, -1, - PREG_SPLIT_OFFSET_CAPTURE + PREG_SPLIT_OFFSET_CAPTURE, ); $result = []; $countResults = count($matches); @@ -79,9 +81,9 @@ private static function parsePath(string $path): array '\\', '.', ], - $key + $key, ), - $result + $result, ); } } diff --git a/src/Message/Formatter.php b/src/Message/Formatter.php index 7f231af5..6563ff00 100644 --- a/src/Message/Formatter.php +++ b/src/Message/Formatter.php @@ -13,6 +13,7 @@ use function is_object; use function method_exists; use function sprintf; +use function is_int; /** * Formatter formats log messages. @@ -102,7 +103,7 @@ public function format(Message $message, array $commonContext): string if (!is_string($formatted)) { throw new RuntimeException(sprintf( 'The PHP callable "format" must return a string, %s received.', - get_debug_type($formatted) + get_debug_type($formatted), )); } @@ -150,7 +151,7 @@ private function getPrefix(Message $message, array $commonContext): string if (!is_string($prefix)) { throw new RuntimeException(sprintf( 'The PHP callable "prefix" must return a string, %s received.', - get_debug_type($prefix) + get_debug_type($prefix), )); } diff --git a/src/PsrTarget.php b/src/PsrTarget.php index 36228535..d4172dc2 100644 --- a/src/PsrTarget.php +++ b/src/PsrTarget.php @@ -5,6 +5,7 @@ namespace Yiisoft\Log; use Psr\Log\LoggerInterface; +use Psr\Log\LogLevel; /** * PsrTarget is a log target which simply passes messages to another PSR-3 compatible logger. @@ -15,7 +16,7 @@ final class PsrTarget extends Target * Sets the PSR-3 logger used to save messages of this target. * * @param LoggerInterface $logger The logger instance to be used for messages processing. - * @param string[] $levels The {@see \Psr\Log\LogLevel log message levels} that this target is interested in. + * @param string[] $levels The {@see LogLevel log message levels} that this target is interested in. */ public function __construct(private LoggerInterface $logger, array $levels = []) { diff --git a/src/StreamTarget.php b/src/StreamTarget.php index 677ddb78..e307018f 100644 --- a/src/StreamTarget.php +++ b/src/StreamTarget.php @@ -6,6 +6,7 @@ use InvalidArgumentException; use RuntimeException; +use Psr\Log\LogLevel; use function error_get_last; use function fclose; @@ -17,6 +18,8 @@ use function sprintf; use function stream_get_meta_data; +use function is_string; + use const LOCK_EX; use const LOCK_UN; @@ -27,7 +30,7 @@ final class StreamTarget extends Target { /** * @param resource|string $stream A string stream identifier or a stream resource. - * @param string[] $levels The {@see \Psr\Log\LogLevel log message levels} that this target is interested in. + * @param string[] $levels The {@see LogLevel log message levels} that this target is interested in. */ public function __construct(private $stream = 'php://stdout', array $levels = []) { diff --git a/src/Target.php b/src/Target.php index cea39809..ceff0a86 100644 --- a/src/Target.php +++ b/src/Target.php @@ -18,7 +18,7 @@ /** * Target is the base class for all log target classes. * - * A log target object will filter the messages logged by {@see \Yiisoft\Log\Logger} according + * A log target object will filter the messages logged by {@see Logger} according * to its {@see Target::setLevels()} and {@see Target::setCategories()}. It may also export * the filtered messages to specific destination defined by the target, such as emails, files. * @@ -73,12 +73,6 @@ abstract class Target */ private $enabled = true; - /** - * Exports log messages to a specific destination. - * Child classes must implement this method. - */ - abstract protected function export(): void; - /** * When defining a constructor in child classes, you must call `parent::__construct()`. * @@ -309,13 +303,19 @@ public function isEnabled(): bool if (!is_bool($enabled = ($this->enabled)())) { throw new RuntimeException(sprintf( 'The PHP callable "enabled" must returns a boolean, %s received.', - get_debug_type($enabled) + get_debug_type($enabled), )); } return $enabled; } + /** + * Exports log messages to a specific destination. + * Child classes must implement this method. + */ + abstract protected function export(): void; + /** * Gets a list of log messages that are retrieved from the logger so far by this log target. * diff --git a/tests/Benchmark/LoggerBench.php b/tests/Benchmark/LoggerBench.php index 6e0f284f..89946d51 100644 --- a/tests/Benchmark/LoggerBench.php +++ b/tests/Benchmark/LoggerBench.php @@ -14,7 +14,7 @@ final class LoggerBench public function __construct() { - $this->logger = new Logger([new class () extends Target { + $this->logger = new Logger([new class extends Target { protected function export(): void { // noop diff --git a/tests/ContextProvider/CompositeContextProviderTest.php b/tests/ContextProvider/CompositeContextProviderTest.php index 4e99aa61..4f3db7fe 100644 --- a/tests/ContextProvider/CompositeContextProviderTest.php +++ b/tests/ContextProvider/CompositeContextProviderTest.php @@ -31,7 +31,7 @@ public function testBase(): void 'b' => 3, 'c' => 4, ], - $context + $context, ); } } diff --git a/tests/LoggerTest.php b/tests/LoggerTest.php index 46c9a038..63b96154 100644 --- a/tests/LoggerTest.php +++ b/tests/LoggerTest.php @@ -18,6 +18,8 @@ use Yiisoft\Log\Tests\TestAsset\StubContextProvider; use function memory_get_usage; +use function count; +use function is_float; final class LoggerTest extends TestCase { @@ -68,7 +70,7 @@ public function testLogWithTraceLevel(): void $this->assertSame('application', $messages[0]->context('category')); $this->assertSame([ 'file' => __FILE__, - 'line' => 62, + 'line' => 64, 'function' => 'log', 'class' => Logger::class, 'type' => '->', @@ -82,7 +84,7 @@ public function messageProvider(): array return [ 'string' => ['test', 'test'], 'stringable-object' => [ - $stringableObject = new class () { + $stringableObject = new class { public function __toString(): string { return 'Stringable object'; @@ -156,7 +158,7 @@ public function invalidExcludedTracePathsProvider(): array 'array' => [[[]]], 'bool' => [[true]], 'null' => [[null]], - 'callable' => [[fn () => null]], + 'callable' => [[fn() => null]], 'object' => [[new stdClass()]], ]; } @@ -190,7 +192,7 @@ public function invalidMessageLevelProvider(): array 'bool' => [true], 'null' => [null], 'array' => [[]], - 'callable' => [fn () => null], + 'callable' => [fn() => null], 'object' => [new stdClass()], ]; } @@ -224,7 +226,7 @@ public function invalidListTargetProvider(): array 'bool' => [[true]], 'null' => [[null]], 'array' => [[[]]], - 'callable' => [[fn () => null]], + 'callable' => [[fn() => null]], 'object' => [[new stdClass()]], ]; } @@ -337,7 +339,7 @@ public function testDispatchWithSuccessTargetCollect(): void ->method('collect') ->with( $this->equalTo([$message]), - $this->equalTo(true) + $this->equalTo(true), ); $logger = new Logger(['fakeTarget' => $target]); @@ -382,7 +384,7 @@ public function testDispatchWithFakeTarget2ThrowExceptionWhenCollect(): void && $message->context('exception') === $exception; }), $this->equalTo(true), - ] + ], ); $target2 @@ -390,7 +392,7 @@ public function testDispatchWithFakeTarget2ThrowExceptionWhenCollect(): void ->method('collect') ->with( $this->equalTo([$message]), - $this->equalTo(true) + $this->equalTo(true), ) ->will($this->throwException($exception)); diff --git a/tests/Message/CategoryFilterTest.php b/tests/Message/CategoryFilterTest.php index c64e74cd..02bef65c 100644 --- a/tests/Message/CategoryFilterTest.php +++ b/tests/Message/CategoryFilterTest.php @@ -25,7 +25,7 @@ public function invalidCategoryMessageStructureProvider(): array 'float' => [[1.1]], 'array' => [[[]]], 'bool' => [[true]], - 'callable' => [[fn () => null]], + 'callable' => [[fn() => null]], 'object' => [[new stdClass()]], ]; } diff --git a/tests/Message/FormatterTest.php b/tests/Message/FormatterTest.php index eab89dce..abe1ec97 100644 --- a/tests/Message/FormatterTest.php +++ b/tests/Message/FormatterTest.php @@ -19,6 +19,8 @@ use function json_encode; use function strtoupper; +use const JSON_THROW_ON_ERROR; + final class FormatterTest extends TestCase { private Formatter $formatter; @@ -36,10 +38,10 @@ public function contextProvider(): array 'float' => [['foo' => 1.1], 'foo: 1.1'], 'null' => [['foo' => null], 'foo: null'], 'array' => [['foo' => []], 'foo: []'], - 'callable' => [['foo' => fn () => null], 'foo: fn () => null'], + 'callable' => [['foo' => fn() => null], 'foo: fn() => null'], 'exception' => [['foo' => $exception = new Exception('some error')], "foo: {$exception->__toString()}"], 'stringable-object' => [ - ['foo' => new class () { + ['foo' => new class { public function __toString(): string { return 'stringable-object'; @@ -90,7 +92,7 @@ public function testFormatWithSetFormat(): void public function testFormatWithSetFormatNotIncludingCommonContext(): void { - $this->formatter->setFormat(static fn (Message $message) => "[{$message->level()}][{$message->context('category')}] {$message->message()}"); + $this->formatter->setFormat(static fn(Message $message) => "[{$message->level()}][{$message->context('category')}] {$message->message()}"); $message = new Message(LogLevel::INFO, 'message', ['category' => 'app', 'time' => 1_508_160_390.6083]); $expected = '[info][app] message'; @@ -99,7 +101,7 @@ public function testFormatWithSetFormatNotIncludingCommonContext(): void public function testFormatWithSetPrefix(): void { - $this->formatter->setPrefix(static fn () => 'Prefix: '); + $this->formatter->setPrefix(static fn() => 'Prefix: '); $message = new Message(LogLevel::INFO, 'message', ['category' => 'app', 'time' => 1_508_160_390.6083]); $expected = '2017-10-16 13:26:30.608300 Prefix: [info][app] message' . "\n\nMessage context:\n\ncategory: 'app'\ntime: 1508160390.6083\n" @@ -129,13 +131,13 @@ public function testFormatWithTimeCommaSeparated(): void public function testFormatWithSetFormatAndSetPrefix(): void { - $this->formatter->setFormat(static fn (Message $message) => "({$message->level()}) {$message->message()}"); + $this->formatter->setFormat(static fn(Message $message) => "({$message->level()}) {$message->message()}"); $this->formatter->setPrefix( static function (Message $message) { $category = strtoupper($message->context('category')); $time = date('H:i:s', $message->context('time')); return "{$category}: ({$time})"; - } + }, ); $time = 1_508_160_390; @@ -143,7 +145,7 @@ static function (Message $message) { $this->assertSame( 'APP: (' . date('H:i:s', $time) . ')(info) message', - $this->formatter->format($message, []) + $this->formatter->format($message, []), ); } @@ -218,13 +220,13 @@ public function testFormatWithTraceInContext(string $expectedTrace, array $trace public function invalidCallableReturnStringProvider(): array { return [ - 'string' => [fn () => true], - 'int' => [fn () => 1], - 'float' => [fn () => 1.1], - 'array' => [fn () => []], - 'null' => [fn () => null], - 'callable' => [fn () => static fn () => 'a'], - 'object' => [fn () => new stdClass()], + 'string' => [fn() => true], + 'int' => [fn() => 1], + 'float' => [fn() => 1.1], + 'array' => [fn() => []], + 'null' => [fn() => null], + 'callable' => [fn() => static fn() => 'a'], + 'object' => [fn() => new stdClass()], ]; } diff --git a/tests/PsrTargetTest.php b/tests/PsrTargetTest.php index 69664bb5..ed842b5d 100644 --- a/tests/PsrTargetTest.php +++ b/tests/PsrTargetTest.php @@ -14,13 +14,15 @@ use function json_encode; +use const JSON_THROW_ON_ERROR; + final class PsrTargetTest extends TestCase { private PsrTarget $target; public function setUp(): void { - $this->target = new PsrTarget(new class () implements LoggerInterface { + $this->target = new PsrTarget(new class implements LoggerInterface { use LoggerTrait; public string $message = ''; @@ -60,7 +62,7 @@ public function testPsrLogInterfaceMethods(string $level, string $message, array public function testSetLevelsViaConstructor(): void { $target = new PsrTarget( - new class () implements LoggerInterface { + new class implements LoggerInterface { use LoggerTrait; public function log($level, $message, array $context = []): void @@ -68,7 +70,7 @@ public function log($level, $message, array $context = []): void echo "$level: $message"; } }, - [LogLevel::ERROR, LogLevel::INFO] + [LogLevel::ERROR, LogLevel::INFO], ); $target->collect( @@ -77,7 +79,7 @@ public function log($level, $message, array $context = []): void new Message(LogLevel::DEBUG, 'message-2', ['foo' => true]), new Message(LogLevel::ERROR, 'message-3', ['foo' => 1]), ], - true + true, ); $this->expectOutputString('info: message-1error: message-3'); diff --git a/tests/StreamTargetTest.php b/tests/StreamTargetTest.php index 916aeb75..4d5943b8 100644 --- a/tests/StreamTargetTest.php +++ b/tests/StreamTargetTest.php @@ -79,42 +79,42 @@ public function testExportThrowExceptionForErrorWritingToStream($stream): void $this->exportStreamTarget($target); } - /** - * @param resource|string $stream - */ - private function createStreamTarget($stream): StreamTarget + public function testSetLevelsViaConstructor(): void { - $target = new StreamTarget($stream); - $target->setFormat(static fn (Message $message) => "[{$message->level()}] {$message->message()}"); - return $target; - } + $target = new StreamTarget('php://output', [LogLevel::ERROR, LogLevel::INFO]); + $target->setFormat(static fn(Message $message) => "[{$message->level()}] {$message->message()}"); - private function exportStreamTarget(StreamTarget $target): void - { $target->collect( [ new Message(LogLevel::INFO, 'message-1', ['foo' => 'bar']), new Message(LogLevel::DEBUG, 'message-2', ['foo' => true]), new Message(LogLevel::ERROR, 'message-3', ['foo' => 1]), ], - true + true, ); + + $this->expectOutputString("[info] message-1\n[error] message-3\n"); } - public function testSetLevelsViaConstructor(): void + /** + * @param resource|string $stream + */ + private function createStreamTarget($stream): StreamTarget { - $target = new StreamTarget('php://output', [LogLevel::ERROR, LogLevel::INFO]); - $target->setFormat(static fn (Message $message) => "[{$message->level()}] {$message->message()}"); + $target = new StreamTarget($stream); + $target->setFormat(static fn(Message $message) => "[{$message->level()}] {$message->message()}"); + return $target; + } + private function exportStreamTarget(StreamTarget $target): void + { $target->collect( [ new Message(LogLevel::INFO, 'message-1', ['foo' => 'bar']), new Message(LogLevel::DEBUG, 'message-2', ['foo' => true]), new Message(LogLevel::ERROR, 'message-3', ['foo' => 1]), ], - true + true, ); - - $this->expectOutputString("[info] message-1\n[error] message-3\n"); } } diff --git a/tests/TargetTest.php b/tests/TargetTest.php index 9612390d..9caae345 100644 --- a/tests/TargetTest.php +++ b/tests/TargetTest.php @@ -20,6 +20,9 @@ use function implode; use function strtoupper; use function ucfirst; +use function count; + +use const JSON_THROW_ON_ERROR; final class TargetTest extends TestCase { @@ -91,12 +94,12 @@ public function testFilter(array $filter, array $expected): void $logger->log(LogLevel::ERROR, 'testI', ['category' => 'Yiisoft\Db\Command::query']); $messages = $this->target->getMessages(); - $texts = array_map(static fn (Message $message): string => $message->message(), $messages); + $texts = array_map(static fn(Message $message): string => $message->message(), $messages); $this->assertCount( count($expected), $messages, - 'Expected ' . implode(',', $expected) . ', got ' . implode(',', $texts) + 'Expected ' . implode(',', $expected) . ', got ' . implode(',', $texts), ); $i = 0; @@ -114,19 +117,19 @@ public function testEnabled(): void $this->assertFalse($this->target->isEnabled()); $enabled = true; - $this->target->setEnabled(static fn () => $enabled); + $this->target->setEnabled(static fn() => $enabled); $this->assertTrue($this->target->isEnabled()); } public function invalidCallableEnabledProvider(): array { return [ - 'string' => [fn () => 'a'], - 'int' => [fn () => 1], - 'float' => [fn () => 1.1], - 'array' => [fn () => []], - 'callable' => [fn () => static fn () => true], - 'object' => [fn () => new stdClass()], + 'string' => [fn() => 'a'], + 'int' => [fn() => 1], + 'float' => [fn() => 1.1], + 'array' => [fn() => []], + 'callable' => [fn() => static fn() => true], + 'object' => [fn() => new stdClass()], ]; } @@ -223,7 +226,7 @@ public function invalidStringListProvider(): array 'float' => [[1.1]], 'array' => [[[]]], 'bool' => [[true]], - 'callable' => [[fn () => null]], + 'callable' => [[fn() => null]], 'object' => [[new stdClass()]], ]; } @@ -257,7 +260,7 @@ public function testSetLevelsThrowExceptionForNonStringList(array $list): void public function testSetFormat(): void { - $this->target->setFormat(static fn (Message $message) => "[{$message->level()}][{$message->context('category')}] {$message->message()}"); + $this->target->setFormat(static fn(Message $message) => "[{$message->level()}][{$message->context('category')}] {$message->message()}"); $expected = '[info][app] message'; $this->collectOneAndExport(LogLevel::INFO, 'message', ['category' => 'app']); @@ -266,7 +269,7 @@ public function testSetFormat(): void public function testSetPrefix(): void { - $this->target->setPrefix(static fn () => 'Prefix: '); + $this->target->setPrefix(static fn() => 'Prefix: '); $expected = '2017-10-16 13:26:30.608300 Prefix: [info][app] message' . "\n\nMessage context:\n\ncategory: 'app'\ntime: 1508160390.6083\n"; $this->collectOneAndExport(LogLevel::INFO, 'message', ['category' => 'app', 'time' => 1_508_160_390.6083]); @@ -275,8 +278,8 @@ public function testSetPrefix(): void public function testSetFormatAndSetPrefix(): void { - $this->target->setFormat(static fn (Message $message) => "({$message->level()}) {$message->message()}"); - $this->target->setPrefix(static fn (Message $message) => strtoupper($message->context('category') . ': ')); + $this->target->setFormat(static fn(Message $message) => "({$message->level()}) {$message->message()}"); + $this->target->setPrefix(static fn(Message $message) => strtoupper($message->context('category') . ': ')); $expected = 'APP: (info) message'; $this->collectOneAndExport(LogLevel::INFO, 'message', ['category' => 'app']); @@ -308,8 +311,8 @@ public function collectMessageProvider(): array */ public function testFormatMessagesWithSeparatorAndSetFormatAndSetPrefix(array $messages, bool $export): void { - $this->target->setFormat(static fn (Message $message) => "({$message->level()}) {$message->message()}"); - $this->target->setPrefix(static fn (Message $message) => strtoupper($message->context('category') . ': ')); + $this->target->setFormat(static fn(Message $message) => "({$message->level()}) {$message->message()}"); + $this->target->setPrefix(static fn(Message $message) => strtoupper($message->context('category') . ': ')); $expected = "APP: (info) message-1\nAPP: (debug) message-2\n"; $this->target->collect($messages, $export); @@ -322,8 +325,8 @@ public function testFormatMessagesWithSeparatorAndSetFormatAndSetPrefix(array $m */ public function testGetFormattedMessagesAndSetFormatAndSetPrefix(array $messages, bool $export): void { - $this->target->setFormat(static fn (Message $message) => "({$message->level()}) {$message->message()}"); - $this->target->setPrefix(static fn (Message $message) => strtoupper($message->context('category') . ': ')); + $this->target->setFormat(static fn(Message $message) => "({$message->level()}) {$message->message()}"); + $this->target->setPrefix(static fn(Message $message) => strtoupper($message->context('category') . ': ')); $expected = ['APP: (info) message-1', 'APP: (debug) message-2']; $this->target->collect($messages, $export); @@ -337,7 +340,7 @@ public function testGetFormattedMessagesAndSetFormatAndSetPrefix(array $messages public function testSetExportIntervalAndSetFormat(array $messages, bool $export): void { $this->target->setExportInterval(3); - $this->target->setFormat(static fn (Message $message) => "[{$message->level()}][{$message->context('category')}] {$message->message()}"); + $this->target->setFormat(static fn(Message $message) => "[{$message->level()}][{$message->context('category')}] {$message->message()}"); $this->target->collect($messages, $export); $this->assertSame((int) $export, $this->target->getExportCount()); @@ -351,10 +354,10 @@ public function contextProvider(): array 'float' => [['foo' => 1.1], 'foo: 1.1'], 'array' => [['foo' => []], 'foo: []'], 'null' => [['foo' => null], 'foo: null'], - 'callable' => [['foo' => fn () => null], 'foo: fn () => null'], + 'callable' => [['foo' => fn() => null], 'foo: fn() => null'], 'exception' => [['foo' => $exception = new Exception('some error')], "foo: {$exception->__toString()}"], 'stringable-object' => [ - ['foo' => new class () { + ['foo' => new class { public function __toString(): string { return 'stringable-object'; @@ -396,7 +399,7 @@ public function testSetCommonContext(array $commonContext, string $expected): vo public function testSetFormatWithoutMessageContextAndSetCommonContext(): void { $this->target->setCommonContext($commonContext = ['foo' => 'bar', 'baz' => true]); - $this->target->setFormat(static fn (Message $message, array $commonContext) => "[{$message->level()}] {$message->message()}, common context: " . json_encode($commonContext, JSON_THROW_ON_ERROR)); + $this->target->setFormat(static fn(Message $message, array $commonContext) => "[{$message->level()}] {$message->message()}, common context: " . json_encode($commonContext, JSON_THROW_ON_ERROR)); $this->collectOneAndExport(LogLevel::INFO, 'message'); $expected = '[info] message, common context: {"foo":"bar","baz":true}'; @@ -407,12 +410,12 @@ public function testSetFormatWithoutMessageContextAndSetCommonContext(): void public function invalidCallableReturnStringProvider(): array { return [ - 'string' => [fn () => true], - 'int' => [fn () => 1], - 'float' => [fn () => 1.1], - 'array' => [fn () => []], - 'callable' => [fn () => static fn () => 'a'], - 'object' => [fn () => new stdClass()], + 'string' => [fn() => true], + 'int' => [fn() => 1], + 'float' => [fn() => 1.1], + 'array' => [fn() => []], + 'callable' => [fn() => static fn() => 'a'], + 'object' => [fn() => new stdClass()], ]; } @@ -436,7 +439,7 @@ public function invalidMessageListProvider(): array 'bool' => [[true]], 'null' => [[null]], 'array' => [[[]]], - 'callable' => [[fn () => null]], + 'callable' => [[fn() => null]], 'object' => [[new stdClass()]], ]; } diff --git a/tests/TestAsset/StringableObject.php b/tests/TestAsset/StringableObject.php index 99de541a..a307597a 100644 --- a/tests/TestAsset/StringableObject.php +++ b/tests/TestAsset/StringableObject.php @@ -10,8 +10,7 @@ final class StringableObject implements Stringable { public function __construct( private string $string, - ) { - } + ) {} public function __toString(): string { diff --git a/tests/TestAsset/StubContextProvider.php b/tests/TestAsset/StubContextProvider.php index 6ec17b2f..270d901a 100644 --- a/tests/TestAsset/StubContextProvider.php +++ b/tests/TestAsset/StubContextProvider.php @@ -10,8 +10,7 @@ final class StubContextProvider implements ContextProviderInterface { public function __construct( private array $context = [], - ) { - } + ) {} public function getContext(): array { From 41b0fa5a96ee8c4a82940c93a1e9b25304af20e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=A1=D0=BF=D0=B8?= =?UTF-8?q?=D1=80=D0=BA=D0=BE=D0=B2?= Date: Tue, 27 Jan 2026 16:57:20 +0400 Subject: [PATCH 3/5] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b97922af..4b543463 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - Enh #132: Add benchmarks, improve performance of `Message::parse()` (@samdark) - Bug #130: Updated `Message::parse()` to correctly support multiple placeholders (@technicated) - Chg #130, #133: Changed `Message::parse()` to conform to PSR-3 (@technicated, @vjik) +- Enh #137: Explicitly import classes, functions, and constants in "use" section (@mspirkov) ## 2.2.0 December 13, 2025 From 57a1306cd8c359c882fdf8e56bcaacc6b2ab0bca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=A1=D0=BF=D0=B8?= =?UTF-8?q?=D1=80=D0=BA=D0=BE=D0=B2?= Date: Tue, 27 Jan 2026 17:12:19 +0400 Subject: [PATCH 4/5] fix composer-require-checker installation --- tools/{ => composer-require-checker}/composer.json | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tools/{ => composer-require-checker}/composer.json (100%) diff --git a/tools/composer.json b/tools/composer-require-checker/composer.json similarity index 100% rename from tools/composer.json rename to tools/composer-require-checker/composer.json From 67ef97d3e7eeaf67d7a3ecf9993f4b70137f904e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=A1=D0=BF=D0=B8?= =?UTF-8?q?=D1=80=D0=BA=D0=BE=D0=B2?= Date: Tue, 27 Jan 2026 18:12:28 +0400 Subject: [PATCH 5/5] fix PHP version --- .github/workflows/rector-cs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rector-cs.yml b/.github/workflows/rector-cs.yml index 03b7c75c..de7ea7fc 100644 --- a/.github/workflows/rector-cs.yml +++ b/.github/workflows/rector-cs.yml @@ -25,4 +25,4 @@ jobs: token: ${{ secrets.YIISOFT_GITHUB_TOKEN }} with: repository: ${{ github.event.pull_request.head.repo.full_name }} - php: '8.1' + php: '8.0'