diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b6e7a16..dc46de4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,18 +24,20 @@ jobs: strategy: matrix: - php: ['8.0', 8.1, 8.2] - lib: - - { laravel: ^11.0 } - - { laravel: ^10.0 } - - { laravel: ^9.0 } + php: [8.2, 8.3, 8.4] + laravel: [^11.0, ^12.0, ^13.0.x-dev] exclude: - - { php: 8.0, lib: { laravel: ^10.0 } } - - { php: 8.0, lib: { laravel: ^11.0 } } - - { php: 8.1, lib: { laravel: ^11.0 } } + - php: 8.2 + laravel: ^13.0.x-dev include: - - { lib: { laravel: ^9.0 }, phpstan: 1 } - - { lib: { laravel: ^10.0 }, phpstan: 1 } + - php: 8.2 + php-cs-fixer: 1 + - php: 8.3 + php-cs-fixer: 1 + - laravel: ^11.0 + larastan: 1 + - laravel: ^12.0 + larastan: 1 steps: - uses: actions/checkout@v3 @@ -46,27 +48,39 @@ jobs: php-version: ${{ matrix.php }} coverage: xdebug - - name: Remove impossible dependencies - if: ${{ matrix.phpstan != 1 }} + - name: Remove impossible dependencies (nunomaduro/larastan) + if: ${{ matrix.larastan != 1 }} run: composer remove nunomaduro/larastan --dev --no-update + - name: Remove impossible dependencies (friendsofphp/php-cs-fixer) + if: ${{ matrix.php-cs-fixer != 1 }} + run: composer remove friendsofphp/php-cs-fixer --dev --no-update + - name: Adjust Package Versions run: | - composer require "laravel/framework:${{ matrix.lib.laravel }}" --dev + composer require "laravel/framework:${{ matrix.laravel }}" --dev --no-update + composer update + + - name: Prepare Coverage Directory + run: mkdir -p build/logs + + - name: PHP-CS-Fixer + if: ${{ matrix.php-cs-fixer == 1 }} + run: composer cs - name: PHPStan - if: ${{ matrix.phpstan == 1 }} + if: ${{ matrix.larastan == 1 }} run: composer phpstan - - run: mkdir -p build/logs - - run: vendor/bin/phpunit --coverage-clover build/logs/clover.xml + - name: Test + run: composer test -- --testdox --coverage-clover build/logs/clover.xml - name: Upload Coverage uses: nick-invision/retry@v2 env: COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }} COVERALLS_PARALLEL: 'true' - COVERALLS_FLAG_NAME: 'laravel:${{ matrix.lib.laravel }}' + COVERALLS_FLAG_NAME: "laravel:${{ matrix.laravel }} php:${{ matrix.php }}" with: timeout_minutes: 1 max_attempts: 3 diff --git a/.gitignore b/.gitignore index afc62df..36be102 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,5 @@ composer.lock /.idea/ /vendor/ /build/logs/ -.php_cs.cache +.php-cs-fixer.cache /.phpunit.cache/ diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php new file mode 100644 index 0000000..1b47ed4 --- /dev/null +++ b/.php-cs-fixer.php @@ -0,0 +1,90 @@ +setFinder( + (new Finder()) + ->in([ + __DIR__ . '/src', + __DIR__ . '/phpstan', + __DIR__ . '/tests', + ]), + ) + ->setRules([ + '@Symfony' => true, + '@Symfony:risky' => true, + '@PhpCsFixer' => true, + '@PhpCsFixer:risky' => true, + '@PHP80Migration' => true, + '@PHP80Migration:risky' => true, + '@PSR12' => true, + '@PHPUnit84Migration:risky' => true, + 'blank_line_before_statement' => [ + 'statements' => [ + 'break', + 'case', + 'continue', + 'declare', + 'default', + 'exit', + 'goto', + 'include', + 'include_once', + 'phpdoc', + 'require', + 'require_once', + 'return', + 'switch', + 'throw', + 'try', + ], + ], + 'cast_spaces' => ['space' => 'none'], + 'concat_space' => ['spacing' => 'one'], + 'control_structure_continuation_position' => true, + 'date_time_immutable' => true, + 'declare_parentheses' => true, + 'echo_tag_syntax' => ['format' => 'short'], + 'final_internal_class' => false, + 'general_phpdoc_annotation_remove' => true, + 'global_namespace_import' => [ + 'import_classes' => true, + 'import_constants' => true, + 'import_functions' => true, + ], + 'heredoc_indentation' => false, + 'multiline_whitespace_before_semicolons' => ['strategy' => 'no_multi_line'], + 'native_constant_invocation' => false, + 'native_function_invocation' => false, + 'nullable_type_declaration_for_default_null_value' => true, + 'php_unit_internal_class' => false, + 'php_unit_method_casing' => false, + 'php_unit_strict' => false, + 'php_unit_test_annotation' => false, + 'php_unit_test_case_static_method_calls' => ['call_type' => 'this'], + 'php_unit_test_class_requires_covers' => false, + 'phpdoc_line_span' => true, + 'phpdoc_separation' => false, + 'phpdoc_summary' => false, + 'phpdoc_to_comment' => ['ignored_tags' => ['noinspection']], + 'phpdoc_types_order' => false, + 'regular_callable_call' => true, + 'simplified_if_return' => true, + 'simplified_null_return' => true, + 'single_line_throw' => false, + 'trailing_comma_in_multiline' => [ + 'elements' => ['arrays', 'arguments', 'parameters'], + ], + 'types_spaces' => false, + 'use_arrow_functions' => false, + 'yoda_style' => [ + 'equal' => false, + 'identical' => false, + 'less_and_greater' => false, + ], + ]) + ->setRiskyAllowed(true); diff --git a/.scrutinizer.yml b/.scrutinizer.yml deleted file mode 100644 index bc4e2ef..0000000 --- a/.scrutinizer.yml +++ /dev/null @@ -1,47 +0,0 @@ -checks: - php: - code_rating: true - -filter: - excluded_paths: - - phpstan/* - - tests/* - - vendor/* - -build: - - image: default-bionic - - nodes: - analysis: - tests: - override: - - php-scrutinizer-run - custom-nodes: - services: - custom-mysql: - image: docker.io/library/mysql:5.7 - env: - MYSQL_DATABASE: testing - MYSQL_USER: testing - MYSQL_PASSWORD: testing - MYSQL_ROOT_PASSWORD: testing - ports: - - 3306 - - environment: - php: '8.1.8' - docker: true - - dependencies: - before: - - composer install - - mkdir -p build/logs - - tests: - override: - - - command: 'XDEBUG_MODE=coverage vendor/bin/phpunit --coverage-clover build/logs/clover.xml' - coverage: - file: 'build/logs/clover.xml' - format: 'clover' diff --git a/README.md b/README.md index 43648f5..c3373bf 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Laravel MySQL System Variable Manager
[![Build Status](https://github.com/mpyw/laravel-mysql-system-variable-manager/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/mpyw/laravel-mysql-system-variable-manager/actions) [![Coverage Status](https://coveralls.io/repos/github/mpyw/laravel-mysql-system-variable-manager/badge.svg?branch=migrate-ci)](https://coveralls.io/github/mpyw/laravel-mysql-system-variable-manager?branch=migrate-ci) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/mpyw/laravel-mysql-system-variable-manager/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/mpyw/laravel-mysql-system-variable-manager/?branch=master) +# Laravel MySQL System Variable Manager
[![Build Status](https://github.com/mpyw/laravel-mysql-system-variable-manager/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/mpyw/laravel-mysql-system-variable-manager/actions) [![Coverage Status](https://coveralls.io/repos/github/mpyw/laravel-mysql-system-variable-manager/badge.svg?branch=migrate-ci)](https://coveralls.io/github/mpyw/laravel-mysql-system-variable-manager?branch=migrate-ci) A tiny extension of `MySqlConnection` that manages **session** system variables @@ -6,9 +6,12 @@ A tiny extension of `MySqlConnection` that manages **session** system variables | Package | Version | Mandatory | |:--------|:--------------------------------------|:---------:| -| PHP | ^8.0 | ✅ | -| Laravel | ^9.0 || ^10.0 | ✅ | -| PHPStan | >=1.1 | | +| PHP | ^8.2 | ✅ | +| Laravel | ^11.0 || ^12.0 | ✅ | +| PHPStan | >=2.0 | | + +> [!NOTE] +> Older versions have outdated dependency requirements. If you cannot prepare the latest environment, please refer to past releases. ## Installing diff --git a/_ide_helper.php b/_ide_helper.php index 0159066..b726064 100644 --- a/_ide_helper.php +++ b/_ide_helper.php @@ -1,7 +1,11 @@ =7.0", - "phpunit/phpunit": ">=9.5", - "phpstan/phpstan": ">=1.1", - "phpstan/extension-installer": ">=1.1", - "nunomaduro/larastan": ">=1.0" + "orchestra/testbench-core": ">=9.0", + "phpunit/phpunit": ">=11.0", + "phpstan/phpstan": ">=2.0", + "phpstan/extension-installer": ">=1.4", + "nunomaduro/larastan": ">=3.1", + "friendsofphp/php-cs-fixer": "^3.70" }, "scripts": { "test": "vendor/bin/phpunit", - "phpstan": "vendor/bin/phpstan analyse src tests phpstan" + "phpstan": "vendor/bin/phpstan analyse src tests phpstan", + "cs": "vendor/bin/php-cs-fixer fix --dry-run", + "cs:fix": "vendor/bin/php-cs-fixer fix" }, "minimum-stability": "dev", "prefer-stable": true, diff --git a/phpstan.neon b/phpstan.neon index 2a71b8d..9d94d4b 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -3,7 +3,6 @@ includes: parameters: level: 9 - checkMissingIterableValueType: false reportUnmatchedIgnoredErrors: false ignoreErrors: - message: '#Cannot access property \$value on mixed#' diff --git a/phpstan/CallableArgumentParameter.php b/phpstan/CallableArgumentParameter.php index 6c9092d..f720295 100644 --- a/phpstan/CallableArgumentParameter.php +++ b/phpstan/CallableArgumentParameter.php @@ -1,5 +1,7 @@ getName(), $methods, true); + return in_array($methodReflection->getName(), $methods, true); } - public function getTypeFromStaticMethodCall(MethodReflection $methodReflection, StaticCall $methodCall, Scope $scope): \PHPStan\Type\Type + public function getTypeFromStaticMethodCall(MethodReflection $methodReflection, StaticCall $methodCall, Scope $scope): Type { if ($methodReflection->getName()[0] === 's') { return new ObjectType(Connection::class); } - $offset = $methodReflection->getName()[\strlen($methodReflection->getName()) - 1] === 's' ? 1 : 2; + $offset = $methodReflection->getName()[strlen($methodReflection->getName()) - 1] === 's' ? 1 : 2; - if (\count($methodCall->getArgs()) > $offset) { + if (count($methodCall->getArgs()) > $offset) { $type = $scope->getType($methodCall->getArgs()[$offset]->value); if ($type instanceof ParametersAcceptor) { diff --git a/phpstan/CallableParameter.php b/phpstan/CallableParameter.php index e432187..4a50ead 100644 --- a/phpstan/CallableParameter.php +++ b/phpstan/CallableParameter.php @@ -1,5 +1,7 @@ */ private array $argumentParameters; /** - * @param CallableArgumentParameter[] $argumentParameters + * @param list $argumentParameters */ public function __construct(array $argumentParameters) { diff --git a/phpstan/CallableReturnTypeExtension.php b/phpstan/CallableReturnTypeExtension.php index 9306e2d..dfff8f1 100644 --- a/phpstan/CallableReturnTypeExtension.php +++ b/phpstan/CallableReturnTypeExtension.php @@ -1,5 +1,7 @@ getName(), $methods, true); + return in_array($methodReflection->getName(), $methods, true); } public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): Type @@ -37,9 +43,9 @@ public function getTypeFromMethodCall(MethodReflection $methodReflection, Method return new ThisType($methodReflection->getDeclaringClass()); } - $offset = $methodReflection->getName()[\strlen($methodReflection->getName()) - 1] === 's' ? 1 : 2; + $offset = $methodReflection->getName()[strlen($methodReflection->getName()) - 1] === 's' ? 1 : 2; - if (\count($methodCall->getArgs()) > $offset) { + if (count($methodCall->getArgs()) > $offset) { $type = $scope->getType($methodCall->getArgs()[$offset]->value); if ($type instanceof ParametersAcceptor) { diff --git a/phpstan/ConnectionClassExtension.php b/phpstan/ConnectionClassExtension.php index 841a23d..4b2e355 100644 --- a/phpstan/ConnectionClassExtension.php +++ b/phpstan/ConnectionClassExtension.php @@ -1,5 +1,7 @@ getName(), ConnectionInterface::class, true); + return in_array($methodName, $methods, true) + && $classReflection->is(ConnectionInterface::class); } public function getMethod(ClassReflection $classReflection, string $methodName): MethodReflection diff --git a/phpstan/KeyParameter.php b/phpstan/KeyParameter.php index 4ce858c..a0f9b1a 100644 --- a/phpstan/KeyParameter.php +++ b/phpstan/KeyParameter.php @@ -1,5 +1,7 @@ + */ public function getVariants(): array { return $this->getName()[0] === 's' @@ -67,12 +74,15 @@ public function getVariants(): array : $this->getUsingVariants(); } + /** + * @return list + */ private function getSetVariants(): array { return [new FunctionVariant( TemplateTypeMap::createEmpty(), null, - $this->getName()[\strlen($this->getName()) - 1] === 's' + $this->getName()[strlen($this->getName()) - 1] === 's' ? [ new ValuesParameter(), new MemoizeParameter(), @@ -87,9 +97,12 @@ private function getSetVariants(): array )]; } + /** + * @return list + */ private function getUsingVariants(): array { - $baseArgs = $this->getName()[\strlen($this->getName()) - 1] === 's' + $baseArgs = $this->getName()[strlen($this->getName()) - 1] === 's' ? [ new ValuesParameter(), ] @@ -142,7 +155,7 @@ public function isInternal(): TrinaryLogic return TrinaryLogic::createNo(); } - public function getThrowType(): ?Type + public function getThrowType(): Type { return new ObjectType(QueryException::class); } diff --git a/phpstan/ValueParameter.php b/phpstan/ValueParameter.php index e8bf8a7..5bfcdb9 100644 --- a/phpstan/ValueParameter.php +++ b/phpstan/ValueParameter.php @@ -1,5 +1,7 @@ - - + + + - src + ./src - + + + + - ./tests/ + ./tests diff --git a/src/ExpressionInterface.php b/src/ExpressionInterface.php index dac89b1..c940ac3 100644 --- a/src/ExpressionInterface.php +++ b/src/ExpressionInterface.php @@ -1,5 +1,7 @@ getType()) { case ExpressionInterface::TYPE_INTEGER: return PDO::PARAM_INT; + case ExpressionInterface::TYPE_BOOLEAN: return PDO::PARAM_BOOL; + case ExpressionInterface::TYPE_FLOAT: case ExpressionInterface::TYPE_STRING: default: @@ -39,6 +43,7 @@ public function getPlaceholder(): string switch ($this->getType()) { case ExpressionInterface::TYPE_FLOAT: return 'cast(? as decimal(65, 30))'; + case ExpressionInterface::TYPE_INTEGER: case ExpressionInterface::TYPE_BOOLEAN: case ExpressionInterface::TYPE_STRING: diff --git a/src/ManagesSystemVariables.php b/src/ManagesSystemVariables.php index 0af6351..33cbd76 100644 --- a/src/ManagesSystemVariables.php +++ b/src/ManagesSystemVariables.php @@ -1,5 +1,7 @@ $values * @return $this */ public function setSystemVariables(array $values, bool $memoizeForReconnect = true) { + // @phpstan-ignore-next-line assign.propertyType (new SystemVariableMemoizedAssigner($this->reconnector, $this->readPdo, $this->pdo)) ->assign($values, $memoizeForReconnect); @@ -54,12 +56,12 @@ public function usingSystemVariable(string $key, $value, callable $callback, ... * Run callback temporarily setting MySQL system variables for both read and write PDOs. * It is lazily executed for unresolved PDO instance. * - * @param array $values - * @param mixed ...$args + * @param array $values * @return mixed */ - public function usingSystemVariables(array $values, callable $callback, ...$args) + public function usingSystemVariables(array $values, callable $callback, mixed ...$args) { + // @phpstan-ignore-next-line assign.propertyType return (new SystemVariableTemporaryAssigner($this->readPdo, $this->pdo)) ->using($values, $callback, ...$args); } diff --git a/src/MySqlConnection.php b/src/MySqlConnection.php index 2d4eef7..d0f3005 100644 --- a/src/MySqlConnection.php +++ b/src/MySqlConnection.php @@ -1,5 +1,7 @@ pdos = \array_filter($pdos); + $this->pdos = array_filter($pdos); } /** * Set MySQL system variables for PDO. * - * @param array $values + * @param array $values * @return $this */ public function assign(array $values) @@ -47,9 +53,12 @@ public function assign(array $values) /** * Configure PDO using query and parameters temporarily enabling PDO::ATTR_EMULATE_PREPARES. * - * @param array $values + * @param array $values * @return $this */ + /** + * @phpstan-ignore-next-line missingType.iterableValue + */ protected function withEmulatedStatement(string $query, array $values = []) { foreach ($this->pdos as &$pdo) { @@ -57,7 +66,7 @@ protected function withEmulatedStatement(string $query, array $values = []) $pdo, Closure::fromCallable([$this, 'withEmulatedStatementFor']), $query, - $values + $values, ); } unset($pdo); @@ -66,7 +75,10 @@ protected function withEmulatedStatement(string $query, array $values = []) } /** - * @param array $values + * @param array $values + */ + /** + * @phpstan-ignore-next-line missingType.iterableValue */ protected static function withEmulatedStatementFor(PDO $pdo, string $query, array $values): PDO { @@ -74,16 +86,19 @@ protected static function withEmulatedStatementFor(PDO $pdo, string $query, arra Closure::fromCallable([static::class, 'withStatementFor']), $pdo, $query, - $values + $values, ); } /** - * @param array $values + * @param array $values + */ + /** + * @phpstan-ignore-next-line missingType.iterableValue */ protected static function withStatementFor(PDO $pdo, string $query, array $values): PDO { - $expressions = \array_map([Value::class, 'wrap'], $values); + $expressions = array_map([Value::class, 'wrap'], $values); $original = static::selectOriginalVariablesForReplacer($pdo, $expressions); $statement = $pdo->prepare($query); @@ -97,12 +112,12 @@ protected static function withStatementFor(PDO $pdo, string $query, array $value } /** - * @param \Mpyw\LaravelMySqlSystemVariableManager\ExpressionInterface[] $expressions - * @return \Mpyw\LaravelMySqlSystemVariableManager\ValueInterface[] + * @param ExpressionInterface[] $expressions + * @return ValueInterface[] */ protected static function selectOriginalVariablesForReplacer(PDO $pdo, array $expressions): array { - $replacers = \array_filter($expressions, function ($value) { + $replacers = array_filter($expressions, static function ($value) { return $value instanceof IntegerReplacerInterface || $value instanceof BooleanReplacerInterface || $value instanceof FloatReplacerInterface @@ -116,24 +131,29 @@ protected static function bindValue(PDOStatement $statement, int $parameter, Exp { if ($expression instanceof ValueInterface) { $statement->bindValue($parameter, $expression->getValue(), $expression->getParamType()); + return; } if ($original) { if ($expression instanceof IntegerReplacerInterface) { $statement->bindValue($parameter, $expression->replace((int)$original->getValue()), $expression->getParamType()); + return; } if ($expression instanceof BooleanReplacerInterface) { $statement->bindValue($parameter, $expression->replace((bool)$original->getValue()), $expression->getParamType()); + return; } if ($expression instanceof FloatReplacerInterface) { $statement->bindValue($parameter, $expression->replace((float)$original->getValue()), $expression->getParamType()); + return; } if ($expression instanceof StringReplacerInterface) { $statement->bindValue($parameter, $expression->replace((string)$original->getValue()), $expression->getParamType()); + return; } } diff --git a/src/SystemVariableAwareReconnector.php b/src/SystemVariableAwareReconnector.php index b184bc3..9d1d9cb 100644 --- a/src/SystemVariableAwareReconnector.php +++ b/src/SystemVariableAwareReconnector.php @@ -1,17 +1,23 @@ */ protected array $memoizedSystemVariables = []; @@ -29,12 +35,13 @@ public function __construct(?callable $reconnector = null) } /** - * @param array $values + * @param array $values * @return $this */ public function memoizeSystemVariables(array $values) { - $this->memoizedSystemVariables = \array_replace($this->memoizedSystemVariables, $values); + $this->memoizedSystemVariables = array_replace($this->memoizedSystemVariables, $values); + return $this; } @@ -43,9 +50,11 @@ public function memoizeSystemVariables(array $values) */ public function __invoke(ConnectionInterface $connection) { - if (\is_callable($this->reconnector) && \method_exists($connection, 'setSystemVariables')) { + // @phpstan-ignore-next-line function.alreadyNarrowedType + if (is_callable($this->reconnector) && method_exists($connection, 'setSystemVariables')) { $result = ($this->reconnector)($connection); $connection->setSystemVariables($this->memoizedSystemVariables, true); + return $result; } diff --git a/src/SystemVariableGrammar.php b/src/SystemVariableGrammar.php index 1ad161b..d204e1d 100644 --- a/src/SystemVariableGrammar.php +++ b/src/SystemVariableGrammar.php @@ -1,7 +1,13 @@ $values */ public static function assignmentStatement(array $values): string { - return 'set session ' . \implode(', ', static::assignmentExpressions($values)); + return 'set session ' . implode(', ', static::assignmentExpressions($values)); } /** - * @param array $values + * @param array $values * @return string[] */ public static function assignmentExpressions(array $values): array @@ -43,11 +50,12 @@ public static function assignmentExpressions(array $values): array foreach ($values as $name => $value) { $expressions[] = static::escapeIdentifier($name) . '=' . Value::wrap($value)->getPlaceholder(); } + return $expressions; } public static function escapeIdentifier(string $identifier): string { - return '`' . \str_replace('`', '``', $identifier) . '`'; + return '`' . str_replace('`', '``', $identifier) . '`'; } } diff --git a/src/SystemVariableMemoizedAssigner.php b/src/SystemVariableMemoizedAssigner.php index 63d5321..ccd7d23 100644 --- a/src/SystemVariableMemoizedAssigner.php +++ b/src/SystemVariableMemoizedAssigner.php @@ -1,21 +1,31 @@ pdos = \array_filter($pdos); + $this->pdos = array_filter($pdos); } /** * Set MySQL system variables for PDO. * - * @param array $values + * @param array $values * @return $this */ public function assign(array $values, bool $memoizeForReconnect = true) { + // @phpstan-ignore-next-line assign.propertyType (new SystemVariableAssigner(...$this->pdos)) ->assign($values); diff --git a/src/SystemVariableSelector.php b/src/SystemVariableSelector.php index 5ec8790..65e00a2 100644 --- a/src/SystemVariableSelector.php +++ b/src/SystemVariableSelector.php @@ -1,16 +1,22 @@ $newValues + * @return ValueInterface[] */ public static function selectOriginalVariables(PDO $pdo, array $newValues): array { @@ -18,7 +24,7 @@ public static function selectOriginalVariables(PDO $pdo, array $newValues): arra return []; } - $stmt = $pdo->query(SystemVariableGrammar::selectStatement(\array_keys($newValues))); + $stmt = $pdo->query(SystemVariableGrammar::selectStatement(array_keys($newValues))); if (!$stmt) { // @codeCoverageIgnoreStart @@ -28,9 +34,10 @@ public static function selectOriginalVariables(PDO $pdo, array $newValues): arra $original = $stmt->fetch(PDO::FETCH_ASSOC); - \assert(\is_array($original)); + assert(is_array($original)); foreach ($original as $key => $value) { + // @phpstan-ignore-next-line $original[$key] = Value::as(Value::wrap($newValues[$key])->getType(), $value); } diff --git a/src/SystemVariableTemporaryAssigner.php b/src/SystemVariableTemporaryAssigner.php index bcf8767..4221868 100644 --- a/src/SystemVariableTemporaryAssigner.php +++ b/src/SystemVariableTemporaryAssigner.php @@ -1,41 +1,50 @@ pdos = \array_filter($pdos); + $this->pdos = array_filter($pdos); } /** * Temporarily set MySQL system variables for PDO. * - * @param array $using - * @param mixed ...$args + * @param array $using + * @param mixed ...$args * @return $this */ public function using(array $using, callable $callback, ...$args) { - return ValueEffector::withEffectForEach($this->pdos, function (PDO $pdo) use ($using) { + // @phpstan-ignore-next-line: assign.propertyType + return ValueEffector::withEffectForEach($this->pdos, static function (PDO $pdo) use ($using) { $original = SystemVariableSelector::selectOriginalVariables($pdo, $using); (new SystemVariableAssigner($pdo))->assign($using); - return function (PDO $pdo) use ($original) { + return static function (PDO $pdo) use ($original): void { (new SystemVariableAssigner($pdo))->assign($original); }; }, $callback, ...$args); diff --git a/src/Value.php b/src/Value.php index 3a43b2c..677171b 100644 --- a/src/Value.php +++ b/src/Value.php @@ -1,5 +1,7 @@ getReturnType(); if ($returnType instanceof ReflectionNamedType && !$returnType->allowsNull()) { @@ -134,11 +142,10 @@ public function getValue() /** * Return type. - * - * @return string */ public function getType(): string { + // @phpstan-ignore return.type return $this->type; } } diff --git a/src/ValueInterface.php b/src/ValueInterface.php index f0a81a8..e318c50 100644 --- a/src/ValueInterface.php +++ b/src/ValueInterface.php @@ -1,5 +1,7 @@ {$emulated ? 'onEmulatedConnection' : 'onNativeConnection'}(function (MySqlConnection $db) use ($variableName, $expectedOriginal, $newValue, $expectedChanged) { + $this->{$emulated ? 'onEmulatedConnection' : 'onNativeConnection'}(function (MySqlConnection $db) use ($variableName, $expectedOriginal, $newValue, $expectedChanged): void { $this->assertSame($expectedOriginal, $db->selectOne("select @@{$variableName} as value")->value); $db->setSystemVariable($variableName, $newValue); $this->assertSame($expectedChanged, $db->selectOne("select @@{$variableName} as value")->value); @@ -27,16 +29,16 @@ public function testAssignments(string $variableName, bool $emulated, $expectedO /** * @test - * @param mixed $expectedOriginal - * @param mixed $newValue - * @param mixed $expectedChanged + * @param mixed $expectedOriginal + * @param mixed $newValue + * @param mixed $expectedChanged * @dataProvider provideBasicVariables */ public function testTemporaryAssignments(string $variableName, bool $emulated, $expectedOriginal, $newValue, $expectedChanged): void { - $this->{$emulated ? 'onEmulatedConnection' : 'onNativeConnection'}(function (MySqlConnection $db) use ($variableName, $expectedOriginal, $newValue, $expectedChanged) { + $this->{$emulated ? 'onEmulatedConnection' : 'onNativeConnection'}(function (MySqlConnection $db) use ($variableName, $expectedOriginal, $newValue, $expectedChanged): void { $this->assertSame($expectedOriginal, $db->selectOne("select @@{$variableName} as value")->value); - $db->usingSystemVariable($variableName, $newValue, function () use ($expectedChanged, $db, $variableName) { + $db->usingSystemVariable($variableName, $newValue, function () use ($expectedChanged, $db, $variableName): void { $this->assertSame($expectedChanged, $db->selectOne("select @@{$variableName} as value")->value); }); $this->assertSame($expectedOriginal, $db->selectOne("select @@{$variableName} as value")->value); @@ -46,41 +48,44 @@ public function testTemporaryAssignments(string $variableName, bool $emulated, $ /** * @return array */ - public function provideBasicVariables(): array + /** + * @phpstan-ignore-next-line missingType.iterableValue + */ + public static function provideBasicVariables(): iterable { return [ 'assigning float (native)' => ['long_query_time', false, 10.0, 15.0, 15.0], - 'assigning float (emulated)' => ['long_query_time', true, $this->v81('10.000000', 10.0), 15.0, $this->v81('15.000000', 15.0)], + 'assigning float (emulated)' => ['long_query_time', true, 10.0, 15.0, 15.0], 'assigning integer (native)' => ['long_query_time', false, 10.0, 15, 15.0], - 'assigning integer (emulated)' => ['long_query_time', true, $this->v81('10.000000', 10.0), 15, $this->v81('15.000000', 15.0)], + 'assigning integer (emulated)' => ['long_query_time', true, 10.0, 15, 15.0], 'assigning boolean (native)' => ['foreign_key_checks', false, 1, false, 0], - 'assigning boolean (emulated)' => ['foreign_key_checks', true, $this->v81('1', 1), false, $this->v81('0', 0)], + 'assigning boolean (emulated)' => ['foreign_key_checks', true, 1, false, 0], 'assigning string (native)' => ['transaction_isolation', false, 'REPEATABLE-READ', 'read-committed', 'READ-COMMITTED'], 'assigning string (emulated)' => ['transaction_isolation', true, 'REPEATABLE-READ', 'read-committed', 'READ-COMMITTED'], 'assigning wrapped float (native)' => ['long_query_time', false, 10.0, Value::float(15.0), 15.0], - 'assigning wrapped float (emulated)' => ['long_query_time', true, $this->v81('10.000000', 10.0), Value::float(15.0), $this->v81('15.000000', 15.0)], + 'assigning wrapped float (emulated)' => ['long_query_time', true, 10.0, Value::float(15.0), 15.0], 'assigning wrapped integer (native)' => ['long_query_time', false, 10.0, Value::int(15), 15.0], - 'assigning wrapped integer (emulated)' => ['long_query_time', true, $this->v81('10.000000', 10.0), Value::int(15), $this->v81('15.000000', 15.0)], + 'assigning wrapped integer (emulated)' => ['long_query_time', true, 10.0, Value::int(15), 15.0], 'assigning wrapped boolean (native)' => ['foreign_key_checks', false, 1, Value::bool(false), 0], - 'assigning wrapped boolean (emulated)' => ['foreign_key_checks', true, $this->v81('1', 1), Value::bool(false), $this->v81('0', 0)], + 'assigning wrapped boolean (emulated)' => ['foreign_key_checks', true, 1, Value::bool(false), 0], 'assigning wrapped string (native)' => ['transaction_isolation', false, 'REPEATABLE-READ', Value::str('read-committed'), 'READ-COMMITTED'], 'assigning wrapped string (emulated)' => ['transaction_isolation', true, 'REPEATABLE-READ', Value::str('read-committed'), 'READ-COMMITTED'], - 'replacing explicit float (native)' => ['long_query_time', false, 10.0, Replacer::float(function ($v) { return $v + 5.0; }), 15.0], - 'replacing explicit float (emulated)' => ['long_query_time', true, $this->v81('10.000000', 10.0), Replacer::float(function ($v) { return $v + 5.0; }), $this->v81('15.000000', 15.0)], - 'replacing explicit integer (native)' => ['long_query_time', false, 10.0, Replacer::int(function ($v) { return $v + 5; }), 15.0], - 'replacing explicit integer (emulated)' => ['long_query_time', true, $this->v81('10.000000', 10.0), Replacer::int(function ($v) { return $v + 5; }), $this->v81('15.000000', 15.0)], - 'replacing explicit boolean (native)' => ['foreign_key_checks', false, 1, Replacer::bool(function ($v) { return !$v; }), 0], - 'replacing explicit boolean (emulated)' => ['foreign_key_checks', true, $this->v81('1', 1), Replacer::bool(function ($v) { return !$v; }), $this->v81('0', 0)], - 'replacing explicit string (native)' => ['transaction_isolation', false, 'REPEATABLE-READ', Replacer::str(function ($v) { return str_ireplace('repeatable-read', 'read-committed', $v); }), 'READ-COMMITTED'], - 'replacing explicit string (emulated)' => ['transaction_isolation', true, 'REPEATABLE-READ', Replacer::str(function ($v) { return str_ireplace('repeatable-read', 'read-committed', $v); }), 'READ-COMMITTED'], - 'replacing implicit float (native)' => ['long_query_time', false, 10.0, function ($v): float { return $v + 5.0; }, 15.0], - 'replacing implicit float (emulated)' => ['long_query_time', true, $this->v81('10.000000', 10.0), function ($v): float { return $v + 5.0; }, $this->v81('15.000000', 15.0)], - 'replacing implicit integer (native)' => ['long_query_time', false, 10.0, function ($v): int { return $v + 5; }, 15.0], - 'replacing implicit integer (emulated)' => ['long_query_time', true, $this->v81('10.000000', 10.0), function ($v): int { return $v + 5; }, $this->v81('15.000000', 15.0)], - 'replacing implicit boolean (native)' => ['foreign_key_checks', false, 1, function ($v): bool { return !$v; }, 0], - 'replacing implicit boolean (emulated)' => ['foreign_key_checks', true, $this->v81('1', 1), function ($v): bool { return !$v; }, $this->v81('0', 0)], - 'replacing implicit string (native)' => ['transaction_isolation', false, 'REPEATABLE-READ', function ($v): string { return str_ireplace('repeatable-read', 'read-committed', $v); }, 'READ-COMMITTED'], - 'replacing implicit string (emulated)' => ['transaction_isolation', true, 'REPEATABLE-READ', function ($v): string { return str_ireplace('repeatable-read', 'read-committed', $v); }, 'READ-COMMITTED'], + 'replacing explicit float (native)' => ['long_query_time', false, 10.0, Replacer::float(static function ($v) { return $v + 5.0; }), 15.0], + 'replacing explicit float (emulated)' => ['long_query_time', true, 10.0, Replacer::float(static function ($v) { return $v + 5.0; }), 15.0], + 'replacing explicit integer (native)' => ['long_query_time', false, 10.0, Replacer::int(static function ($v) { return $v + 5; }), 15.0], + 'replacing explicit integer (emulated)' => ['long_query_time', true, 10.0, Replacer::int(static function ($v) { return $v + 5; }), 15.0], + 'replacing explicit boolean (native)' => ['foreign_key_checks', false, 1, Replacer::bool(static function ($v) { return !$v; }), 0], + 'replacing explicit boolean (emulated)' => ['foreign_key_checks', true, 1, Replacer::bool(static function ($v) { return !$v; }), 0], + 'replacing explicit string (native)' => ['transaction_isolation', false, 'REPEATABLE-READ', Replacer::str(static function ($v) { return str_ireplace('repeatable-read', 'read-committed', $v); }), 'READ-COMMITTED'], + 'replacing explicit string (emulated)' => ['transaction_isolation', true, 'REPEATABLE-READ', Replacer::str(static function ($v) { return str_ireplace('repeatable-read', 'read-committed', $v); }), 'READ-COMMITTED'], + 'replacing implicit float (native)' => ['long_query_time', false, 10.0, static function ($v): float { return $v + 5.0; }, 15.0], + 'replacing implicit float (emulated)' => ['long_query_time', true, 10.0, static function ($v): float { return $v + 5.0; }, 15.0], + 'replacing implicit integer (native)' => ['long_query_time', false, 10.0, static function ($v): int { return $v + 5; }, 15.0], + 'replacing implicit integer (emulated)' => ['long_query_time', true, 10.0, static function ($v): int { return $v + 5; }, 15.0], + 'replacing implicit boolean (native)' => ['foreign_key_checks', false, 1, static function ($v): bool { return !$v; }, 0], + 'replacing implicit boolean (emulated)' => ['foreign_key_checks', true, 1, static function ($v): bool { return !$v; }, 0], + 'replacing implicit string (native)' => ['transaction_isolation', false, 'REPEATABLE-READ', static function ($v): string { return str_ireplace('repeatable-read', 'read-committed', $v); }, 'READ-COMMITTED'], + 'replacing implicit string (emulated)' => ['transaction_isolation', true, 'REPEATABLE-READ', static function ($v): string { return str_ireplace('repeatable-read', 'read-committed', $v); }, 'READ-COMMITTED'], ]; } @@ -89,7 +94,7 @@ public function testAssigningNullThrowsExceptionOnNative(): void $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('The value must be a scalar, return-type-explicit closure or Mpyw\LaravelMySqlSystemVariableManager\ExpressionInterface instance.'); - $this->onNativeConnection(function (MySqlConnection $db) { + $this->onNativeConnection(static function (MySqlConnection $db): void { $db->setSystemVariable('foreign_key_checks', null); $db->getPdo(); }); @@ -100,7 +105,7 @@ public function testAssigningNullThrowsExceptionOnEmulation(): void $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('The value must be a scalar, return-type-explicit closure or Mpyw\LaravelMySqlSystemVariableManager\ExpressionInterface instance.'); - $this->onEmulatedConnection(function (MySqlConnection $db) { + $this->onEmulatedConnection(static function (MySqlConnection $db): void { $db->setSystemVariable('foreign_key_checks', null); $db->getPdo(); }); @@ -111,7 +116,7 @@ public function testAssigningNullThrowsOnUnresolvedNativeConnection(): void $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('The value must be a scalar, return-type-explicit closure or Mpyw\LaravelMySqlSystemVariableManager\ExpressionInterface instance.'); - $this->onNativeConnection(function (MySqlConnection $db) { + $this->onNativeConnection(static function (MySqlConnection $db): void { $db->setSystemVariable('foreign_key_checks', null); }); } @@ -121,14 +126,14 @@ public function testAssigningNullThrowsOnUnresolvedEmulatedConnection(): void $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('The value must be a scalar, return-type-explicit closure or Mpyw\LaravelMySqlSystemVariableManager\ExpressionInterface instance.'); - $this->onEmulatedConnection(function (MySqlConnection $db) { + $this->onEmulatedConnection(static function (MySqlConnection $db): void { $db->setSystemVariable('foreign_key_checks', null); }); } public function testAssignmentPriorityOnLazilyResolvedConnection(): void { - $this->onNativeConnection(function (MySqlConnection $db) { + $this->onNativeConnection(function (MySqlConnection $db): void { $this->assertPdoNotResolved($db->getName()); $db @@ -147,7 +152,7 @@ public function testAssignmentPriorityOnLazilyResolvedConnection(): void $this->assertPdoResolved($db->getName()); }); - $this->onEmulatedConnection(function (MySqlConnection $db) { + $this->onEmulatedConnection(function (MySqlConnection $db): void { $this->assertPdoNotResolved($db->getName()); $db @@ -161,7 +166,7 @@ public function testAssignmentPriorityOnLazilyResolvedConnection(): void $this->assertPdoResolved($db->getName()); - $this->assertSame($this->v81('13.000000', 13.0), $db->selectOne('select @@long_query_time as value')->value); + $this->assertSame(13.0, $db->selectOne('select @@long_query_time as value')->value); $this->assertPdoResolved($db->getName()); }); @@ -169,7 +174,7 @@ public function testAssignmentPriorityOnLazilyResolvedConnection(): void public function testAssignmentPriorityOnEagerlyResolvedConnection(): void { - $this->onNativeConnection(function (MySqlConnection $db) { + $this->onNativeConnection(function (MySqlConnection $db): void { $this->assertPdoNotResolved($db->getName()); $db->getPdo(); @@ -188,7 +193,7 @@ public function testAssignmentPriorityOnEagerlyResolvedConnection(): void $this->assertPdoResolved($db->getName()); }); - $this->onEmulatedConnection(function (MySqlConnection $db) { + $this->onEmulatedConnection(function (MySqlConnection $db): void { $this->assertPdoNotResolved($db->getName()); $db->getPdo(); @@ -202,7 +207,7 @@ public function testAssignmentPriorityOnEagerlyResolvedConnection(): void $this->assertPdoResolved($db->getName()); - $this->assertSame($this->v81('13.000000', 13.0), $db->selectOne('select @@long_query_time as value')->value); + $this->assertSame(13.0, $db->selectOne('select @@long_query_time as value')->value); $this->assertPdoResolved($db->getName()); }); diff --git a/tests/ReconnectionTest.php b/tests/ReconnectionTest.php index b68863f..35d2170 100644 --- a/tests/ReconnectionTest.php +++ b/tests/ReconnectionTest.php @@ -1,5 +1,7 @@ onNativeConnection(function (MySqlConnection $db) { + $this->onNativeConnection(function (MySqlConnection $db): void { $this->assertSame('REPEATABLE-READ', $db->selectOne('select @@transaction_isolation as value')->value); $this->assertSame(10.0, $db->selectOne('select @@long_query_time as value')->value); @@ -23,9 +25,9 @@ public function testOnlyMemoizedVariablesAreReassigned(): void $this->assertSame(10.0, $db->selectOne('select @@long_query_time as value')->value); }); - $this->onEmulatedConnection(function (MySqlConnection $db) { + $this->onEmulatedConnection(function (MySqlConnection $db): void { $this->assertSame('REPEATABLE-READ', $db->selectOne('select @@transaction_isolation as value')->value); - $this->assertSame($this->v81('10.000000', 10.0), $db->selectOne('select @@long_query_time as value')->value); + $this->assertSame(10.0, $db->selectOne('select @@long_query_time as value')->value); $db ->setSystemVariable('transaction_isolation', 'read-committed') @@ -34,7 +36,7 @@ public function testOnlyMemoizedVariablesAreReassigned(): void $db->reconnect(); $this->assertSame('READ-COMMITTED', $db->selectOne('select @@transaction_isolation as value')->value); - $this->assertSame($this->v81('10.000000', 10.0), $db->selectOne('select @@long_query_time as value')->value); + $this->assertSame(10.0, $db->selectOne('select @@long_query_time as value')->value); }); } diff --git a/tests/TestCase.php b/tests/TestCase.php index 4ebad34..c26ecfb 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -1,5 +1,7 @@ assertInstanceOf(Closure::class, $this->getConnectionPropertyValue($connection, 'pdo')); } - - /** - * @param mixed $v80 - * @param mixed $v81 - * @return mixed - */ - protected function v81($v80, $v81) - { - // Since PHP 8.1, always get native number regardless of emulation. - return version_compare(PHP_VERSION, '8.1', '<') - ? $v80 - : $v81; - } }