From 413e2a79fb1aef888d264ed0d3f389eaf2996c76 Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Sun, 8 May 2022 11:34:21 -0700 Subject: [PATCH 1/5] Separate PHPStan configuration for DBAL 4 See https://github.com/doctrine/dbal/pull/3480 --- phpstan-dbal4.neon | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 phpstan-dbal4.neon diff --git a/phpstan-dbal4.neon b/phpstan-dbal4.neon new file mode 100644 index 00000000000..e7e618c9019 --- /dev/null +++ b/phpstan-dbal4.neon @@ -0,0 +1,16 @@ +includes: + - phpstan.neon + +parameters: + ignoreErrors: + # Compatibility with DBAL 3 + # See https://github.com/doctrine/dbal/pull/3480 + - + message: '~^Result of method Doctrine\\DBAL\\Connection::commit\(\) \(void\) is used\.$~' + path: lib/Doctrine/ORM/UnitOfWork.php + - + message: '~^Strict comparison using === between void and false will always evaluate to false\.$~' + path: lib/Doctrine/ORM/UnitOfWork.php + - + message: '~^Variable \$e on left side of \?\? always exists and is not nullable\.$~' + path: lib/Doctrine/ORM/UnitOfWork.php From 10442a7b4ee021d9f71e0a5f634279d02b3f021d Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Sun, 8 May 2022 10:40:26 -0700 Subject: [PATCH 2/5] Assert that date interval expressions are numeric strings See https://github.com/doctrine/dbal/pull/3498 --- .../Query/AST/Functions/DateAddFunction.php | 30 ++++++-- .../Query/AST/Functions/DateSubFunction.php | 30 ++++++-- phpstan-baseline.neon | 70 ------------------- 3 files changed, 46 insertions(+), 84 deletions(-) diff --git a/lib/Doctrine/ORM/Query/AST/Functions/DateAddFunction.php b/lib/Doctrine/ORM/Query/AST/Functions/DateAddFunction.php index 7fa28fdc850..efc0f4b5ec3 100644 --- a/lib/Doctrine/ORM/Query/AST/Functions/DateAddFunction.php +++ b/lib/Doctrine/ORM/Query/AST/Functions/DateAddFunction.php @@ -4,12 +4,15 @@ namespace Doctrine\ORM\Query\AST\Functions; +use Doctrine\ORM\Query\AST\ASTException; use Doctrine\ORM\Query\AST\Node; use Doctrine\ORM\Query\Lexer; use Doctrine\ORM\Query\Parser; use Doctrine\ORM\Query\QueryException; use Doctrine\ORM\Query\SqlWalker; +use function assert; +use function is_numeric; use function strtolower; /** @@ -38,43 +41,43 @@ public function getSql(SqlWalker $sqlWalker) case 'second': return $sqlWalker->getConnection()->getDatabasePlatform()->getDateAddSecondsExpression( $this->firstDateExpression->dispatch($sqlWalker), - $this->intervalExpression->dispatch($sqlWalker) + $this->dispatchIntervalExpression($sqlWalker) ); case 'minute': return $sqlWalker->getConnection()->getDatabasePlatform()->getDateAddMinutesExpression( $this->firstDateExpression->dispatch($sqlWalker), - $this->intervalExpression->dispatch($sqlWalker) + $this->dispatchIntervalExpression($sqlWalker) ); case 'hour': return $sqlWalker->getConnection()->getDatabasePlatform()->getDateAddHourExpression( $this->firstDateExpression->dispatch($sqlWalker), - $this->intervalExpression->dispatch($sqlWalker) + $this->dispatchIntervalExpression($sqlWalker) ); case 'day': return $sqlWalker->getConnection()->getDatabasePlatform()->getDateAddDaysExpression( $this->firstDateExpression->dispatch($sqlWalker), - $this->intervalExpression->dispatch($sqlWalker) + $this->dispatchIntervalExpression($sqlWalker) ); case 'week': return $sqlWalker->getConnection()->getDatabasePlatform()->getDateAddWeeksExpression( $this->firstDateExpression->dispatch($sqlWalker), - $this->intervalExpression->dispatch($sqlWalker) + $this->dispatchIntervalExpression($sqlWalker) ); case 'month': return $sqlWalker->getConnection()->getDatabasePlatform()->getDateAddMonthExpression( $this->firstDateExpression->dispatch($sqlWalker), - $this->intervalExpression->dispatch($sqlWalker) + $this->dispatchIntervalExpression($sqlWalker) ); case 'year': return $sqlWalker->getConnection()->getDatabasePlatform()->getDateAddYearsExpression( $this->firstDateExpression->dispatch($sqlWalker), - $this->intervalExpression->dispatch($sqlWalker) + $this->dispatchIntervalExpression($sqlWalker) ); default: @@ -84,6 +87,19 @@ public function getSql(SqlWalker $sqlWalker) } } + /** + * @return numeric-string + * + * @throws ASTException + */ + private function dispatchIntervalExpression(SqlWalker $sqlWalker) + { + $sql = $this->intervalExpression->dispatch($sqlWalker); + assert(is_numeric($sql)); + + return $sql; + } + /** * @override * @inheritdoc diff --git a/lib/Doctrine/ORM/Query/AST/Functions/DateSubFunction.php b/lib/Doctrine/ORM/Query/AST/Functions/DateSubFunction.php index a6ae22523a3..8aa2a43919b 100644 --- a/lib/Doctrine/ORM/Query/AST/Functions/DateSubFunction.php +++ b/lib/Doctrine/ORM/Query/AST/Functions/DateSubFunction.php @@ -4,9 +4,12 @@ namespace Doctrine\ORM\Query\AST\Functions; +use Doctrine\ORM\Query\AST\ASTException; use Doctrine\ORM\Query\QueryException; use Doctrine\ORM\Query\SqlWalker; +use function assert; +use function is_numeric; use function strtolower; /** @@ -26,43 +29,43 @@ public function getSql(SqlWalker $sqlWalker) case 'second': return $sqlWalker->getConnection()->getDatabasePlatform()->getDateSubSecondsExpression( $this->firstDateExpression->dispatch($sqlWalker), - $this->intervalExpression->dispatch($sqlWalker) + $this->dispatchIntervalExpression($sqlWalker) ); case 'minute': return $sqlWalker->getConnection()->getDatabasePlatform()->getDateSubMinutesExpression( $this->firstDateExpression->dispatch($sqlWalker), - $this->intervalExpression->dispatch($sqlWalker) + $this->dispatchIntervalExpression($sqlWalker) ); case 'hour': return $sqlWalker->getConnection()->getDatabasePlatform()->getDateSubHourExpression( $this->firstDateExpression->dispatch($sqlWalker), - $this->intervalExpression->dispatch($sqlWalker) + $this->dispatchIntervalExpression($sqlWalker) ); case 'day': return $sqlWalker->getConnection()->getDatabasePlatform()->getDateSubDaysExpression( $this->firstDateExpression->dispatch($sqlWalker), - $this->intervalExpression->dispatch($sqlWalker) + $this->dispatchIntervalExpression($sqlWalker) ); case 'week': return $sqlWalker->getConnection()->getDatabasePlatform()->getDateSubWeeksExpression( $this->firstDateExpression->dispatch($sqlWalker), - $this->intervalExpression->dispatch($sqlWalker) + $this->dispatchIntervalExpression($sqlWalker) ); case 'month': return $sqlWalker->getConnection()->getDatabasePlatform()->getDateSubMonthExpression( $this->firstDateExpression->dispatch($sqlWalker), - $this->intervalExpression->dispatch($sqlWalker) + $this->dispatchIntervalExpression($sqlWalker) ); case 'year': return $sqlWalker->getConnection()->getDatabasePlatform()->getDateSubYearsExpression( $this->firstDateExpression->dispatch($sqlWalker), - $this->intervalExpression->dispatch($sqlWalker) + $this->dispatchIntervalExpression($sqlWalker) ); default: @@ -71,4 +74,17 @@ public function getSql(SqlWalker $sqlWalker) ); } } + + /** + * @return numeric-string + * + * @throws ASTException + */ + private function dispatchIntervalExpression(SqlWalker $sqlWalker) + { + $sql = $this->intervalExpression->dispatch($sqlWalker); + assert(is_numeric($sql)); + + return $sql; + } } diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 35527c844e9..e53c16fbb0b 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -270,81 +270,11 @@ parameters: count: 1 path: lib/Doctrine/ORM/Query/AST/Functions/DateAddFunction.php - - - message: "#^Parameter \\#2 \\$days of method Doctrine\\\\DBAL\\\\Platforms\\\\AbstractPlatform\\:\\:getDateAddDaysExpression\\(\\) expects int, string given\\.$#" - count: 1 - path: lib/Doctrine/ORM/Query/AST/Functions/DateAddFunction.php - - - - message: "#^Parameter \\#2 \\$hours of method Doctrine\\\\DBAL\\\\Platforms\\\\AbstractPlatform\\:\\:getDateAddHourExpression\\(\\) expects int, string given\\.$#" - count: 1 - path: lib/Doctrine/ORM/Query/AST/Functions/DateAddFunction.php - - - - message: "#^Parameter \\#2 \\$minutes of method Doctrine\\\\DBAL\\\\Platforms\\\\AbstractPlatform\\:\\:getDateAddMinutesExpression\\(\\) expects int, string given\\.$#" - count: 1 - path: lib/Doctrine/ORM/Query/AST/Functions/DateAddFunction.php - - - - message: "#^Parameter \\#2 \\$months of method Doctrine\\\\DBAL\\\\Platforms\\\\AbstractPlatform\\:\\:getDateAddMonthExpression\\(\\) expects int, string given\\.$#" - count: 1 - path: lib/Doctrine/ORM/Query/AST/Functions/DateAddFunction.php - - - - message: "#^Parameter \\#2 \\$seconds of method Doctrine\\\\DBAL\\\\Platforms\\\\AbstractPlatform\\:\\:getDateAddSecondsExpression\\(\\) expects int, string given\\.$#" - count: 1 - path: lib/Doctrine/ORM/Query/AST/Functions/DateAddFunction.php - - - - message: "#^Parameter \\#2 \\$weeks of method Doctrine\\\\DBAL\\\\Platforms\\\\AbstractPlatform\\:\\:getDateAddWeeksExpression\\(\\) expects int, string given\\.$#" - count: 1 - path: lib/Doctrine/ORM/Query/AST/Functions/DateAddFunction.php - - - - message: "#^Parameter \\#2 \\$years of method Doctrine\\\\DBAL\\\\Platforms\\\\AbstractPlatform\\:\\:getDateAddYearsExpression\\(\\) expects int, string given\\.$#" - count: 1 - path: lib/Doctrine/ORM/Query/AST/Functions/DateAddFunction.php - - message: "#^Access to an undefined property Doctrine\\\\ORM\\\\Query\\\\AST\\\\Node\\:\\:\\$value\\.$#" count: 1 path: lib/Doctrine/ORM/Query/AST/Functions/DateSubFunction.php - - - message: "#^Parameter \\#2 \\$days of method Doctrine\\\\DBAL\\\\Platforms\\\\AbstractPlatform\\:\\:getDateSubDaysExpression\\(\\) expects int, string given\\.$#" - count: 1 - path: lib/Doctrine/ORM/Query/AST/Functions/DateSubFunction.php - - - - message: "#^Parameter \\#2 \\$hours of method Doctrine\\\\DBAL\\\\Platforms\\\\AbstractPlatform\\:\\:getDateSubHourExpression\\(\\) expects int, string given\\.$#" - count: 1 - path: lib/Doctrine/ORM/Query/AST/Functions/DateSubFunction.php - - - - message: "#^Parameter \\#2 \\$minutes of method Doctrine\\\\DBAL\\\\Platforms\\\\AbstractPlatform\\:\\:getDateSubMinutesExpression\\(\\) expects int, string given\\.$#" - count: 1 - path: lib/Doctrine/ORM/Query/AST/Functions/DateSubFunction.php - - - - message: "#^Parameter \\#2 \\$months of method Doctrine\\\\DBAL\\\\Platforms\\\\AbstractPlatform\\:\\:getDateSubMonthExpression\\(\\) expects int, string given\\.$#" - count: 1 - path: lib/Doctrine/ORM/Query/AST/Functions/DateSubFunction.php - - - - message: "#^Parameter \\#2 \\$seconds of method Doctrine\\\\DBAL\\\\Platforms\\\\AbstractPlatform\\:\\:getDateSubSecondsExpression\\(\\) expects int, string given\\.$#" - count: 1 - path: lib/Doctrine/ORM/Query/AST/Functions/DateSubFunction.php - - - - message: "#^Parameter \\#2 \\$weeks of method Doctrine\\\\DBAL\\\\Platforms\\\\AbstractPlatform\\:\\:getDateSubWeeksExpression\\(\\) expects int, string given\\.$#" - count: 1 - path: lib/Doctrine/ORM/Query/AST/Functions/DateSubFunction.php - - - - message: "#^Parameter \\#2 \\$years of method Doctrine\\\\DBAL\\\\Platforms\\\\AbstractPlatform\\:\\:getDateSubYearsExpression\\(\\) expects int, string given\\.$#" - count: 1 - path: lib/Doctrine/ORM/Query/AST/Functions/DateSubFunction.php - - message: "#^Parameter \\#1 \\$simpleArithmeticExpr of method Doctrine\\\\ORM\\\\Query\\\\SqlWalker\\:\\:walkSimpleArithmeticExpression\\(\\) expects Doctrine\\\\ORM\\\\Query\\\\AST\\\\SimpleArithmeticExpression, Doctrine\\\\ORM\\\\Query\\\\AST\\\\Node given\\.$#" count: 1 From d8159b8be27e0c89a28bd88aa078aa06e780d7c5 Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Sun, 8 May 2022 11:27:08 -0700 Subject: [PATCH 3/5] Suppress known issues related to sequence-based identity generation See https://github.com/doctrine/orm/issues/8850 --- phpstan-dbal4.neon | 7 +++++++ psalm.xml | 3 +++ 2 files changed, 10 insertions(+) diff --git a/phpstan-dbal4.neon b/phpstan-dbal4.neon index e7e618c9019..83b83b0f4e6 100644 --- a/phpstan-dbal4.neon +++ b/phpstan-dbal4.neon @@ -14,3 +14,10 @@ parameters: - message: '~^Variable \$e on left side of \?\? always exists and is not nullable\.$~' path: lib/Doctrine/ORM/UnitOfWork.php + + # See https://github.com/doctrine/orm/issues/8850 + - + message: '~^Method Doctrine\\DBAL\\Connection::lastInsertId\(\) invoked with 1 parameter, 0 required\.$~' + paths: + - lib/Doctrine/ORM/Id/BigIntegerIdentityGenerator.php + - lib/Doctrine/ORM/Id/IdentityGenerator.php diff --git a/psalm.xml b/psalm.xml index 9cafaf741e2..a19ffbb23a4 100644 --- a/psalm.xml +++ b/psalm.xml @@ -88,6 +88,9 @@ + + + From 0119d8cbbc06cedc044b68903ac7357c439ad088 Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Sun, 8 May 2022 11:46:59 -0700 Subject: [PATCH 4/5] Accommodate API changes in the Column class See https://github.com/doctrine/dbal/pull/3511 --- .../ORM/Mapping/Driver/DatabaseDriver.php | 15 ++++++--------- psalm.xml | 12 ++++++++++++ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/lib/Doctrine/ORM/Mapping/Driver/DatabaseDriver.php b/lib/Doctrine/ORM/Mapping/Driver/DatabaseDriver.php index cfd5c46e4b6..886714b49ea 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/DatabaseDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/DatabaseDriver.php @@ -391,11 +391,11 @@ private function buildFieldMappings(ClassMetadata $metadata): void * columnName: string, * type: string, * nullable: bool, - * options?: array{ + * options: array{ * unsigned?: bool, * fixed?: bool, - * comment?: string, - * default?: string + * comment: string|null, + * default?: mixed * }, * precision?: int, * scale?: int, @@ -409,6 +409,9 @@ private function buildFieldMapping(string $tableName, Column $column): array 'columnName' => $column->getName(), 'type' => Type::getTypeRegistry()->lookupName($column->getType()), 'nullable' => ! $column->getNotnull(), + 'options' => [ + 'comment' => $column->getComment(), + ], ]; // Type specific elements @@ -437,12 +440,6 @@ private function buildFieldMapping(string $tableName, Column $column): array break; } - // Comment - $comment = $column->getComment(); - if ($comment !== null) { - $fieldMapping['options']['comment'] = $comment; - } - // Default $default = $column->getDefault(); if ($default !== null) { diff --git a/psalm.xml b/psalm.xml index a19ffbb23a4..3a4f0e04eae 100644 --- a/psalm.xml +++ b/psalm.xml @@ -52,6 +52,18 @@ + + + + + + + + + + + + From 2e856599b36293c60cc3208422721bf01734acb8 Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Sat, 7 May 2022 19:44:18 -0700 Subject: [PATCH 5/5] Run static analysis with DBAL 4@dev --- .github/workflows/static-analysis.yml | 71 ++++++++++++++++++++++++--- composer.json | 2 +- 2 files changed, 65 insertions(+), 8 deletions(-) diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 0e2a253610e..f46c5505b5b 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -1,5 +1,4 @@ - -name: "Static Analysis" +name: Static Analysis on: pull_request: @@ -10,8 +9,66 @@ on: - "*.x" jobs: - static-analysis: - name: "Static Analysis" - uses: "doctrine/.github/.github/workflows/static-analysis.yml@1.4.1" - with: - php-version: "8.1" + static-analysis-phpstan: + name: Static Analysis with PHPStan + runs-on: ubuntu-20.04 + + strategy: + matrix: + include: + - dbal-version: default + config: phpstan.neon + - dbal-version: 4@dev + config: phpstan-dbal4.neon + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Install PHP + uses: shivammathur/setup-php@v2 + with: + coverage: none + php-version: "8.1" + tools: cs2pr + + - name: Require specific DBAL version + run: "composer require doctrine/dbal ^${{ matrix.dbal-version }} --no-update" + if: "${{ matrix.dbal-version != 'default' }}" + + - name: Install dependencies with Composer + uses: ramsey/composer-install@v1 + + - name: Run static analysis with phpstan/phpstan + run: "vendor/bin/phpstan analyse -c ${{ matrix.config }} --error-format=checkstyle | cs2pr" + + static-analysis-psalm: + name: Static Analysis with Psalm + runs-on: ubuntu-20.04 + + strategy: + matrix: + dbal-version: + - default + - 4@dev + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Install PHP + uses: shivammathur/setup-php@v2 + with: + coverage: none + php-version: "8.1" + tools: cs2pr + + - name: Require specific DBAL version + run: "composer require doctrine/dbal ^${{ matrix.dbal-version }} --no-update" + if: "${{ matrix.dbal-version != 'default' }}" + + - name: Install dependencies with Composer + uses: ramsey/composer-install@v1 + + - name: Run static analysis with Vimeo Psalm + run: vendor/bin/psalm --shepherd diff --git a/composer.json b/composer.json index 19765e18ede..715ec89876f 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,7 @@ "ext-ctype": "*", "doctrine/collections": "^1.5", "doctrine/common": "^3.3", - "doctrine/dbal": "^3.3", + "doctrine/dbal": "^3.4@dev", "doctrine/deprecations": "^0.5.3 || ^1", "doctrine/event-manager": "^1.1", "doctrine/inflector": "^1.4 || ^2.0",