From 1fa613566364753180f775d2af22e4b4d95abdb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Vo=C5=99=C3=AD=C5=A1ek?= Date: Sat, 22 Jan 2022 13:14:47 +0100 Subject: [PATCH 1/5] Drop DBAL 2.x support --- .github/workflows/test-unit.yml | 8 ----- composer.json | 4 +-- phpstan.neon.dist | 8 ----- src/Persistence/GenericPlatform.php | 35 --------------------- src/Persistence/Sql/Connection.php | 22 +++---------- src/Persistence/Sql/Expression.php | 27 +++------------- src/Schema/Migrator.php | 4 --- src/Schema/TestCase.php | 5 --- tests/ModelNestedSqlTest.php | 4 --- tests/Persistence/Sql/WithDb/SelectTest.php | 4 --- tests/RandomTest.php | 5 ++- 11 files changed, 13 insertions(+), 113 deletions(-) diff --git a/.github/workflows/test-unit.yml b/.github/workflows/test-unit.yml index f3f2ea3e9..a297100d4 100644 --- a/.github/workflows/test-unit.yml +++ b/.github/workflows/test-unit.yml @@ -73,14 +73,6 @@ jobs: echo "memory_limit = 2G" > /usr/local/etc/php/conf.d/custom-memory-limit.ini vendor/bin/phpstan analyse - - name: Run Static Analysis with DBAL 2.x (only for StaticAnalysis) - if: matrix.type == 'StaticAnalysis' - run: | - composer require "doctrine/dbal:^2.10" --ansi --prefer-dist --no-interaction --no-progress --optimize-autoloader - echo ' vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/MySQLPlatform.php - echo ' vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/PostgreSQLPlatform.php - vendor/bin/phpstan analyse - unit-test: name: Unit runs-on: ubuntu-latest diff --git a/composer.json b/composer.json index 214c124e6..0c62d85d1 100644 --- a/composer.json +++ b/composer.json @@ -36,13 +36,13 @@ "require": { "php": ">=7.4 <8.2", "atk4/core": "dev-develop", - "doctrine/dbal": "^2.13.5 || ^3.2", + "doctrine/dbal": "^3.2", "mvorisek/atk4-hintable": "~1.7.1" }, "require-release": { "php": ">=7.4 <8.2", "atk4/core": "~3.2.0", - "doctrine/dbal": "^2.13.5 || ^3.2", + "doctrine/dbal": "^3.2", "mvorisek/atk4-hintable": "~1.7.1" }, "require-dev": { diff --git a/phpstan.neon.dist b/phpstan.neon.dist index f85d3cbda..1ecaf73c1 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -30,14 +30,6 @@ parameters: path: '*' count: 2 - # for Doctrine DBAL 2.x, remove the support once Doctrine ORM 2.10 is released - # see https://github.com/doctrine/orm/issues/8526 - - - message: '~^(Call to an undefined method Doctrine\\DBAL\\Driver\\Connection::getWrappedConnection\(\)\.|Call to an undefined method Doctrine\\DBAL\\Connection::createSchemaManager\(\)\.|Call to an undefined static method Doctrine\\DBAL\\Exception::invalidPdoInstance\(\)\.|Call to method (getCreateTableSQL|getClobTypeDeclarationSQL|initializeCommentedDoctrineTypes)\(\) of deprecated class Doctrine\\DBAL\\Platforms\\\w+Platform:\n.+|Anonymous class extends deprecated class Doctrine\\DBAL\\Platforms\\(PostgreSQL94Platform|SQLServer2012Platform):\n.+|Call to deprecated method fetch(|All)\(\) of class Doctrine\\DBAL\\Result:\n.+|Call to deprecated method getSchemaManager\(\) of class Doctrine\\DBAL\\Connection:\n.+|Call to deprecated method getWrappedConnection\(\) of class Doctrine\\DBAL\\Connection:\n.+getNativeConnection\(\).+|Call to deprecated method getWrappedResourceHandle\(\) of class Doctrine\\DBAL\\Driver\\Mysqli\\Connection:\n.+getNativeConnection\(\).+|Access to an undefined property Doctrine\\DBAL\\Driver\\PDO\\Connection::\$connection\.|Parameter #1 \$dsn of class Doctrine\\DBAL\\Driver\\PDO\\SQLSrv\\Connection constructor expects string, Doctrine\\DBAL\\Driver\\PDO\\Connection given\.|Method Atk4\\Data\\Persistence\\Sql\\Expression::execute\(\) should return Doctrine\\DBAL\\Result\|PDOStatement but returns bool\.|PHPDoc tag @return contains generic type Doctrine\\DBAL\\Schema\\AbstractSchemaManager but class Doctrine\\DBAL\\Schema\\AbstractSchemaManager is not generic\.|Class Doctrine\\DBAL\\Platforms\\(MySqlPlatform|PostgreSqlPlatform) referenced with incorrect case: Doctrine\\DBAL\\Platforms\\(MySQLPlatform|PostgreSQLPlatform)\.)$~' - path: '*' - # count for DBAL 3.x matched in "src/Persistence/GenericPlatform.php" file - count: 40 - # TODO these rules are generated, this ignores should be fixed in the code # for src/Schema/TestCase.php - '~^Access to an undefined property Atk4\\Data\\Persistence::\$connection\.$~' diff --git a/src/Persistence/GenericPlatform.php b/src/Persistence/GenericPlatform.php index 3fe2df090..ff511e714 100644 --- a/src/Persistence/GenericPlatform.php +++ b/src/Persistence/GenericPlatform.php @@ -6,46 +6,11 @@ use Doctrine\DBAL\Exception as DbalException; use Doctrine\DBAL\Platforms; -use Mvorisek\Atk4\Hintable\Phpstan\PhpstanUtil; class GenericPlatform extends Platforms\AbstractPlatform { private function createNotSupportedException(): \Exception { - if (\Atk4\Data\Persistence\Sql\Connection::isComposerDbal2x()) { - // hack for PHPStan, keep ignored error count for DBAL 2.x and DBAL 3.x the same - if (PhpstanUtil::alwaysFalseAnalyseOnly()) { - $connection = (new class() extends Sql\Connection {})->connection(); - $connection->getSchemaManager(); - $connection->getSchemaManager(); - $connection->getSchemaManager(); - $connection->getSchemaManager(); - $connection->getSchemaManager(); - $connection->getSchemaManager(); - $connection->getSchemaManager(); - $connection->getSchemaManager(); - $connection->getSchemaManager(); - $connection->getSchemaManager(); - $connection->getSchemaManager(); - $connection->getSchemaManager(); - $connection->getSchemaManager(); - $connection->getSchemaManager(); - $connection->getSchemaManager(); - $connection->getSchemaManager(); - $connection->getSchemaManager(); - $connection->getSchemaManager(); - $connection->getSchemaManager(); - $connection->getSchemaManager(); - $connection->getSchemaManager(); - $connection->getSchemaManager(); - $connection->getSchemaManager(); - $connection->getSchemaManager(); - $connection->getSchemaManager(); - $connection->getSchemaManager(); - $connection->getSchemaManager(); - } - } - return DbalException::notSupported('SQL'); } diff --git a/src/Persistence/Sql/Connection.php b/src/Persistence/Sql/Connection.php index 9de952a32..06a11c6fe 100644 --- a/src/Persistence/Sql/Connection.php +++ b/src/Persistence/Sql/Connection.php @@ -201,11 +201,6 @@ public static function connect($dsn, $user = null, $password = null, $args = []) ], $args)); } - final public static function isComposerDbal2x(): bool - { - return !class_exists(DbalResult::class); - } - /** * @param DbalDriverConnection|DbalConnection $connection * @@ -216,17 +211,10 @@ private static function getDriverFromDbalDriverConnection(object $connection) // TODO replace this method with Connection::getNativeConnection() once only DBAL 3.3+ is supported // https://github.com/doctrine/dbal/pull/5037 - if (self::isComposerDbal2x()) { - if ($connection instanceof \PDO || $connection instanceof \mysqli) { - return $connection; - } - } - - $isDbal2x = self::isComposerDbal2x(); // remove once https://github.com/phpstan/phpstan/issues/6319 is fixed $wrappedConnection = $connection instanceof DbalMysqliConnection ? $connection->getWrappedResourceHandle() : ($connection instanceof DbalOci8Connection - ? \Closure::bind(fn () => $isDbal2x ? $connection->dbh : $connection->connection, null, DbalOci8Connection::class)() // @phpstan-ignore-line + ? \Closure::bind(fn () => $connection->connection, null, DbalOci8Connection::class)() : $connection->getWrappedConnection()); if ($wrappedConnection instanceof \PDO || $wrappedConnection instanceof \mysqli @@ -286,7 +274,7 @@ protected static function connectFromDbalDriverConnection(DbalDriverConnection $ if ($dbalConnection->getDatabasePlatform() instanceof PostgreSQLPlatform) { \Closure::bind(function () use ($dbalConnection) { - $dbalConnection->platform = new class() extends \Doctrine\DBAL\Platforms\PostgreSQL94Platform { + $dbalConnection->platform = new class() extends \Doctrine\DBAL\Platforms\PostgreSQL94Platform { // @phpstan-ignore-line use Postgresql\PlatformTrait; }; }, null, DbalConnection::class)(); @@ -294,7 +282,7 @@ protected static function connectFromDbalDriverConnection(DbalDriverConnection $ if ($dbalConnection->getDatabasePlatform() instanceof SQLServerPlatform) { \Closure::bind(function () use ($dbalConnection) { - $dbalConnection->platform = new class() extends \Doctrine\DBAL\Platforms\SQLServer2012Platform { + $dbalConnection->platform = new class() extends \Doctrine\DBAL\Platforms\SQLServer2012Platform { // @phpstan-ignore-line use Mssql\PlatformTrait; }; }, null, DbalConnection::class)(); @@ -350,10 +338,8 @@ public function connection() /** * Execute Expression by using this connection. - * - * @return DbalResult|\PDOStatement PDOStatement iff for DBAL 2.x */ - public function execute(Expression $expr): object + public function execute(Expression $expr): DbalResult { if ($this->connection === null) { throw new Exception('Queries cannot be executed through this connection'); diff --git a/src/Persistence/Sql/Expression.php b/src/Persistence/Sql/Expression.php index 45630d923..014448345 100644 --- a/src/Persistence/Sql/Expression.php +++ b/src/Persistence/Sql/Expression.php @@ -530,10 +530,8 @@ function ($matches) use ($params, &$numParams, &$i, &$j) { /** * @param DbalConnection|Connection $connection - * - * @return DbalResult|\PDOStatement PDOStatement iff for DBAL 2.x */ - public function execute(object $connection = null): object + public function execute(object $connection = null): DbalResult { if ($connection === null) { $connection = $this->connection; @@ -600,9 +598,6 @@ public function execute(object $connection = null): object } $result = $statement->execute(); // @phpstan-ignore-line - if (Connection::isComposerDbal2x()) { - return $statement; // @phpstan-ignore-line - } return $result; } catch (DbalException $e) { @@ -653,11 +648,7 @@ public function getRowsIterator(): \Traversable { // DbalResult::iterateAssociative() is broken with streams with Oracle database // https://github.com/doctrine/dbal/issues/5002 - if (Connection::isComposerDbal2x()) { - $iterator = $this->execute(); - } else { - $iterator = $this->execute()->iterateAssociative(); - } + $iterator = $this->execute()->iterateAssociative(); foreach ($iterator as $row) { yield array_map(function ($v) { @@ -675,14 +666,10 @@ public function getRows(): array { // DbalResult::fetchAllAssociative() is broken with streams with Oracle database // https://github.com/doctrine/dbal/issues/5002 - if (Connection::isComposerDbal2x()) { - $result = $this->execute(); - } else { - $result = $this->execute(); - } + $result = $this->execute(); $rows = []; - while (($row = Connection::isComposerDbal2x() ? $result->fetchAssociative() : $result->fetch()) !== false) { + while (($row = $result->fetchAssociative()) !== false) { $rows[] = array_map(function ($v) { return $this->castGetValue($v); }, $row); @@ -698,11 +685,7 @@ public function getRows(): array */ public function getRow(): ?array { - if (Connection::isComposerDbal2x()) { - $row = $this->execute()->fetch(); - } else { - $row = $this->execute()->fetchAssociative(); - } + $row = $this->execute()->fetchAssociative(); if ($row === false) { return null; diff --git a/src/Schema/Migrator.php b/src/Schema/Migrator.php index 891ae6d93..14da7986b 100644 --- a/src/Schema/Migrator.php +++ b/src/Schema/Migrator.php @@ -69,10 +69,6 @@ protected function getDatabasePlatform(): AbstractPlatform */ protected function createSchemaManager(): AbstractSchemaManager { - if (Connection::isComposerDbal2x()) { - return $this->connection->connection()->getSchemaManager(); - } - return $this->connection->connection()->createSchemaManager(); } diff --git a/src/Schema/TestCase.php b/src/Schema/TestCase.php index da1dcabf3..e32b63f74 100644 --- a/src/Schema/TestCase.php +++ b/src/Schema/TestCase.php @@ -7,7 +7,6 @@ use Atk4\Core\Phpunit\TestCase as BaseTestCase; use Atk4\Data\Model; use Atk4\Data\Persistence; -use Atk4\Data\Persistence\Sql\Connection; use Doctrine\DBAL\Logging\SQLLogger; use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Platforms\MySQLPlatform; @@ -96,10 +95,6 @@ protected function getDatabasePlatform(): AbstractPlatform */ protected function createSchemaManager(): AbstractSchemaManager { - if (Connection::isComposerDbal2x()) { - return $this->db->connection->connection()->getSchemaManager(); - } - return $this->db->connection->connection()->createSchemaManager(); } diff --git a/tests/ModelNestedSqlTest.php b/tests/ModelNestedSqlTest.php index 3fb2f592f..93cc5a0d2 100644 --- a/tests/ModelNestedSqlTest.php +++ b/tests/ModelNestedSqlTest.php @@ -7,7 +7,6 @@ use Atk4\Core\HookBreaker; use Atk4\Data\Model; use Atk4\Data\Persistence; -use Atk4\Data\Persistence\Sql\Connection; use Atk4\Data\Persistence\Sql\Query; use Atk4\Data\Schema\TestCase; use Doctrine\DBAL\Result as DbalResult; @@ -54,9 +53,6 @@ protected function convertValueToLog($v) } $res = preg_replace('~(?<=^Atk4\\\\Data\\\\Persistence\\\\Sql\\\\)\w+\\\\(?=\w+$)~', '', get_debug_type($v)); - if (Connection::isComposerDbal2x() && $res === 'Doctrine\DBAL\Statement') { - $res = DbalResult::class; - } return $res; } diff --git a/tests/Persistence/Sql/WithDb/SelectTest.php b/tests/Persistence/Sql/WithDb/SelectTest.php index 0d16231f2..6f7071f64 100644 --- a/tests/Persistence/Sql/WithDb/SelectTest.php +++ b/tests/Persistence/Sql/WithDb/SelectTest.php @@ -259,10 +259,6 @@ public function testExecuteException(): void $expectedErrorCode = 1; // SQLSTATE[HY000]: General error: 1 no such table: non_existing_table } - if (Connection::isComposerDbal2x() && $e->getCode() === 0) { - $this->markTestIncomplete('DBAL 2.x with non-PDO driver does not set exception code'); - } - $this->assertSame($expectedErrorCode, $e->getCode()); $this->assertSameSql( preg_replace('~\s+~', '', 'select "non_existing_field" from "non_existing_table"'), diff --git a/tests/RandomTest.php b/tests/RandomTest.php index 068ebba6c..e5bfb1824 100644 --- a/tests/RandomTest.php +++ b/tests/RandomTest.php @@ -9,7 +9,6 @@ use Atk4\Data\Field; use Atk4\Data\Model; use Atk4\Data\Persistence; -use Atk4\Data\Persistence\Sql\Connection; use Atk4\Data\Persistence\Sql\Expression; use Atk4\Data\Schema\TestCase; use Doctrine\DBAL\Platforms\OraclePlatform; @@ -529,13 +528,13 @@ public function testNoWriteActionDelete(): void public function testTableWithSchema(): void { - if ($this->getDatabasePlatform() instanceof SqlitePlatform || Connection::isComposerDbal2x()) { + if ($this->getDatabasePlatform() instanceof SqlitePlatform) { $userSchema = 'db1'; $docSchema = 'db2'; $runWithDb = false; } else { $dbSchema = $this->db->connection->dsql() - ->field(null ?? new Expression($this->getDatabasePlatform()->getCurrentDatabaseExpression())) // @phpstan-ignore-line for DBAL 2.x + ->field(new Expression($this->getDatabasePlatform()->getCurrentDatabaseExpression())) ->getOne(); $userSchema = $dbSchema; $docSchema = $dbSchema; From 6dd8b317dce2afe8f0e451b0346e9a918b61e95e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Vo=C5=99=C3=AD=C5=A1ek?= Date: Sat, 22 Jan 2022 14:04:38 +0100 Subject: [PATCH 2/5] require DBAL v3.3+ for getNativeConnection() method --- composer.json | 4 +-- src/Persistence/Sql/Connection.php | 28 +------------------ src/Persistence/Sql/Mysql/ExpressionTrait.php | 9 +----- 3 files changed, 4 insertions(+), 37 deletions(-) diff --git a/composer.json b/composer.json index 0c62d85d1..e6317ee7f 100644 --- a/composer.json +++ b/composer.json @@ -36,13 +36,13 @@ "require": { "php": ">=7.4 <8.2", "atk4/core": "dev-develop", - "doctrine/dbal": "^3.2", + "doctrine/dbal": "^3.3", "mvorisek/atk4-hintable": "~1.7.1" }, "require-release": { "php": ">=7.4 <8.2", "atk4/core": "~3.2.0", - "doctrine/dbal": "^3.2", + "doctrine/dbal": "^3.ลก", "mvorisek/atk4-hintable": "~1.7.1" }, "require-dev": { diff --git a/src/Persistence/Sql/Connection.php b/src/Persistence/Sql/Connection.php index 06a11c6fe..afe0e8830 100644 --- a/src/Persistence/Sql/Connection.php +++ b/src/Persistence/Sql/Connection.php @@ -8,8 +8,6 @@ use Doctrine\Common\EventManager; use Doctrine\DBAL\Connection as DbalConnection; use Doctrine\DBAL\Driver\Connection as DbalDriverConnection; -use Doctrine\DBAL\Driver\Mysqli\Connection as DbalMysqliConnection; -use Doctrine\DBAL\Driver\OCI8\Connection as DbalOci8Connection; use Doctrine\DBAL\DriverManager; use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Platforms\OraclePlatform; @@ -201,33 +199,9 @@ public static function connect($dsn, $user = null, $password = null, $args = []) ], $args)); } - /** - * @param DbalDriverConnection|DbalConnection $connection - * - * @return object|resource - */ - private static function getDriverFromDbalDriverConnection(object $connection) - { - // TODO replace this method with Connection::getNativeConnection() once only DBAL 3.3+ is supported - // https://github.com/doctrine/dbal/pull/5037 - - $wrappedConnection = $connection instanceof DbalMysqliConnection - ? $connection->getWrappedResourceHandle() - : ($connection instanceof DbalOci8Connection - ? \Closure::bind(fn () => $connection->connection, null, DbalOci8Connection::class)() - : $connection->getWrappedConnection()); - - if ($wrappedConnection instanceof \PDO || $wrappedConnection instanceof \mysqli - || (is_resource($wrappedConnection) && get_resource_type($wrappedConnection) === 'oci8 connection')) { - return $wrappedConnection; - } - - return self::getDriverFromDbalDriverConnection($wrappedConnection); - } - private static function getDriverNameFromDbalDriverConnection(DbalDriverConnection $connection): string { - $driver = self::getDriverFromDbalDriverConnection($connection); + $driver = $connection->getNativeConnection(); if ($driver instanceof \PDO) { return 'pdo_' . $driver->getAttribute(\PDO::ATTR_DRIVER_NAME); diff --git a/src/Persistence/Sql/Mysql/ExpressionTrait.php b/src/Persistence/Sql/Mysql/ExpressionTrait.php index 29a8804e3..8d74e2764 100644 --- a/src/Persistence/Sql/Mysql/ExpressionTrait.php +++ b/src/Persistence/Sql/Mysql/ExpressionTrait.php @@ -4,19 +4,12 @@ namespace Atk4\Data\Persistence\Sql\Mysql; -use Atk4\Data\Persistence\Sql\Connection as SqlConnection; - trait ExpressionTrait { protected function hasNativeNamedParamSupport(): bool { - // TODO use Connection::getNativeConnection() once only DBAL 3.3+ is supported - // https://github.com/doctrine/dbal/pull/5037 $dbalConnection = $this->connection->connection(); - $nativeConnection = \Closure::bind(function () use ($dbalConnection) { - return SqlConnection::getDriverFromDbalDriverConnection($dbalConnection->getWrappedConnection()); - }, null, SqlConnection::class)(); - return !$nativeConnection instanceof \mysqli; + return !$dbalConnection->getNativeConnection() instanceof \mysqli; } } From 934822e9f5370a5d1254995535276544773b4207 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Vo=C5=99=C3=AD=C5=A1ek?= Date: Sat, 22 Jan 2022 14:24:07 +0100 Subject: [PATCH 3/5] fix 962 issue --- src/Persistence/Sql/Mssql/PlatformTrait.php | 14 ++++++++------ src/Persistence/Sql/Oracle/PlatformTrait.php | 16 +++++++++------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/Persistence/Sql/Mssql/PlatformTrait.php b/src/Persistence/Sql/Mssql/PlatformTrait.php index 6be0675f1..900391b96 100644 --- a/src/Persistence/Sql/Mssql/PlatformTrait.php +++ b/src/Persistence/Sql/Mssql/PlatformTrait.php @@ -15,12 +15,14 @@ public function getClobTypeDeclarationSQL(array $column) return (str_starts_with($res, 'VARCHAR') ? 'N' : '') . $res; } - protected function initializeCommentedDoctrineTypes() - { - parent::initializeCommentedDoctrineTypes(); - - $this->markDoctrineTypeCommented('text'); - } + // TODO test DBAL DB diff for each supported Field type + // then fix using https://github.com/doctrine/dbal/issues/5194#issuecomment-1018790220 +// protected function initializeCommentedDoctrineTypes() +// { +// parent::initializeCommentedDoctrineTypes(); +// +// $this->markDoctrineTypeCommented('text'); +// } // SQL Server DBAL platform has buggy identifier escaping, fix until fixed officially, see: // https://github.com/doctrine/dbal/pull/4360 diff --git a/src/Persistence/Sql/Oracle/PlatformTrait.php b/src/Persistence/Sql/Oracle/PlatformTrait.php index 686dfa5e5..f09004e21 100644 --- a/src/Persistence/Sql/Oracle/PlatformTrait.php +++ b/src/Persistence/Sql/Oracle/PlatformTrait.php @@ -22,13 +22,15 @@ public function getBlobTypeDeclarationSQL(array $column) return $this->getClobTypeDeclarationSQL($column); } - protected function initializeCommentedDoctrineTypes() - { - parent::initializeCommentedDoctrineTypes(); - - $this->markDoctrineTypeCommented('binary'); - $this->markDoctrineTypeCommented('blob'); - } + // TODO test DBAL DB diff for each supported Field type + // then fix using https://github.com/doctrine/dbal/issues/5194#issuecomment-1018790220 +// protected function initializeCommentedDoctrineTypes() +// { +// parent::initializeCommentedDoctrineTypes(); +// +// $this->markDoctrineTypeCommented('binary'); +// $this->markDoctrineTypeCommented('blob'); +// } // Oracle DBAL platform autoincrement implementation does not increment like // Sqlite or MySQL does, unify the behaviour From 8d0612380add60a50e85e145038a173b76c5769f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Vo=C5=99=C3=AD=C5=A1ek?= Date: Sat, 22 Jan 2022 15:13:06 +0100 Subject: [PATCH 4/5] fix stan --- phpstan.neon.dist | 6 ++++++ src/Persistence/Sql/Connection.php | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 1ecaf73c1..c8a464f0a 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -30,6 +30,12 @@ parameters: path: '*' count: 2 + # fix https://github.com/phpstan/phpstan-deprecation-rules/issues/52 and https://github.com/phpstan/phpstan/issues/6444 + - + message: '~^Call to method (getClobTypeDeclarationSQL|getCreateTableSQL)\(\) of deprecated class Doctrine\\DBAL\\Platforms\\(SQLServerPlatform|AbstractPlatform):\nUse.+instead\.$~' + path: '*' + count: 2 + # TODO these rules are generated, this ignores should be fixed in the code # for src/Schema/TestCase.php - '~^Access to an undefined property Atk4\\Data\\Persistence::\$connection\.$~' diff --git a/src/Persistence/Sql/Connection.php b/src/Persistence/Sql/Connection.php index afe0e8830..157b8392f 100644 --- a/src/Persistence/Sql/Connection.php +++ b/src/Persistence/Sql/Connection.php @@ -180,7 +180,7 @@ public static function resolveConnectionClass(string $driverName): string public static function connect($dsn, $user = null, $password = null, $args = []) { if ($dsn instanceof DbalConnection) { - $driverName = self::getDriverNameFromDbalDriverConnection($dsn->getWrappedConnection()); + $driverName = self::getDriverNameFromDbalDriverConnection($dsn->getWrappedConnection()); // @phpstan-ignore-line https://github.com/doctrine/dbal/issues/5199 $connectionClass = self::resolveConnectionClass($driverName); $dbalConnection = $dsn; } elseif ($dsn instanceof DbalDriverConnection) { @@ -234,7 +234,7 @@ protected static function connectFromDsn(array $dsn): DbalDriverConnection (static::class)::createDbalEventManager() ); - return $dbalConnection->getWrappedConnection(); + return $dbalConnection->getWrappedConnection(); // @phpstan-ignore-line https://github.com/doctrine/dbal/issues/5199 } protected static function connectFromDbalDriverConnection(DbalDriverConnection $dbalDriverConnection): DbalConnection From 68cd064fee520ccf99470bed1f504654bce03fbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Vo=C5=99=C3=AD=C5=A1ek?= Date: Sat, 22 Jan 2022 22:35:44 +0100 Subject: [PATCH 5/5] HOOK_AFTER_*_QUERY pass affected rows --- docs/hooks.rst | 9 ++++----- docs/sql.rst | 2 +- src/Persistence/Sql.php | 16 +++++++--------- tests/ModelNestedSqlTest.php | 7 +++---- tests/RandomTest.php | 8 ++++---- 5 files changed, 19 insertions(+), 23 deletions(-) diff --git a/docs/hooks.rst b/docs/hooks.rst index 173bccf5a..6f5e5f7de 100644 --- a/docs/hooks.rst +++ b/docs/hooks.rst @@ -193,13 +193,12 @@ and your update() may not actually update anything. This does not normally generate an error, however if you want to actually make sure that update() was effective, you can implement this through a hook:: - $m->onHook(Persistence\Sql::HOOK_AFTER_UPDATE_QUERY, function($m, $update, $st) { - if (!$st->rowCount()) { + $m->onHook(Persistence\Sql::HOOK_AFTER_UPDATE_QUERY, function($m, $update, $c) { + if ($c === 0) { throw (new \Atk4\Core\Exception('Update didn\'t affect any records')) ->addMoreInfo('query', $update->getDebugQuery()) - ->addMoreInfo('statement', $st) - ->addMoreInfo('model', $m) - ->addMoreInfo('conditions', $m->conditions); + ->addMoreInfo('statement', $c) + ->addMoreInfo('model', $m); } }); diff --git a/docs/sql.rst b/docs/sql.rst index ce77f8f2c..12a4e4a7c 100644 --- a/docs/sql.rst +++ b/docs/sql.rst @@ -466,7 +466,7 @@ procedure inside Model::init() then set $table property to a temporary table:: function init(): void { parent::init(); - $q = $this->expr("call get_nominal_sheet([],[],'2014-10-01','2015-09-30',0)", [ + $res = $this->expr("call get_nominal_sheet([],[],'2014-10-01','2015-09-30',0)", [ $this->getApp()->system->getId(), $this->getApp()->system['contractor_id'] ])->execute(); diff --git a/src/Persistence/Sql.php b/src/Persistence/Sql.php index 62e5f6ba7..6bd5610c2 100644 --- a/src/Persistence/Sql.php +++ b/src/Persistence/Sql.php @@ -549,10 +549,9 @@ protected function insertRaw(Model $model, array $dataRaw) $insert->setMulti($dataRaw); - $st = null; try { $model->hook(self::HOOK_BEFORE_INSERT_QUERY, [$insert]); - $st = $insert->execute(); + $c = $insert->execute()->rowCount(); } catch (SqlException $e) { throw (new Exception('Unable to execute insert query', 0, $e)) ->addMoreInfo('model', $model) @@ -568,7 +567,7 @@ protected function insertRaw(Model $model, array $dataRaw) $idRaw = ''; } - $model->hook(self::HOOK_AFTER_INSERT_QUERY, [$insert, $st]); + $model->hook(self::HOOK_AFTER_INSERT_QUERY, [$insert, $c]); return $idRaw; } @@ -584,9 +583,8 @@ protected function updateRaw(Model $model, $idRaw, array $dataRaw): void $model->hook(self::HOOK_BEFORE_UPDATE_QUERY, [$update]); - $st = null; try { - $st = $update->execute(); + $c = $update->execute()->rowCount(); } catch (SqlException $e) { throw (new Exception('Unable to update due to query error', 0, $e)) ->addMoreInfo('model', $model) @@ -602,10 +600,10 @@ protected function updateRaw(Model $model, $idRaw, array $dataRaw): void } } - $model->hook(self::HOOK_AFTER_UPDATE_QUERY, [$update, $st]); + $model->hook(self::HOOK_AFTER_UPDATE_QUERY, [$update, $c]); // if any rows were updated in database, and we had expressions, reload - if ($model->reload_after_save && $st->rowCount()) { + if ($model->reload_after_save && $c > 0) { $d = $model->getDirtyRef(); $model->reload(); \Closure::bind(function () use ($model) { @@ -624,14 +622,14 @@ protected function deleteRaw(Model $model, $idRaw): void $model->hook(self::HOOK_BEFORE_DELETE_QUERY, [$delete]); try { - $st = $delete->execute(); + $c = $delete->execute()->rowCount(); } catch (SqlException $e) { throw (new Exception('Unable to delete due to query error', 0, $e)) ->addMoreInfo('model', $model) ->addMoreInfo('scope', $model->getModel(true)->scope()->toWords()); } - $model->hook(self::HOOK_AFTER_DELETE_QUERY, [$delete, $st]); + $model->hook(self::HOOK_AFTER_DELETE_QUERY, [$delete, $c]); } public function getFieldSqlExpression(Field $field, Expression $expression): Expression diff --git a/tests/ModelNestedSqlTest.php b/tests/ModelNestedSqlTest.php index 93cc5a0d2..24ccacfdd 100644 --- a/tests/ModelNestedSqlTest.php +++ b/tests/ModelNestedSqlTest.php @@ -9,7 +9,6 @@ use Atk4\Data\Persistence; use Atk4\Data\Persistence\Sql\Query; use Atk4\Data\Schema\TestCase; -use Doctrine\DBAL\Result as DbalResult; class ModelNestedSqlTest extends TestCase { @@ -171,7 +170,7 @@ public function testInsert(): void ['inner', Model::HOOK_BEFORE_SAVE, [false]], ['inner', Model::HOOK_BEFORE_INSERT, [['uid' => null, 'name' => 'Karl', 'y' => \DateTime::class]]], ['inner', Persistence\Sql::HOOK_BEFORE_INSERT_QUERY, [Query::class]], - ['inner', Persistence\Sql::HOOK_AFTER_INSERT_QUERY, [Query::class, DbalResult::class]], + ['inner', Persistence\Sql::HOOK_AFTER_INSERT_QUERY, [Query::class, 1]], ['inner', Model::HOOK_AFTER_INSERT, []], ['inner', Model::HOOK_AFTER_SAVE, [false]], ['inner', '<<<'], @@ -231,7 +230,7 @@ public function testUpdate(): void ['inner', Model::HOOK_BEFORE_SAVE, [true]], ['inner', Model::HOOK_BEFORE_UPDATE, [['name' => 'Susan']]], ['inner', Persistence\Sql::HOOK_BEFORE_UPDATE_QUERY, [Query::class]], - ['inner', Persistence\Sql::HOOK_AFTER_UPDATE_QUERY, [Query::class, DbalResult::class]], + ['inner', Persistence\Sql::HOOK_AFTER_UPDATE_QUERY, [Query::class, 1]], ['inner', Model::HOOK_AFTER_UPDATE, [['name' => 'Susan']]], ['inner', Model::HOOK_AFTER_SAVE, [true]], ['inner', '<<<'], @@ -266,7 +265,7 @@ public function testDelete(): void ['inner', '>>>'], ['inner', Model::HOOK_BEFORE_DELETE, []], ['inner', Persistence\Sql::HOOK_BEFORE_DELETE_QUERY, [Query::class]], - ['inner', Persistence\Sql::HOOK_AFTER_DELETE_QUERY, [Query::class, DbalResult::class]], + ['inner', Persistence\Sql::HOOK_AFTER_DELETE_QUERY, [Query::class, 1]], ['inner', Model::HOOK_AFTER_DELETE, []], ['inner', '<<<'], ['inner', Model::HOOK_BEFORE_UNLOAD, []], diff --git a/tests/RandomTest.php b/tests/RandomTest.php index e5bfb1824..a8a116911 100644 --- a/tests/RandomTest.php +++ b/tests/RandomTest.php @@ -10,6 +10,7 @@ use Atk4\Data\Model; use Atk4\Data\Persistence; use Atk4\Data\Persistence\Sql\Expression; +use Atk4\Data\Persistence\Sql\Query; use Atk4\Data\Schema\TestCase; use Doctrine\DBAL\Platforms\OraclePlatform; use Doctrine\DBAL\Platforms\PostgreSQLPlatform; @@ -266,13 +267,12 @@ public function testUpdateCondition(): void $m->addField('name'); $m = $m->load(2); - $m->onHook(Persistence\Sql::HOOK_AFTER_UPDATE_QUERY, static function ($m, $update, $st) { + $m->onHook(Persistence\Sql::HOOK_AFTER_UPDATE_QUERY, static function (Model $m, Query $update, int $c) { // we can use afterUpdate to make sure that record was updated - - if (!$st->rowCount()) { + if ($c === 0) { throw (new Exception('Update didn\'t affect any records')) ->addMoreInfo('query', $update->getDebugQuery()) - ->addMoreInfo('statement', $st) + ->addMoreInfo('affected_rows', $c) ->addMoreInfo('model', $m); } });