From 7550b547d6df76495babdd8dbfc80bcb24fd8583 Mon Sep 17 00:00:00 2001 From: Sergei Tigrov Date: Fri, 23 Aug 2024 14:22:42 +0700 Subject: [PATCH] Raise PHP version to 8.1 (#347) --- .github/workflows/build-mariadb.yml | 2 - .github/workflows/build.yml | 2 - .../workflows/composer-require-checker.yml | 1 - .github/workflows/static.yml | 6 - CHANGELOG.md | 1 + README.md | 6 +- composer.json | 6 +- psalm4.xml | 17 --- rector.php | 8 +- src/DQLQueryBuilder.php | 15 +- src/Schema.php | 21 +-- tests/DeadLockTest.php | 2 +- .../Provider/ColumnSchemaBuilderProvider.php | 28 ++-- tests/Provider/QueryBuilderProvider.php | 138 +++++++++--------- tests/SchemaTest.php | 5 +- 15 files changed, 108 insertions(+), 150 deletions(-) delete mode 100644 psalm4.xml diff --git a/.github/workflows/build-mariadb.yml b/.github/workflows/build-mariadb.yml index 4228ded6..ba9f4ad9 100644 --- a/.github/workflows/build-mariadb.yml +++ b/.github/workflows/build-mariadb.yml @@ -43,8 +43,6 @@ jobs: - mariadb:latest include: - - php: 8.0 - mariadb: mariadb:latest - php: 8.1 mariadb: mariadb:latest - php: 8.2 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 14878918..d120c845 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -38,8 +38,6 @@ jobs: - mysql:latest include: - - php: 8.0 - mysql: mysql:latest - php: 8.1 mysql: mysql:latest - php: 8.2 diff --git a/.github/workflows/composer-require-checker.yml b/.github/workflows/composer-require-checker.yml index 58107cb7..c2ca43f8 100644 --- a/.github/workflows/composer-require-checker.yml +++ b/.github/workflows/composer-require-checker.yml @@ -29,7 +29,6 @@ jobs: - ubuntu-latest php: - - 8.0 - 8.1 - 8.2 - 8.3 diff --git a/.github/workflows/static.yml b/.github/workflows/static.yml index 1660a1ad..95e5fd75 100644 --- a/.github/workflows/static.yml +++ b/.github/workflows/static.yml @@ -31,7 +31,6 @@ jobs: - ubuntu-latest php: - - '8.0' - '8.1' - '8.2' - '8.3' @@ -66,9 +65,4 @@ jobs: run: composer update --no-interaction --no-progress --optimize-autoloader --ansi - name: Static analysis. - if: ${{ matrix.php != '8.0' }} run: vendor/bin/psalm --config=${{ inputs.psalm-config }} --shepherd --stats --output-format=github --php-version=${{ matrix.php }} - - - name: Static analysis. - if: ${{ matrix.php == '8.0' }} - run: vendor/bin/psalm --config=psalm4.xml --shepherd --stats --output-format=github --php-version=${{ matrix.php }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 6dca5aa4..4ae81fad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - Chg #339: Replace call of `SchemaInterface::getRawTableName()` to `QuoterInterface::getRawTableName()` (@Tigrov) - Enh #342: Add JSON overlaps condition builder (@Tigrov) - Enh #344: Update `bit` type according to main PR yiisoft/db#860 (@Tigrov) +- Enh #347: Raise minimum PHP version to `^8.1` with minor refactoring (@Tigrov) - Bug #349: Restore connection if closed by connection timeout (@Tigrov) ## 1.2.0 March 21, 2024 diff --git a/README.md b/README.md index d80283a5..07411021 100644 --- a/README.md +++ b/README.md @@ -31,9 +31,9 @@ It is used in [Yii Framework](https://www.yiiframework.com/) but can be used sep ## Support version -| PHP | MySQL/MariaDB Version | CI-Actions | -|-----------|-----------------------|------------| -| **8.0-8.2** |**5.7-8.0**/**10.4-10.10**|[![build](https://github.com/yiisoft/db-mysql/actions/workflows/build.yml/badge.svg?branch=dev)](https://github.com/yiisoft/db-mysql/actions/workflows/build.yml) [![ansi-mode](https://github.com/yiisoft/db-mysql/actions/workflows/ansi-mode.yml/badge.svg)](https://github.com/yiisoft/db-mysql/actions/workflows/ansi-mode.yml) [![Mutation testing badge](https://img.shields.io/endpoint?style=flat&url=https%3A%2F%2Fbadge-api.stryker-mutator.io%2Fgithub.com%2Fyiisoft%2Fdb-mysql%2Fmaster)](https://dashboard.stryker-mutator.io/reports/github.com/yiisoft/db-mysql/master) [![static analysis](https://github.com/yiisoft/db-mysql/actions/workflows/static.yml/badge.svg?branch=dev)](https://github.com/yiisoft/db-mysql/actions/workflows/static.yml) +| PHP | MySQL/MariaDB Version | CI-Actions | +|-------------|-----------------------|------------| +| **8.1-8.3** |**5.7-8.0**/**10.4-10.10**|[![build](https://github.com/yiisoft/db-mysql/actions/workflows/build.yml/badge.svg?branch=dev)](https://github.com/yiisoft/db-mysql/actions/workflows/build.yml) [![ansi-mode](https://github.com/yiisoft/db-mysql/actions/workflows/ansi-mode.yml/badge.svg)](https://github.com/yiisoft/db-mysql/actions/workflows/ansi-mode.yml) [![Mutation testing badge](https://img.shields.io/endpoint?style=flat&url=https%3A%2F%2Fbadge-api.stryker-mutator.io%2Fgithub.com%2Fyiisoft%2Fdb-mysql%2Fmaster)](https://dashboard.stryker-mutator.io/reports/github.com/yiisoft/db-mysql/master) [![static analysis](https://github.com/yiisoft/db-mysql/actions/workflows/static.yml/badge.svg?branch=dev)](https://github.com/yiisoft/db-mysql/actions/workflows/static.yml) ## Installation diff --git a/composer.json b/composer.json index cd0a9980..fde367f8 100644 --- a/composer.json +++ b/composer.json @@ -31,7 +31,7 @@ } ], "require": { - "php": "^8.0", + "php": "^8.1", "ext-ctype": "*", "ext-json": "*", "ext-pdo": "*", @@ -41,11 +41,11 @@ }, "require-dev": { "maglnet/composer-require-checker": "^4.2", - "phpunit/phpunit": "^9.5|^10.0", + "phpunit/phpunit": "^10.0", "rector/rector": "^1.0", "roave/infection-static-analysis-plugin": "^1.16", "spatie/phpunit-watcher": "^1.23", - "vimeo/psalm": "^4.30|^5.20", + "vimeo/psalm": "^5.25", "yiisoft/aliases": "^2.0", "yiisoft/log-target-file": "^2.0", "yiisoft/cache-file": "^3.1", diff --git a/psalm4.xml b/psalm4.xml deleted file mode 100644 index 23bfcce1..00000000 --- a/psalm4.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - diff --git a/rector.php b/rector.php index 6d9558aa..86ff3b6e 100644 --- a/rector.php +++ b/rector.php @@ -4,7 +4,8 @@ use Rector\CodeQuality\Rector\Class_\InlineConstructorDefaultToPropertyRector; use Rector\Config\RectorConfig; -use Rector\Php74\Rector\Closure\ClosureToArrowFunctionRector; +use Rector\Php81\Rector\FuncCall\NullToStrictStringFuncCallArgRector; +use Rector\Php81\Rector\Property\ReadOnlyPropertyRector; use Rector\Set\ValueObject\LevelSetList; return static function (RectorConfig $rectorConfig): void { @@ -23,10 +24,11 @@ // define sets of rules $rectorConfig->sets([ - LevelSetList::UP_TO_PHP_80, + LevelSetList::UP_TO_PHP_81, ]); $rectorConfig->skip([ - ClosureToArrowFunctionRector::class, + NullToStrictStringFuncCallArgRector::class, + ReadOnlyPropertyRector::class, ]); }; diff --git a/src/DQLQueryBuilder.php b/src/DQLQueryBuilder.php index d4604ae6..269ac87c 100644 --- a/src/DQLQueryBuilder.php +++ b/src/DQLQueryBuilder.php @@ -13,7 +13,6 @@ use Yiisoft\Db\QueryBuilder\AbstractDQLQueryBuilder; use Yiisoft\Db\QueryBuilder\Condition\JsonOverlapsCondition; -use function array_merge; use function ctype_digit; /** @@ -82,13 +81,11 @@ protected function hasOffset(mixed $offset): bool */ protected function defaultExpressionBuilders(): array { - return array_merge( - parent::defaultExpressionBuilders(), - [ - JsonExpression::class => JsonExpressionBuilder::class, - JsonOverlapsCondition::class => JsonOverlapsConditionBuilder::class, - Expression::class => ExpressionBuilder::class, - ] - ); + return [ + ...parent::defaultExpressionBuilders(), + JsonExpression::class => JsonExpressionBuilder::class, + JsonOverlapsCondition::class => JsonOverlapsConditionBuilder::class, + Expression::class => ExpressionBuilder::class, + ]; } } diff --git a/src/Schema.php b/src/Schema.php index a1673a0e..5f0fce64 100644 --- a/src/Schema.php +++ b/src/Schema.php @@ -20,7 +20,6 @@ use function array_change_key_case; use function array_map; -use function array_merge; use function array_values; use function bindec; use function explode; @@ -148,7 +147,7 @@ public function findUniqueIndexes(TableSchemaInterface $table): array if (preg_match_all($regexp, $sql, $matches, PREG_SET_ORDER) > 0) { foreach ($matches as $match) { $indexName = $match[1]; - $indexColumns = array_map('trim', preg_split('/[`"],[`"]/', trim($match[2], '`"'))); + $indexColumns = array_map(trim(...), preg_split('/[`"],[`"]/', trim($match[2], '`"'))); $uniqueIndexes[$indexName] = $indexColumns; } } @@ -287,13 +286,7 @@ protected function findConstraints(TableSchemaInterface $table): void * @psalm-var array{referenced_table_name: string, columns: array} $constraint */ foreach ($constraints as $name => $constraint) { - $table->foreignKey( - $name, - array_merge( - [$constraint['referenced_table_name']], - $constraint['columns'] - ), - ); + $table->foreignKey($name, [$constraint['referenced_table_name'], ...$constraint['columns']]); } } @@ -392,12 +385,10 @@ protected function findViewNames(string $schema = ''): array * @param string $name The table name. * * @return array The cache key. - * - * @psalm-suppress DeprecatedMethod */ protected function getCacheKey(string $name): array { - return array_merge([self::class], $this->generateCacheKey(), [$this->db->getQuoter()->getRawTableName($name)]); + return [self::class, ...$this->generateCacheKey(), $this->db->getQuoter()->getRawTableName($name)]; } /** @@ -409,7 +400,7 @@ protected function getCacheKey(string $name): array */ protected function getCacheTag(): string { - return md5(serialize(array_merge([self::class], $this->generateCacheKey()))); + return md5(serialize([self::class, ...$this->generateCacheKey()])); } /** @@ -657,7 +648,7 @@ private function loadTableConstraints(string $tableName, string $returnType): ar ])->queryAll(); /** @psalm-var array[][] $constraints */ - $constraints = array_map('array_change_key_case', $constraints); + $constraints = array_map(array_change_key_case(...), $constraints); $constraints = DbArrayHelper::index($constraints, null, ['type', 'name']); $result = [ @@ -772,7 +763,7 @@ protected function loadTableIndexes(string $tableName): array ])->queryAll(); /** @psalm-var array[] $indexes */ - $indexes = array_map('array_change_key_case', $indexes); + $indexes = array_map(array_change_key_case(...), $indexes); $indexes = DbArrayHelper::index($indexes, null, ['name']); $result = []; diff --git a/tests/DeadLockTest.php b/tests/DeadLockTest.php index 5da9ec65..5392f71c 100644 --- a/tests/DeadLockTest.php +++ b/tests/DeadLockTest.php @@ -347,7 +347,7 @@ private function childrenUpdateLocked(): int */ private function setErrorHandler(): void { - set_error_handler(static function ($errno, $errstr, $errfile, $errline) { + set_error_handler(static function ($errno, $errstr, $errfile, $errline): never { throw new ErrorException($errstr, $errno, $errno, $errfile, $errline); }); } diff --git a/tests/Provider/ColumnSchemaBuilderProvider.php b/tests/Provider/ColumnSchemaBuilderProvider.php index a3446487..84330943 100644 --- a/tests/Provider/ColumnSchemaBuilderProvider.php +++ b/tests/Provider/ColumnSchemaBuilderProvider.php @@ -18,25 +18,23 @@ public static function types(): array $types[1][0] = 'integer(10) UNSIGNED'; $types[2][0] = 'integer(10) COMMENT \'test\''; - return array_merge( - $types, - [ - ['integer UNSIGNED', SchemaInterface::TYPE_INTEGER, null, [['unsigned']]], + return [ + ...$types, + ['integer UNSIGNED', SchemaInterface::TYPE_INTEGER, null, [['unsigned']]], - /** - * {@link https://github.com/yiisoft/yii2/issues/11945}, real test against database. - */ + /** + * {@link https://github.com/yiisoft/yii2/issues/11945}, real test against database. + */ + [ + 'string(50) NOT NULL COMMENT \'Property name\' COLLATE ascii_general_ci', + SchemaInterface::TYPE_STRING, 50, [ - 'string(50) NOT NULL COMMENT \'Property name\' COLLATE ascii_general_ci', - SchemaInterface::TYPE_STRING, 50, - [ - ['comment', 'Property name'], - ['append', 'COLLATE ascii_general_ci'], - ['notNull'], - ], + ['comment', 'Property name'], + ['append', 'COLLATE ascii_general_ci'], + ['notNull'], ], ], - ); + ]; } public static function createColumnTypes(): array diff --git a/tests/Provider/QueryBuilderProvider.php b/tests/Provider/QueryBuilderProvider.php index 14bdb263..0e5d6ee6 100644 --- a/tests/Provider/QueryBuilderProvider.php +++ b/tests/Provider/QueryBuilderProvider.php @@ -19,85 +19,81 @@ final class QueryBuilderProvider extends \Yiisoft\Db\Tests\Provider\QueryBuilder public static function buildCondition(): array { - $buildCondition = parent::buildCondition(); - - return array_merge( - $buildCondition, + return [ + ...parent::buildCondition(), + [ + ['=', 'jsoncol', new JsonExpression(['lang' => 'uk', 'country' => 'UA'])], + '[[jsoncol]] = :qp0', [':qp0' => '{"lang":"uk","country":"UA"}'], + ], [ + ['=', 'jsoncol', new JsonExpression([false])], + '[[jsoncol]] = :qp0', [':qp0' => '[false]'], + ], + 'object with type. Type is ignored for MySQL' => [ + ['=', 'prices', new JsonExpression(['seeds' => 15, 'apples' => 25], 'jsonb')], + '[[prices]] = :qp0', [':qp0' => '{"seeds":15,"apples":25}'], + ], + 'nested json' => [ [ - ['=', 'jsoncol', new JsonExpression(['lang' => 'uk', 'country' => 'UA'])], - '[[jsoncol]] = :qp0', [':qp0' => '{"lang":"uk","country":"UA"}'], + '=', + 'data', + new JsonExpression( + [ + 'user' => ['login' => 'silverfire', 'password' => 'c4ny0ur34d17?'], + 'props' => ['mood' => 'good'], + ] + ), ], + '[[data]] = :qp0', + [':qp0' => '{"user":{"login":"silverfire","password":"c4ny0ur34d17?"},"props":{"mood":"good"}}'], + ], + 'null value' => [ + ['=', 'jsoncol', new JsonExpression(null)], + '[[jsoncol]] = :qp0', [':qp0' => 'null'], + ], + 'null as array value' => [ + ['=', 'jsoncol', new JsonExpression([null])], + '[[jsoncol]] = :qp0', [':qp0' => '[null]'], + ], + 'null as object value' => [ + ['=', 'jsoncol', new JsonExpression(['nil' => null])], + '[[jsoncol]] = :qp0', [':qp0' => '{"nil":null}'], + ], + 'query' => [ [ - ['=', 'jsoncol', new JsonExpression([false])], - '[[jsoncol]] = :qp0', [':qp0' => '[false]'], - ], - 'object with type. Type is ignored for MySQL' => [ - ['=', 'prices', new JsonExpression(['seeds' => 15, 'apples' => 25], 'jsonb')], - '[[prices]] = :qp0', [':qp0' => '{"seeds":15,"apples":25}'], - ], - 'nested json' => [ - [ - '=', - 'data', - new JsonExpression( - [ - 'user' => ['login' => 'silverfire', 'password' => 'c4ny0ur34d17?'], - 'props' => ['mood' => 'good'], - ] - ), - ], - '[[data]] = :qp0', - [':qp0' => '{"user":{"login":"silverfire","password":"c4ny0ur34d17?"},"props":{"mood":"good"}}'], + '=', + 'jsoncol', + new JsonExpression((new Query(self::getDb()))->select('params')->from('user')->where(['id' => 1])), ], - 'null value' => [ - ['=', 'jsoncol', new JsonExpression(null)], - '[[jsoncol]] = :qp0', [':qp0' => 'null'], - ], - 'null as array value' => [ - ['=', 'jsoncol', new JsonExpression([null])], - '[[jsoncol]] = :qp0', [':qp0' => '[null]'], - ], - 'null as object value' => [ - ['=', 'jsoncol', new JsonExpression(['nil' => null])], - '[[jsoncol]] = :qp0', [':qp0' => '{"nil":null}'], - ], - 'query' => [ - [ - '=', - 'jsoncol', - new JsonExpression((new Query(self::getDb()))->select('params')->from('user')->where(['id' => 1])), - ], - '[[jsoncol]] = (SELECT [[params]] FROM [[user]] WHERE [[id]]=:qp0)', - [':qp0' => 1], - ], - 'query with type, that is ignored in MySQL' => [ - [ - '=', - 'jsoncol', - new JsonExpression( - (new Query(self::getDb()))->select('params')->from('user')->where(['id' => 1]), - 'jsonb' - ), - ], - '[[jsoncol]] = (SELECT [[params]] FROM [[user]] WHERE [[id]]=:qp0)', [':qp0' => 1], - ], - 'nested and combined json expression' => [ - [ - '=', - 'jsoncol', - new JsonExpression( - new JsonExpression(['a' => 1, 'b' => 2, 'd' => new JsonExpression(['e' => 3])]) - ), - ], - '[[jsoncol]] = :qp0', [':qp0' => '{"a":1,"b":2,"d":{"e":3}}'], + '[[jsoncol]] = (SELECT [[params]] FROM [[user]] WHERE [[id]]=:qp0)', + [':qp0' => 1], + ], + 'query with type, that is ignored in MySQL' => [ + [ + '=', + 'jsoncol', + new JsonExpression( + (new Query(self::getDb()))->select('params')->from('user')->where(['id' => 1]), + 'jsonb' + ), ], - 'search by property in JSON column (issue #15838)' => [ - ['=', new Expression("(jsoncol->>'$.someKey')"), '42'], - "(jsoncol->>'$.someKey') = :qp0", [':qp0' => 42], + '[[jsoncol]] = (SELECT [[params]] FROM [[user]] WHERE [[id]]=:qp0)', [':qp0' => 1], + ], + 'nested and combined json expression' => [ + [ + '=', + 'jsoncol', + new JsonExpression( + new JsonExpression(['a' => 1, 'b' => 2, 'd' => new JsonExpression(['e' => 3])]) + ), ], + '[[jsoncol]] = :qp0', [':qp0' => '{"a":1,"b":2,"d":{"e":3}}'], ], - ); + 'search by property in JSON column (issue #15838)' => [ + ['=', new Expression("(jsoncol->>'$.someKey')"), '42'], + "(jsoncol->>'$.someKey') = :qp0", [':qp0' => 42], + ], + ]; } public static function insert(): array diff --git a/tests/SchemaTest.php b/tests/SchemaTest.php index 6e5b0a5c..088cba82 100644 --- a/tests/SchemaTest.php +++ b/tests/SchemaTest.php @@ -483,7 +483,8 @@ public function testWorkWithPrimaryKeyConstraint(): void public function withIndexDataProvider(): array { - return array_merge(parent::withIndexDataProvider(), [ + return [ + ...parent::withIndexDataProvider(), [ 'indexType' => null, 'indexMethod' => SchemaInterface::INDEX_HASH, @@ -504,7 +505,7 @@ public function withIndexDataProvider(): array 'indexMethod' => null, 'columnType' => 'GEOMETRY NOT NULL', ], - ]); + ]; } public function testTinyInt1()