From a1f820e3162e90ec325b29549b8f6654cd015f18 Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Sun, 18 Oct 2020 19:28:32 -0700 Subject: [PATCH 01/12] Bump version to 2.12.0-DEV --- lib/Doctrine/DBAL/Version.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Doctrine/DBAL/Version.php b/lib/Doctrine/DBAL/Version.php index 26675dfdbd3..6c8480a92ac 100644 --- a/lib/Doctrine/DBAL/Version.php +++ b/lib/Doctrine/DBAL/Version.php @@ -17,7 +17,7 @@ class Version /** * Current Doctrine Version. */ - public const VERSION = '2.11.3-DEV'; + public const VERSION = '2.12.0-DEV'; /** * Compares a Doctrine version with the current one. From a3135e2381a5b294d2610d2d9683c2dfa7357a1f Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Thu, 15 Oct 2020 19:07:24 +0200 Subject: [PATCH 02/12] PHP 8 compatibility. --- .github/workflows/continuous-integration.yml | 12 ++ UPGRADE.md | 15 +++ composer.json | 2 +- composer.lock | 4 +- lib/Doctrine/DBAL/Driver/PDOConnection.php | 38 +++--- .../DBAL/Driver/PDOQueryImplementation.php | 39 ++++++ lib/Doctrine/DBAL/Driver/PDOStatement.php | 123 +++++++++--------- .../Driver/PDOStatementImplementations.php | 73 +++++++++++ lib/Doctrine/DBAL/Statement.php | 5 + phpcs.xml.dist | 13 ++ psalm.xml | 27 ++++ 11 files changed, 267 insertions(+), 84 deletions(-) create mode 100644 lib/Doctrine/DBAL/Driver/PDOQueryImplementation.php create mode 100644 lib/Doctrine/DBAL/Driver/PDOStatementImplementations.php diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 56725b50e3b..f7d5b250368 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -23,6 +23,7 @@ jobs: php-version: - "7.3" - "7.4" + - "8.0" deps: - "fixed" include: @@ -183,6 +184,9 @@ jobs: - "11" - "12" - "13" + include: + - php-version: "8.0" + postgres-version: "13" services: postgres: @@ -247,6 +251,13 @@ jobs: extension: - "mysqli" - "pdo_mysql" + include: + - php-version: "8.0" + mariadb-version: "10.5" + extension: "mysqli" + - php-version: "8.0" + mariadb-version: "10.5" + extension: "pdo_mysql" services: mariadb: @@ -304,6 +315,7 @@ jobs: matrix: php-version: - "7.4" + - "8.0" mysql-version: - "5.7" - "8.0" diff --git a/UPGRADE.md b/UPGRADE.md index e8c8997dc67..132e058d08d 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,3 +1,18 @@ +# Upgrade to 2.12 + +## PDO signature changes with php 8 + +In php 8.0, the method signatures of two PDO classes which are extended by DBAL have changed. This affects the following classes: + +* `Doctrine\DBAL\Driver\PDOConnection` +* `Doctrine\DBAL\Driver\PDOStatement` + +Code that extends either of the classes needs to be adjusted in order to function properly on php 8. The updated method signatures are: + +* `PDOConnection::query(?string $query = null, ?int $fetchMode = null, mixed ...$fetchModeArgs)` +* `PDOStatement::setFetchMode($mode, ...$args)` +* `PDOStatement::fetchAll($mode = null, ...$args)` + # Upgrade to 2.11 ## Deprecated `Abstraction\Result` diff --git a/composer.json b/composer.json index de722c523a5..2571ac4193a 100644 --- a/composer.json +++ b/composer.json @@ -32,7 +32,7 @@ {"name": "Jonathan Wage", "email": "jonwage@gmail.com"} ], "require": { - "php": "^7.3", + "php": "^7.3 || ^8", "ext-pdo": "*", "doctrine/cache": "^1.0", "doctrine/event-manager": "^1.0" diff --git a/composer.lock b/composer.lock index 55d6b6e3b18..22f01fdd8f7 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "b9b5b86a282f25dc5f24bc422885e9c0", + "content-hash": "0e4428b976a1e1835abdff64014ad723", "packages": [ { "name": "doctrine/cache", @@ -3922,7 +3922,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "^7.3", + "php": "^7.3 || ^8", "ext-pdo": "*" }, "platform-dev": [], diff --git a/lib/Doctrine/DBAL/Driver/PDOConnection.php b/lib/Doctrine/DBAL/Driver/PDOConnection.php index 8409952cb4e..9b532a36383 100644 --- a/lib/Doctrine/DBAL/Driver/PDOConnection.php +++ b/lib/Doctrine/DBAL/Driver/PDOConnection.php @@ -11,7 +11,6 @@ use PDOStatement; use function assert; -use function func_get_args; /** * PDO implementation of the Connection interface. @@ -21,6 +20,8 @@ */ class PDOConnection extends PDO implements ConnectionInterface, ServerInfoAwareConnection { + use PDOQueryImplementation; + /** * @internal The connection can be only instantiated by its driver. * @@ -83,25 +84,6 @@ public function prepare($sql, $driverOptions = []) } } - /** - * {@inheritdoc} - * - * @return PDOStatement - */ - public function query() - { - $args = func_get_args(); - - try { - $stmt = parent::query(...$args); - assert($stmt instanceof PDOStatement); - - return $stmt; - } catch (PDOException $exception) { - throw Exception::new($exception); - } - } - /** * {@inheritdoc} */ @@ -133,4 +115,20 @@ public function requiresQueryForServerVersion() { return false; } + + /** + * @param mixed ...$args + */ + private function doQuery(...$args): PDOStatement + { + try { + $stmt = parent::query(...$args); + } catch (PDOException $exception) { + throw Exception::new($exception); + } + + assert($stmt instanceof PDOStatement); + + return $stmt; + } } diff --git a/lib/Doctrine/DBAL/Driver/PDOQueryImplementation.php b/lib/Doctrine/DBAL/Driver/PDOQueryImplementation.php new file mode 100644 index 00000000000..be05bf64601 --- /dev/null +++ b/lib/Doctrine/DBAL/Driver/PDOQueryImplementation.php @@ -0,0 +1,39 @@ += 80000) { + /** + * @internal + */ + trait PDOQueryImplementation + { + /** + * @return PDOStatement + */ + public function query(?string $query = null, ?int $fetchMode = null, mixed ...$fetchModeArgs) + { + return $this->doQuery($query, $fetchMode, ...$fetchModeArgs); + } + } +} else { + /** + * @internal + */ + trait PDOQueryImplementation + { + /** + * @return PDOStatement + */ + public function query() + { + return $this->doQuery(...func_get_args()); + } + } +} diff --git a/lib/Doctrine/DBAL/Driver/PDOStatement.php b/lib/Doctrine/DBAL/Driver/PDOStatement.php index 4a244ab4617..86d6a15d49e 100644 --- a/lib/Doctrine/DBAL/Driver/PDOStatement.php +++ b/lib/Doctrine/DBAL/Driver/PDOStatement.php @@ -26,6 +26,8 @@ */ class PDOStatement extends \PDOStatement implements StatementInterface, Result { + use PDOStatementImplementations; + private const PARAM_TYPE_MAP = [ ParameterType::NULL => PDO::PARAM_NULL, ParameterType::INTEGER => PDO::PARAM_INT, @@ -54,34 +56,6 @@ protected function __construct() { } - /** - * {@inheritdoc} - * - * @deprecated Use one of the fetch- or iterate-related methods. - */ - public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) - { - $fetchMode = $this->convertFetchMode($fetchMode); - - // This thin wrapper is necessary to shield against the weird signature - // of PDOStatement::setFetchMode(): even if the second and third - // parameters are optional, PHP will not let us remove it from this - // declaration. - try { - if ($arg2 === null && $arg3 === null) { - return parent::setFetchMode($fetchMode); - } - - if ($arg3 === null) { - return parent::setFetchMode($fetchMode, $arg2); - } - - return parent::setFetchMode($fetchMode, $arg2, $arg3); - } catch (PDOException $exception) { - throw Exception::new($exception); - } - } - /** * {@inheritdoc} */ @@ -164,39 +138,6 @@ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEX } } - /** - * {@inheritdoc} - * - * @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchFirstColumn() instead. - */ - public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) - { - $args = func_get_args(); - - if (isset($args[0])) { - $args[0] = $this->convertFetchMode($args[0]); - } - - if ($fetchMode === null && $fetchArgument === null && $ctorArgs === null) { - $args = []; - } elseif ($fetchArgument === null && $ctorArgs === null) { - $args = [$fetchMode]; - } elseif ($ctorArgs === null) { - $args = [$fetchMode, $fetchArgument]; - } else { - $args = [$fetchMode, $fetchArgument, $ctorArgs]; - } - - try { - $data = parent::fetchAll(...$args); - assert(is_array($data)); - - return $data; - } catch (PDOException $exception) { - throw Exception::new($exception); - } - } - /** * {@inheritdoc} * @@ -264,6 +205,66 @@ public function free(): void parent::closeCursor(); } + /** + * @param mixed ...$args + */ + private function doSetFetchMode(int $fetchMode, ...$args): bool + { + $fetchMode = $this->convertFetchMode($fetchMode); + + // This thin wrapper is necessary to shield against the weird signature + // of PDOStatement::setFetchMode(): even if the second and third + // parameters are optional, PHP will not let us remove it from this + // declaration. + $slice = []; + + foreach ($args as $arg) { + if ($arg === null) { + break; + } + + $slice[] = $arg; + } + + try { + return parent::setFetchMode($fetchMode, ...$slice); + } catch (PDOException $exception) { + throw Exception::new($exception); + } + } + + /** + * @param mixed ...$args + * + * @return mixed[] + */ + private function doFetchAll(...$args): array + { + if (isset($args[0])) { + $args[0] = $this->convertFetchMode($args[0]); + } + + $slice = []; + + foreach ($args as $arg) { + if ($arg === null) { + break; + } + + $slice[] = $arg; + } + + try { + $data = parent::fetchAll(...$slice); + } catch (PDOException $exception) { + throw Exception::new($exception); + } + + assert(is_array($data)); + + return $data; + } + /** * Converts DBAL parameter type to PDO parameter type * diff --git a/lib/Doctrine/DBAL/Driver/PDOStatementImplementations.php b/lib/Doctrine/DBAL/Driver/PDOStatementImplementations.php new file mode 100644 index 00000000000..ff1a4af504d --- /dev/null +++ b/lib/Doctrine/DBAL/Driver/PDOStatementImplementations.php @@ -0,0 +1,73 @@ += 80000) { + /** + * @internal + */ + trait PDOStatementImplementations + { + /** + * @deprecated Use one of the fetch- or iterate-related methods. + * + * @param int $mode + * @param mixed ...$args + * + * @return bool + */ + public function setFetchMode($mode, ...$args) + { + return $this->doSetFetchMode($mode, ...$args); + } + + /** + * @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchFirstColumn() instead. + * + * @param int|null $mode + * @param mixed ...$args + * + * @return mixed[] + */ + public function fetchAll($mode = null, ...$args) + { + return $this->doFetchAll($mode, ...$args); + } + } +} else { + /** + * @internal + */ + trait PDOStatementImplementations + { + /** + * @deprecated Use one of the fetch- or iterate-related methods. + * + * @param int $fetchMode + * @param mixed $arg2 + * @param mixed $arg3 + */ + public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null): bool + { + return $this->doSetFetchMode(...func_get_args()); + } + + /** + * @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchFirstColumn() instead. + * + * @param int|null $fetchMode + * @param mixed $fetchArgument + * @param mixed $ctorArgs + * + * @return mixed[] + */ + public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) + { + return $this->doFetchAll(...func_get_args()); + } + } +} diff --git a/lib/Doctrine/DBAL/Statement.php b/lib/Doctrine/DBAL/Statement.php index ad5d29b9a5d..57843031eea 100644 --- a/lib/Doctrine/DBAL/Statement.php +++ b/lib/Doctrine/DBAL/Statement.php @@ -10,6 +10,7 @@ use Doctrine\DBAL\Types\Type; use IteratorAggregate; use PDO; +use PDOStatement; use Throwable; use Traversable; @@ -135,6 +136,10 @@ public function bindParam($param, &$variable, $type = ParameterType::STRING, $le $this->params[$param] = $variable; $this->types[$param] = $type; + if ($this->stmt instanceof PDOStatement) { + $length = $length ?? 0; + } + return $this->stmt->bindParam($param, $variable, $type, $length); } diff --git a/phpcs.xml.dist b/phpcs.xml.dist index 8c6b82da6b0..1d453f936b3 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -22,6 +22,7 @@ + @@ -31,6 +32,11 @@ + + */lib/Doctrine/DBAL/Driver/PDOQueryImplementation.php + */lib/Doctrine/DBAL/Driver/PDOStatementImplementations.php + + @@ -57,6 +63,8 @@ + */lib/Doctrine/DBAL/Driver/PDOQueryImplementation.php + */lib/Doctrine/DBAL/Driver/PDOStatementImplementations.php */tests/* @@ -115,6 +123,11 @@ lib/Doctrine/DBAL/Driver/PDOConnection.php + + */lib/Doctrine/DBAL/Driver/PDOConnection.php + */lib/Doctrine/DBAL/Driver/PDOStatement.php + + lib/Doctrine/DBAL/Driver/ExceptionConverterDriver.php diff --git a/psalm.xml b/psalm.xml index 999a5611126..4fcf11de05d 100644 --- a/psalm.xml +++ b/psalm.xml @@ -32,6 +32,13 @@ + + + + + + + + + @@ -89,6 +98,8 @@ Doctrine\DBAL\Driver\Connection --> + + @@ -99,6 +110,16 @@ + + + + + + + + + + + + + From 22e370aa4f0e3c8bb55dece5c438b46761e781b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Tue, 20 Oct 2020 21:12:12 +0200 Subject: [PATCH 10/12] Reduce number of build jobs Test the newest version, the oldest version, and versions for which we have version-specific code. This is based on platform classes that have a version number in their name. --- .github/workflows/continuous-integration.yml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 698435312a2..5c288313943 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -178,13 +178,7 @@ jobs: - "7.4" postgres-version: - "9.2" - - "9.3" - "9.4" - - "9.5" - - "9.6" - - "10" - - "11" - - "12" - "13" include: - php-version: "8.0" @@ -245,10 +239,7 @@ jobs: - "7.4" mariadb-version: - "10.0" - - "10.1" - "10.2" - - "10.3" - - "10.4" - "10.5" extension: - "mysqli" From e5160b2ab92bf0cbbd9f7d6bb27070edc90c41da Mon Sep 17 00:00:00 2001 From: Benjamin Morel Date: Wed, 21 Oct 2020 22:33:16 +0200 Subject: [PATCH 11/12] Configuration should not be internal --- lib/Doctrine/DBAL/Configuration.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Doctrine/DBAL/Configuration.php b/lib/Doctrine/DBAL/Configuration.php index 545b0ffb0b4..fce8a0b5393 100644 --- a/lib/Doctrine/DBAL/Configuration.php +++ b/lib/Doctrine/DBAL/Configuration.php @@ -11,8 +11,8 @@ /** * Configuration container for the Doctrine DBAL. * - * @internal When adding a new configuration option just write a getter/setter - * pair and add the option to the _attributes array with a proper default value. + * Internal note: When adding a new configuration option just write a getter/setter + * pair and add the option to the _attributes array with a proper default value. */ class Configuration { From c6d37b4c42aaa3c3ee175f05eca68056f4185646 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Thu, 22 Oct 2020 19:26:24 +0200 Subject: [PATCH 12/12] Release 2.12.0 --- lib/Doctrine/DBAL/Version.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Doctrine/DBAL/Version.php b/lib/Doctrine/DBAL/Version.php index 6c8480a92ac..bb8236fcbf9 100644 --- a/lib/Doctrine/DBAL/Version.php +++ b/lib/Doctrine/DBAL/Version.php @@ -17,7 +17,7 @@ class Version /** * Current Doctrine Version. */ - public const VERSION = '2.12.0-DEV'; + public const VERSION = '2.12.0'; /** * Compares a Doctrine version with the current one.