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 @@ +<?php + +declare(strict_types=1); + +use PhpCsFixer\Config; +use PhpCsFixer\Finder; + +return (new Config()) + ->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<br>[](https://github.com/mpyw/laravel-mysql-system-variable-manager/actions) [](https://coveralls.io/github/mpyw/laravel-mysql-system-variable-manager?branch=migrate-ci) [](https://scrutinizer-ci.com/g/mpyw/laravel-mysql-system-variable-manager/?branch=master) +# Laravel MySQL System Variable Manager<br>[](https://github.com/mpyw/laravel-mysql-system-variable-manager/actions) [](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 | <code>^8.0</code> | ✅ | -| Laravel | <code>^9.0 || ^10.0 </code> | ✅ | -| PHPStan | <code>>=1.1</code> | | +| PHP | <code>^8.2</code> | ✅ | +| Laravel | <code>^11.0 || ^12.0</code> | ✅ | +| PHPStan | <code>>=2.0</code> | | + +> [!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 @@ <?php +declare(strict_types=1); + namespace Illuminate\Database { + use Mpyw\LaravelMySqlSystemVariableManager\ManagesSystemVariables; + if (false) { interface ConnectionInterface { @@ -11,7 +15,7 @@ interface ConnectionInterface * * @param mixed $value * @return $this - * @see \Mpyw\LaravelMySqlSystemVariableManager\ManagesSystemVariables + * @see ManagesSystemVariables */ public function setSystemVariable(string $key, $value, bool $memoizeForReconnect = true); @@ -19,10 +23,8 @@ public function setSystemVariable(string $key, $value, bool $memoizeForReconnect * Set MySQL system variables for both read and write PDOs. * It is lazily executed for unresolved PDO instance. * - * @param array $values - * @param bool $memoizeForReconnect * @return $this - * @see \Mpyw\LaravelMySqlSystemVariableManager\ManagesSystemVariables + * @see ManagesSystemVariables */ public function setSystemVariables(array $values, bool $memoizeForReconnect = true); @@ -33,7 +35,7 @@ public function setSystemVariables(array $values, bool $memoizeForReconnect = tr * @param mixed $value * @param mixed ...$args * @return mixed - * @see \Mpyw\LaravelMySqlSystemVariableManager\ManagesSystemVariables + * @see ManagesSystemVariables */ public function usingSystemVariable(string $key, $value, callable $callback, ...$args); @@ -41,10 +43,9 @@ 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 * @return mixed - * @see \Mpyw\LaravelMySqlSystemVariableManager\ManagesSystemVariables + * @see ManagesSystemVariables */ public function usingSystemVariables(array $values, callable $callback, ...$args); } @@ -57,24 +58,18 @@ class Connection implements ConnectionInterface * * @param mixed $value * @return $this - * @see \Mpyw\LaravelMySqlSystemVariableManager\ManagesSystemVariables + * @see ManagesSystemVariables */ - public function setSystemVariable(string $key, $value, bool $memoizeForReconnect = true) - { - } + public function setSystemVariable(string $key, $value, bool $memoizeForReconnect = true) {} /** * Set MySQL system variables for both read and write PDOs. * It is lazily executed for unresolved PDO instance. * - * @param array $values - * @param bool $memoizeForReconnect * @return $this - * @see \Mpyw\LaravelMySqlSystemVariableManager\ManagesSystemVariables + * @see ManagesSystemVariables */ - public function setSystemVariables(array $values, bool $memoizeForReconnect = true) - { - } + public function setSystemVariables(array $values, bool $memoizeForReconnect = true) {} /** * Run callback temporarily setting MySQL system variable for both read and write PDOs. @@ -83,30 +78,28 @@ public function setSystemVariables(array $values, bool $memoizeForReconnect = tr * @param mixed $value * @param mixed ...$args * @return mixed - * @see \Mpyw\LaravelMySqlSystemVariableManager\ManagesSystemVariables + * @see ManagesSystemVariables */ - public function usingSystemVariable(string $key, $value, callable $callback, ...$args) - { - } + public function usingSystemVariable(string $key, $value, callable $callback, ...$args) {} /** * 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 * @return mixed - * @see \Mpyw\LaravelMySqlSystemVariableManager\ManagesSystemVariables + * @see ManagesSystemVariables */ - public function usingSystemVariables(array $values, callable $callback, ...$args) - { - } + public function usingSystemVariables(array $values, callable $callback, ...$args) {} } } } namespace Illuminate\Support\Facades { + use Illuminate\Database\Connection; + use Mpyw\LaravelMySqlSystemVariableManager\ManagesSystemVariables; + if (false) { class DB extends Facade { @@ -114,26 +107,20 @@ class DB extends Facade * Set MySQL system variable for both read and write PDOs. * It is lazily executed for unresolved PDO instance. * - * @param mixed $value - * @return \Illuminate\Database\Connection - * @see \Mpyw\LaravelMySqlSystemVariableManager\ManagesSystemVariables + * @param mixed $value + * @return Connection + * @see ManagesSystemVariables */ - public static function setSystemVariable(string $key, $value, bool $memoizeForReconnect = true) - { - } + public static function setSystemVariable(string $key, $value, bool $memoizeForReconnect = true) {} /** * Set MySQL system variables for both read and write PDOs. * It is lazily executed for unresolved PDO instance. * - * @param array $values - * @param bool $memoizeForReconnect - * @return \Illuminate\Database\Connection - * @see \Mpyw\LaravelMySqlSystemVariableManager\ManagesSystemVariables + * @return Connection + * @see ManagesSystemVariables */ - public static function setSystemVariables(array $values, bool $memoizeForReconnect = true) - { - } + public static function setSystemVariables(array $values, bool $memoizeForReconnect = true) {} /** * Run callback temporarily setting MySQL system variable for both read and write PDOs. @@ -142,24 +129,19 @@ public static function setSystemVariables(array $values, bool $memoizeForReconne * @param mixed $value * @param mixed ...$args * @return mixed - * @see \Mpyw\LaravelMySqlSystemVariableManager\ManagesSystemVariables + * @see ManagesSystemVariables */ - public static function usingSystemVariable(string $key, $value, callable $callback, ...$args) - { - } + public static function usingSystemVariable(string $key, $value, callable $callback, ...$args) {} /** * 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 * @return mixed - * @see \Mpyw\LaravelMySqlSystemVariableManager\ManagesSystemVariables + * @see ManagesSystemVariables */ - public static function usingSystemVariables(array $values, callable $callback, ...$args) - { - } + public static function usingSystemVariables(array $values, callable $callback, ...$args) {} } } } diff --git a/composer.json b/composer.json index 8cd61d4..e4dc7ac 100644 --- a/composer.json +++ b/composer.json @@ -22,24 +22,27 @@ } }, "require": { - "php": "^8.0", + "php": "^8.2", "ext-pdo": "*", - "illuminate/support": "^9.0 || ^10.0 || ^11.0", - "illuminate/database": "^9.0 || ^10.0 || ^11.0", - "mpyw/unclosure": "^3.0", - "mpyw/laravel-pdo-emulation-control": "^2.0.2" + "illuminate/support": "^11.0 || ^12.0 || ^13.0", + "illuminate/database": "^11.0 || ^12.0 || ^13.0", + "mpyw/unclosure": "^3.1", + "mpyw/laravel-pdo-emulation-control": "^2.1" }, "require-dev": { "orchestra/testbench": "*", - "orchestra/testbench-core": ">=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 @@ <?php +declare(strict_types=1); + namespace Mpyw\LaravelMySqlSystemVariableManager\PHPStan; use PHPStan\Reflection\ParameterReflection; diff --git a/phpstan/CallableFacadeReturnTypeExtension.php b/phpstan/CallableFacadeReturnTypeExtension.php index 5b03312..0bf312a 100644 --- a/phpstan/CallableFacadeReturnTypeExtension.php +++ b/phpstan/CallableFacadeReturnTypeExtension.php @@ -1,5 +1,7 @@ <?php +declare(strict_types=1); + namespace Mpyw\LaravelMySqlSystemVariableManager\PHPStan; use Illuminate\Database\Connection; @@ -11,6 +13,11 @@ use PHPStan\Type\DynamicStaticMethodReturnTypeExtension; use PHPStan\Type\MixedType; use PHPStan\Type\ObjectType; +use PHPStan\Type\Type; + +use function count; +use function in_array; +use function strlen; final class CallableFacadeReturnTypeExtension implements DynamicStaticMethodReturnTypeExtension { @@ -28,18 +35,18 @@ public function isStaticMethodSupported(MethodReflection $methodReflection): boo 'usingSystemVariables', ]; - return \in_array($methodReflection->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 @@ <?php +declare(strict_types=1); + namespace Mpyw\LaravelMySqlSystemVariableManager\PHPStan; use PHPStan\Reflection\ParameterReflection; @@ -10,12 +12,12 @@ final class CallableParameter implements ParameterReflection { /** - * @var CallableArgumentParameter[] + * @var list<CallableArgumentParameter> */ private array $argumentParameters; /** - * @param CallableArgumentParameter[] $argumentParameters + * @param list<CallableArgumentParameter> $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 @@ <?php +declare(strict_types=1); + namespace Mpyw\LaravelMySqlSystemVariableManager\PHPStan; use Illuminate\Database\ConnectionInterface; @@ -12,6 +14,10 @@ use PHPStan\Type\ThisType; use PHPStan\Type\Type; +use function count; +use function in_array; +use function strlen; + final class CallableReturnTypeExtension implements DynamicMethodReturnTypeExtension { public function getClass(): string @@ -28,7 +34,7 @@ public function isMethodSupported(MethodReflection $methodReflection): bool 'usingSystemVariables', ]; - return \in_array($methodReflection->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 @@ <?php +declare(strict_types=1); + namespace Mpyw\LaravelMySqlSystemVariableManager\PHPStan; use Illuminate\Database\ConnectionInterface; @@ -7,6 +9,8 @@ use PHPStan\Reflection\MethodReflection; use PHPStan\Reflection\MethodsClassReflectionExtension; +use function in_array; + final class ConnectionClassExtension implements MethodsClassReflectionExtension { public function hasMethod(ClassReflection $classReflection, string $methodName): bool @@ -18,8 +22,8 @@ public function hasMethod(ClassReflection $classReflection, string $methodName): 'usingSystemVariables', ]; - return \in_array($methodName, $methods, true) - && \is_a($classReflection->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 @@ <?php +declare(strict_types=1); + namespace Mpyw\LaravelMySqlSystemVariableManager\PHPStan; use PHPStan\Reflection\ParameterReflection; diff --git a/phpstan/MemoizeParameter.php b/phpstan/MemoizeParameter.php index 09ca417..dac2cb7 100644 --- a/phpstan/MemoizeParameter.php +++ b/phpstan/MemoizeParameter.php @@ -1,5 +1,7 @@ <?php +declare(strict_types=1); + namespace Mpyw\LaravelMySqlSystemVariableManager\PHPStan; use PHPStan\Reflection\ParameterReflection; @@ -35,7 +37,7 @@ public function isVariadic(): bool return false; } - public function getDefaultValue(): ?Type + public function getDefaultValue(): Type { return new ConstantBooleanType(true); } diff --git a/phpstan/SystemVariablesMethod.php b/phpstan/SystemVariablesMethod.php index 940b693..c139f39 100644 --- a/phpstan/SystemVariablesMethod.php +++ b/phpstan/SystemVariablesMethod.php @@ -1,5 +1,7 @@ <?php +declare(strict_types=1); + namespace Mpyw\LaravelMySqlSystemVariableManager\PHPStan; use Illuminate\Database\QueryException; @@ -14,6 +16,8 @@ use PHPStan\Type\ThisType; use PHPStan\Type\Type; +use function strlen; + final class SystemVariablesMethod implements MethodReflection { private ClassReflection $class; @@ -60,6 +64,9 @@ public function getPrototype(): ClassMemberReflection return $this; } + /** + * @return list<FunctionVariant> + */ public function getVariants(): array { return $this->getName()[0] === 's' @@ -67,12 +74,15 @@ public function getVariants(): array : $this->getUsingVariants(); } + /** + * @return list<FunctionVariant> + */ 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<FunctionVariant> + */ 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 @@ <?php +declare(strict_types=1); + namespace Mpyw\LaravelMySqlSystemVariableManager\PHPStan; use PHPStan\Reflection\ParameterReflection; diff --git a/phpstan/ValuesParameter.php b/phpstan/ValuesParameter.php index f6953cd..3f35e4f 100644 --- a/phpstan/ValuesParameter.php +++ b/phpstan/ValuesParameter.php @@ -1,5 +1,7 @@ <?php +declare(strict_types=1); + namespace Mpyw\LaravelMySqlSystemVariableManager\PHPStan; use PHPStan\Reflection\ParameterReflection; diff --git a/phpunit.xml b/phpunit.xml index e0e3371..90602b3 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,13 +1,23 @@ <?xml version="1.0" encoding="UTF-8"?> -<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" backupGlobals="false" bootstrap="vendor/autoload.php" colors="true" processIsolation="false" stopOnFailure="false" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.0/phpunit.xsd" cacheDirectory=".phpunit.cache" backupStaticProperties="false"> - <coverage> +<phpunit backupGlobals="false" + bootstrap="vendor/autoload.php" + colors="true" + processIsolation="false" + stopOnFailure="false" + cacheDirectory=".phpunit.cache" + backupStaticProperties="false"> + + <source> <include> - <directory suffix=".php">src</directory> + <directory>./src</directory> </include> - </coverage> + </source> + + <coverage/> + <testsuites> <testsuite name="Package Test Suite"> - <directory suffix="Test.php">./tests/</directory> + <directory suffix="Test.php">./tests</directory> </testsuite> </testsuites> </phpunit> 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 @@ <?php +declare(strict_types=1); + namespace Mpyw\LaravelMySqlSystemVariableManager; interface ExpressionInterface diff --git a/src/ExpressionTrait.php b/src/ExpressionTrait.php index 0c57c68..0b69656 100644 --- a/src/ExpressionTrait.php +++ b/src/ExpressionTrait.php @@ -1,5 +1,7 @@ <?php +declare(strict_types=1); + namespace Mpyw\LaravelMySqlSystemVariableManager; use PDO; @@ -22,8 +24,10 @@ public function getParamType(): int switch ($this->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 @@ <?php +declare(strict_types=1); + namespace Mpyw\LaravelMySqlSystemVariableManager; /** @@ -25,12 +27,12 @@ public function setSystemVariable(string $key, $value, bool $memoizeForReconnect * Set MySQL system variables for both read and write PDOs. * It is lazily executed for unresolved PDO instance. * - * @param array $values - * @param bool $memoizeForReconnect + * @param array<string, mixed> $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<string, mixed> $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 @@ <?php +declare(strict_types=1); + namespace Mpyw\LaravelMySqlSystemVariableManager; use Illuminate\Database\MySqlConnection as BaseMySqlConnection; diff --git a/src/MySqlConnectionServiceProvider.php b/src/MySqlConnectionServiceProvider.php index cc3fa53..9b74ede 100644 --- a/src/MySqlConnectionServiceProvider.php +++ b/src/MySqlConnectionServiceProvider.php @@ -1,5 +1,7 @@ <?php +declare(strict_types=1); + namespace Mpyw\LaravelMySqlSystemVariableManager; use Illuminate\Database\Connection; @@ -12,7 +14,7 @@ class MySqlConnectionServiceProvider extends ServiceProvider { public function register(): void { - Connection::resolverFor('mysql', function (...$parameters) { + Connection::resolverFor('mysql', static function (...$parameters) { return new MySqlConnection(...$parameters); }); } diff --git a/src/Replacer.php b/src/Replacer.php index d928fe2..9496210 100644 --- a/src/Replacer.php +++ b/src/Replacer.php @@ -1,5 +1,7 @@ <?php +declare(strict_types=1); + namespace Mpyw\LaravelMySqlSystemVariableManager; use InvalidArgumentException; @@ -62,12 +64,16 @@ public static function as(string $type, callable $callback): ExpressionInterface switch ($type) { case ExpressionInterface::TYPE_INTEGER: return static::int($callback); + case ExpressionInterface::TYPE_BOOLEAN: return static::bool($callback); + case ExpressionInterface::TYPE_FLOAT: return static::float($callback); + case ExpressionInterface::TYPE_STRING: return static::str($callback); + default: throw new InvalidArgumentException('The return type must be one of "integer", "boolean", "double" or "string".'); } diff --git a/src/Replacers/BooleanReplacerInterface.php b/src/Replacers/BooleanReplacerInterface.php index 2e6f76f..eb4df6b 100644 --- a/src/Replacers/BooleanReplacerInterface.php +++ b/src/Replacers/BooleanReplacerInterface.php @@ -1,5 +1,7 @@ <?php +declare(strict_types=1); + namespace Mpyw\LaravelMySqlSystemVariableManager\Replacers; use Mpyw\LaravelMySqlSystemVariableManager\ExpressionInterface; diff --git a/src/Replacers/CallbackBooleanReplacer.php b/src/Replacers/CallbackBooleanReplacer.php index 5613894..6752aa9 100644 --- a/src/Replacers/CallbackBooleanReplacer.php +++ b/src/Replacers/CallbackBooleanReplacer.php @@ -1,5 +1,7 @@ <?php +declare(strict_types=1); + namespace Mpyw\LaravelMySqlSystemVariableManager\Replacers; use Mpyw\LaravelMySqlSystemVariableManager\ExpressionInterface; diff --git a/src/Replacers/CallbackFloatReplacer.php b/src/Replacers/CallbackFloatReplacer.php index cd7d876..802d537 100644 --- a/src/Replacers/CallbackFloatReplacer.php +++ b/src/Replacers/CallbackFloatReplacer.php @@ -1,5 +1,7 @@ <?php +declare(strict_types=1); + namespace Mpyw\LaravelMySqlSystemVariableManager\Replacers; use Mpyw\LaravelMySqlSystemVariableManager\ExpressionInterface; diff --git a/src/Replacers/CallbackIntegerReplacer.php b/src/Replacers/CallbackIntegerReplacer.php index de9fbc4..1c186f2 100644 --- a/src/Replacers/CallbackIntegerReplacer.php +++ b/src/Replacers/CallbackIntegerReplacer.php @@ -1,5 +1,7 @@ <?php +declare(strict_types=1); + namespace Mpyw\LaravelMySqlSystemVariableManager\Replacers; use Mpyw\LaravelMySqlSystemVariableManager\ExpressionInterface; diff --git a/src/Replacers/CallbackStringReplacer.php b/src/Replacers/CallbackStringReplacer.php index b692ff2..fba3583 100644 --- a/src/Replacers/CallbackStringReplacer.php +++ b/src/Replacers/CallbackStringReplacer.php @@ -1,5 +1,7 @@ <?php +declare(strict_types=1); + namespace Mpyw\LaravelMySqlSystemVariableManager\Replacers; use Mpyw\LaravelMySqlSystemVariableManager\ExpressionInterface; diff --git a/src/Replacers/FloatReplacerInterface.php b/src/Replacers/FloatReplacerInterface.php index ab97353..ad39077 100644 --- a/src/Replacers/FloatReplacerInterface.php +++ b/src/Replacers/FloatReplacerInterface.php @@ -1,5 +1,7 @@ <?php +declare(strict_types=1); + namespace Mpyw\LaravelMySqlSystemVariableManager\Replacers; use Mpyw\LaravelMySqlSystemVariableManager\ExpressionInterface; diff --git a/src/Replacers/IntegerReplacerInterface.php b/src/Replacers/IntegerReplacerInterface.php index 83b2868..2e577af 100644 --- a/src/Replacers/IntegerReplacerInterface.php +++ b/src/Replacers/IntegerReplacerInterface.php @@ -1,5 +1,7 @@ <?php +declare(strict_types=1); + namespace Mpyw\LaravelMySqlSystemVariableManager\Replacers; use Mpyw\LaravelMySqlSystemVariableManager\ExpressionInterface; diff --git a/src/Replacers/StringReplacerInterface.php b/src/Replacers/StringReplacerInterface.php index c9bcc51..ceede5b 100644 --- a/src/Replacers/StringReplacerInterface.php +++ b/src/Replacers/StringReplacerInterface.php @@ -1,5 +1,7 @@ <?php +declare(strict_types=1); + namespace Mpyw\LaravelMySqlSystemVariableManager\Replacers; use Mpyw\LaravelMySqlSystemVariableManager\ExpressionInterface; diff --git a/src/SystemVariableAssigner.php b/src/SystemVariableAssigner.php index 9786087..64f4dca 100644 --- a/src/SystemVariableAssigner.php +++ b/src/SystemVariableAssigner.php @@ -1,5 +1,7 @@ <?php +declare(strict_types=1); + namespace Mpyw\LaravelMySqlSystemVariableManager; use Closure; @@ -14,27 +16,31 @@ use Mpyw\LaravelMySqlSystemVariableManager\SystemVariableGrammar as Grammar; use PDOStatement; +use function array_filter; +use function array_map; + class SystemVariableAssigner { /** - * @var \Closure[]|\PDO[] + * @var Closure[]|PDO[] */ protected array $pdos; /** * SystemVariableAssigner constructor. - * - * @param null|\Closure|\PDO &...$pdos */ - public function __construct(&...$pdos) + /** + * @phpstan-ignore-next-line parameterByRef.unusedType + */ + public function __construct(null|Closure|PDO &...$pdos) { - $this->pdos = \array_filter($pdos); + $this->pdos = array_filter($pdos); } /** * Set MySQL system variables for PDO. * - * @param array $values + * @param array<string, mixed> $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<string, mixed> $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<string, mixed> $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<string, mixed> $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 @@ <?php +declare(strict_types=1); + namespace Mpyw\LaravelMySqlSystemVariableManager; use Illuminate\Database\ConnectionInterface; use LogicException; +use function array_replace; +use function is_callable; +use function method_exists; + /** * Class SystemVariableAwareReconnector */ class SystemVariableAwareReconnector { /** - * @var array + * @var array<string, mixed> */ protected array $memoizedSystemVariables = []; @@ -29,12 +35,13 @@ public function __construct(?callable $reconnector = null) } /** - * @param array $values + * @param array<string, mixed> $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 @@ <?php +declare(strict_types=1); + namespace Mpyw\LaravelMySqlSystemVariableManager; +use function implode; +use function sprintf; +use function str_replace; + class SystemVariableGrammar { /** @@ -9,32 +15,33 @@ class SystemVariableGrammar */ public static function selectStatement(array $variables): string { - return 'select ' . \implode(', ', static::variableExpressions($variables)); + return 'select ' . implode(', ', static::variableExpressions($variables)); } /** - * @param string[] $variables + * @param string[] $variables * @return string[] */ public static function variableExpressions(array $variables): array { $expressions = []; foreach ($variables as $variable) { - $expressions[] = \sprintf('@@%1$s as %1$s', static::escapeIdentifier($variable)); + $expressions[] = sprintf('@@%1$s as %1$s', static::escapeIdentifier($variable)); } + return $expressions; } /** - * @param array $values + * @param array<array-key, mixed> $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<array-key, mixed> $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 @@ <?php +declare(strict_types=1); + namespace Mpyw\LaravelMySqlSystemVariableManager; +use Closure; +use PDO; + +use function array_filter; + class SystemVariableMemoizedAssigner { protected SystemVariableAwareReconnector $reconnector; /** - * @var \Closure[]|\PDO[] + * @var Closure[]|PDO[] */ protected array $pdos; /** * SystemVariableMemoizedAssigner constructor. * - * @param null|callable|\Mpyw\LaravelMySqlSystemVariableManager\SystemVariableAwareReconnector &$reconnector - * @param null|\Closure|\PDO &...$pdos + * @param null|callable|SystemVariableAwareReconnector &$reconnector + * @param null|Closure|PDO &...$pdos + */ + /** + * @phpstan-ignore-next-line parameterByRef.unusedType */ public function __construct(&$reconnector, &...$pdos) { @@ -23,17 +33,18 @@ public function __construct(&$reconnector, &...$pdos) ? new SystemVariableAwareReconnector($reconnector) : $reconnector; - $this->pdos = \array_filter($pdos); + $this->pdos = array_filter($pdos); } /** * Set MySQL system variables for PDO. * - * @param array $values + * @param array<string, mixed> $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 @@ <?php +declare(strict_types=1); + namespace Mpyw\LaravelMySqlSystemVariableManager; use PDO; +use function array_keys; +use function assert; +use function is_array; + class SystemVariableSelector { /** * Select current MySQL system variable values. * - * @param array $newValues - * @return \Mpyw\LaravelMySqlSystemVariableManager\ValueInterface[] + * @param array<string, mixed> $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 @@ <?php +declare(strict_types=1); + namespace Mpyw\LaravelMySqlSystemVariableManager; use Mpyw\Unclosure\Value as ValueEffector; use PDO; +use Closure; + +use function array_filter; class SystemVariableTemporaryAssigner { /** - * @var \Closure[]|\PDO[] + * @var Closure[]|PDO[] */ protected array $pdos; /** * SystemVariableAssigner constructor. * - * @param null|\Closure|\PDO &...$pdos + * @param null|Closure|PDO &...$pdos + */ + /** + * @phpstan-ignore-next-line parameterByRef.unusedType */ public function __construct(&...$pdos) { - $this->pdos = \array_filter($pdos); + $this->pdos = array_filter($pdos); } /** * Temporarily set MySQL system variables for PDO. * - * @param array $using - * @param mixed ...$args + * @param array<string, mixed> $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 @@ <?php +declare(strict_types=1); + namespace Mpyw\LaravelMySqlSystemVariableManager; use Closure; @@ -7,6 +9,8 @@ use ReflectionFunction; use ReflectionNamedType; +use function is_scalar; + class Value implements ValueInterface { use ExpressionTrait; @@ -68,12 +72,16 @@ public static function as(string $type, $value): ExpressionInterface switch ($type) { case static::TYPE_INTEGER: return static::int((int)$value); + case static::TYPE_BOOLEAN: return static::bool((bool)$value); + case static::TYPE_FLOAT: return static::float((float)$value); + case static::TYPE_STRING: return static::str((string)$value); + default: throw new InvalidArgumentException('The type must be one of "integer", "boolean", "double" or "string".'); } @@ -92,12 +100,12 @@ public static function wrap($value): ExpressionInterface return $value; } - if (\is_scalar($value)) { + if (is_scalar($value)) { return static::as(gettype($value), $value); } if ($value instanceof Closure) { - /* @noinspection PhpUnhandledExceptionInspection */ + /** @noinspection PhpUnhandledExceptionInspection */ $reflector = new ReflectionFunction($value); $returnType = $reflector->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 @@ <?php +declare(strict_types=1); + namespace Mpyw\LaravelMySqlSystemVariableManager; interface ValueInterface extends ExpressionInterface diff --git a/tests/BasicVariableAssignmentTest.php b/tests/BasicVariableAssignmentTest.php index 7fc42b5..d2c174d 100644 --- a/tests/BasicVariableAssignmentTest.php +++ b/tests/BasicVariableAssignmentTest.php @@ -1,5 +1,7 @@ <?php +declare(strict_types=1); + namespace Mpyw\LaravelMySqlSystemVariableManager\Tests; use InvalidArgumentException; @@ -11,14 +13,14 @@ class BasicVariableAssignmentTest extends TestCase { /** * @test - * @param mixed $expectedOriginal - * @param mixed $newValue - * @param mixed $expectedChanged + * @param mixed $expectedOriginal + * @param mixed $newValue + * @param mixed $expectedChanged * @dataProvider provideBasicVariables */ public function testAssignments(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->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 @@ <?php +declare(strict_types=1); + namespace Mpyw\LaravelMySqlSystemVariableManager\Tests; use Illuminate\Support\Facades\DB; @@ -9,7 +11,7 @@ class ReconnectionTest extends TestCase { public function testOnlyMemoizedVariablesAreReassigned(): void { - $this->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 @@ <?php +declare(strict_types=1); + namespace Mpyw\LaravelMySqlSystemVariableManager\Tests; use Closure; @@ -8,11 +10,12 @@ use Orchestra\Testbench\TestCase as BaseTestCase; use PDO; use ReflectionProperty; +use Illuminate\Foundation\Application; class TestCase extends BaseTestCase { /** - * @param \Illuminate\Foundation\Application $app + * @param Application $app */ protected function getEnvironmentSetUp($app): void { @@ -41,7 +44,7 @@ protected function getEnvironmentSetUp($app): void } /** - * @param \Illuminate\Foundation\Application $app + * @param Application $app * @return string[] */ protected function getPackageProviders($app): array @@ -62,8 +65,7 @@ protected function onEmulatedConnection(callable $callback): void } /** - * @param string $property - * @return \Closure|\PDO + * @return Closure|PDO */ protected function getConnectionPropertyValue(?string $connection, string $property) { @@ -86,17 +88,4 @@ protected function assertPdoNotResolved(?string $connection): void { $this->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; - } }