From 01e837f22b774dbedfcc0b087bf5377ce83dbab0 Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Fri, 21 Oct 2022 12:00:15 -0700 Subject: [PATCH] Deprecate extension via connection events --- UPGRADE.md | 10 ++++ ci/github/phpunit/oci8.xml | 1 - ci/github/phpunit/pdo_oci.xml | 1 - ci/github/phpunit/pdo_sqlite.xml | 1 - ci/github/phpunit/sqlite3.xml | 1 - docs/en/reference/events.rst | 30 ----------- psalm.xml.dist | 10 ++++ src/Connection.php | 7 +++ .../PrimaryReadReplicaConnection.php | 8 +++ .../Middleware/EnableForeignKeys.php | 28 ++++++++++ .../OCI8/Middleware/InitializeSession.php | 36 +++++++++++++ src/Event/ConnectionEventArgs.php | 2 + src/Event/Listeners/OracleSessionInit.php | 2 + src/Event/Listeners/SQLSessionInit.php | 2 + src/Event/Listeners/SQLiteSessionInit.php | 1 + src/Events.php | 1 + tests/TestUtil.php | 54 ++++++++----------- 17 files changed, 130 insertions(+), 65 deletions(-) create mode 100644 src/Driver/AbstractSQLiteDriver/Middleware/EnableForeignKeys.php create mode 100644 src/Driver/OCI8/Middleware/InitializeSession.php diff --git a/UPGRADE.md b/UPGRADE.md index 8c726635218..c14a776c921 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -8,6 +8,16 @@ awareness about deprecated code. # Upgrade to 3.5 +## Deprecated extension via connection events + +Subscription to the `postConnect` event has been deprecated. Use one of the following replacements for the standard +event listeners or implement a custom middleware instead. + +The following `postConnect` event listeners have been deprecated: +1. `OracleSessionInit`. Use `Doctrine\DBAL\Driver\OCI8\Middleware\InitializeSession`. +2. `SQLiteSessionInit`. Use `Doctrine\DBAL\Driver\AbstractSQLiteDriver\Middleware\EnableForeignKeys`. +3. `SQLSessionInit`. Implement a custom middleware. + ## Deprecated extension via transaction events Subscription to the following events has been deprecated: diff --git a/ci/github/phpunit/oci8.xml b/ci/github/phpunit/oci8.xml index fcb0d5423ff..d8e1d99fbf7 100644 --- a/ci/github/phpunit/oci8.xml +++ b/ci/github/phpunit/oci8.xml @@ -17,7 +17,6 @@ - diff --git a/ci/github/phpunit/pdo_oci.xml b/ci/github/phpunit/pdo_oci.xml index 00daa7f2cd9..ef1e272e5e0 100644 --- a/ci/github/phpunit/pdo_oci.xml +++ b/ci/github/phpunit/pdo_oci.xml @@ -17,7 +17,6 @@ - diff --git a/ci/github/phpunit/pdo_sqlite.xml b/ci/github/phpunit/pdo_sqlite.xml index 2ff89cc6f10..ad374f5d3df 100644 --- a/ci/github/phpunit/pdo_sqlite.xml +++ b/ci/github/phpunit/pdo_sqlite.xml @@ -13,7 +13,6 @@ - diff --git a/ci/github/phpunit/sqlite3.xml b/ci/github/phpunit/sqlite3.xml index 3c58120444c..09a27e9c223 100644 --- a/ci/github/phpunit/sqlite3.xml +++ b/ci/github/phpunit/sqlite3.xml @@ -13,7 +13,6 @@ - diff --git a/docs/en/reference/events.rst b/docs/en/reference/events.rst index bbc8616dfd4..c6ba5f99f98 100644 --- a/docs/en/reference/events.rst +++ b/docs/en/reference/events.rst @@ -7,36 +7,6 @@ Both ``Doctrine\DBAL\DriverManager`` and events inside the DBAL layer that are triggered for the user to listen to. -PostConnect Event ------------------ - -``Doctrine\DBAL\Events::postConnect`` is triggered right after the -connection to the database is established. It allows to specify any -relevant connection specific options and gives access to the -``Doctrine\DBAL\Connection`` instance that is responsible for the -connection management via an instance of -``Doctrine\DBAL\Event\ConnectionEventArgs`` event arguments -instance. - -Doctrine ships with one implementation for the "PostConnect" event: - -- ``Doctrine\DBAL\Event\Listeners\OracleSessionInit`` allows to - specify any number of Oracle Session related environment variables - that are set right after the connection is established. - -You can register events by subscribing them to the ``EventManager`` -instance passed to the Connection factory: - -.. code-block:: php - - addEventSubscriber(new OracleSessionInit([ - 'NLS_TIME_FORMAT' => 'HH24:MI:SS', - ])); - - $conn = DriverManager::getConnection($connectionParams, null, $evm); - Schema Events ------------- diff --git a/psalm.xml.dist b/psalm.xml.dist index 7a6cf943691..901f7817635 100644 --- a/psalm.xml.dist +++ b/psalm.xml.dist @@ -118,6 +118,10 @@ + + + + @@ -142,9 +146,15 @@ TODO: remove in 4.0.0 --> + + + + + + diff --git a/src/Connection.php b/src/Connection.php index 843f543c7b5..0bf80ab6acd 100644 --- a/src/Connection.php +++ b/src/Connection.php @@ -340,6 +340,13 @@ public function connect() } if ($this->_eventManager->hasListeners(Events::postConnect)) { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/issues/5784', + 'Subscribing to %s events is deprecated. Implement a middleware instead.', + Events::postConnect, + ); + $eventArgs = new Event\ConnectionEventArgs($this); $this->_eventManager->dispatchEvent(Events::postConnect, $eventArgs); } diff --git a/src/Connections/PrimaryReadReplicaConnection.php b/src/Connections/PrimaryReadReplicaConnection.php index 1591ae1fb99..c65eb8ae97a 100644 --- a/src/Connections/PrimaryReadReplicaConnection.php +++ b/src/Connections/PrimaryReadReplicaConnection.php @@ -13,6 +13,7 @@ use Doctrine\DBAL\Events; use Doctrine\DBAL\Exception; use Doctrine\DBAL\Statement; +use Doctrine\Deprecations\Deprecation; use InvalidArgumentException; use function array_rand; @@ -199,6 +200,13 @@ protected function performConnect(?string $connectionName = null): bool } if ($this->_eventManager->hasListeners(Events::postConnect)) { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/issues/5784', + 'Subscribing to %s events is deprecated. Implement a middleware instead.', + Events::postConnect, + ); + $eventArgs = new ConnectionEventArgs($this); $this->_eventManager->dispatchEvent(Events::postConnect, $eventArgs); } diff --git a/src/Driver/AbstractSQLiteDriver/Middleware/EnableForeignKeys.php b/src/Driver/AbstractSQLiteDriver/Middleware/EnableForeignKeys.php new file mode 100644 index 00000000000..a5eee748436 --- /dev/null +++ b/src/Driver/AbstractSQLiteDriver/Middleware/EnableForeignKeys.php @@ -0,0 +1,28 @@ +exec('PRAGMA foreign_keys=ON'); + + return $connection; + } + }; + } +} diff --git a/src/Driver/OCI8/Middleware/InitializeSession.php b/src/Driver/OCI8/Middleware/InitializeSession.php new file mode 100644 index 00000000000..30896a23c6b --- /dev/null +++ b/src/Driver/OCI8/Middleware/InitializeSession.php @@ -0,0 +1,36 @@ +exec( + 'ALTER SESSION SET' + . " NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS'" + . " NLS_TIME_FORMAT = 'HH24:MI:SS'" + . " NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS'" + . " NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS'" + . " NLS_TIMESTAMP_TZ_FORMAT = 'YYYY-MM-DD HH24:MI:SS TZH:TZM'" + . " NLS_NUMERIC_CHARACTERS = '.,'", + ); + + return $connection; + } + }; + } +} diff --git a/src/Event/ConnectionEventArgs.php b/src/Event/ConnectionEventArgs.php index aa52ce89db3..9a69c25415e 100644 --- a/src/Event/ConnectionEventArgs.php +++ b/src/Event/ConnectionEventArgs.php @@ -7,6 +7,8 @@ /** * Event Arguments used when a Driver connection is established inside Doctrine\DBAL\Connection. + * + * @deprecated */ class ConnectionEventArgs extends EventArgs { diff --git a/src/Event/Listeners/OracleSessionInit.php b/src/Event/Listeners/OracleSessionInit.php index 6949f6e544c..6256cdb5b49 100644 --- a/src/Event/Listeners/OracleSessionInit.php +++ b/src/Event/Listeners/OracleSessionInit.php @@ -23,6 +23,8 @@ * NLS_DATE_FORMAT="YYYY-MM-DD HH24:MI:SS" * NLS_TIMESTAMP_FORMAT="YYYY-MM-DD HH24:MI:SS" * NLS_TIMESTAMP_TZ_FORMAT="YYYY-MM-DD HH24:MI:SS TZH:TZM" + * + * @deprecated Use {@see \Doctrine\DBAL\Driver\OCI8\Middleware\InitializeSession} instead. */ class OracleSessionInit implements EventSubscriber { diff --git a/src/Event/Listeners/SQLSessionInit.php b/src/Event/Listeners/SQLSessionInit.php index 09e0b19ce2f..0f77e9ffc5e 100644 --- a/src/Event/Listeners/SQLSessionInit.php +++ b/src/Event/Listeners/SQLSessionInit.php @@ -9,6 +9,8 @@ /** * Session init listener for executing a single SQL statement right after a connection is opened. + * + * @deprecated Implement a middleware instead. */ class SQLSessionInit implements EventSubscriber { diff --git a/src/Event/Listeners/SQLiteSessionInit.php b/src/Event/Listeners/SQLiteSessionInit.php index 3c31dc7f012..f2ee05a32d3 100644 --- a/src/Event/Listeners/SQLiteSessionInit.php +++ b/src/Event/Listeners/SQLiteSessionInit.php @@ -7,6 +7,7 @@ use Doctrine\DBAL\Events; use Doctrine\DBAL\Exception; +/** @deprecated Use {@see \Doctrine\DBAL\Driver\AbstractSQLiteDriver\Middleware\EnableForeignKeys} instead. */ class SQLiteSessionInit implements EventSubscriber { /** diff --git a/src/Events.php b/src/Events.php index 00ef9a86a00..0646029dd5d 100644 --- a/src/Events.php +++ b/src/Events.php @@ -18,6 +18,7 @@ private function __construct() { } + /** @deprecated */ public const postConnect = 'postConnect'; /** @deprecated */ diff --git a/tests/TestUtil.php b/tests/TestUtil.php index c6dd4b33289..c88a347f4ee 100644 --- a/tests/TestUtil.php +++ b/tests/TestUtil.php @@ -2,29 +2,26 @@ namespace Doctrine\DBAL\Tests; -use Doctrine\Common\EventSubscriber; +use Doctrine\DBAL\Configuration; use Doctrine\DBAL\Connection; +use Doctrine\DBAL\Driver\AbstractSQLiteDriver\Middleware\EnableForeignKeys; +use Doctrine\DBAL\Driver\OCI8\Middleware\InitializeSession; use Doctrine\DBAL\DriverManager; -use Doctrine\DBAL\Event\Listeners\SQLiteSessionInit; use Doctrine\DBAL\Exception\DatabaseObjectNotFoundException; use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Platforms\DB2Platform; use Doctrine\DBAL\Platforms\OraclePlatform; use Doctrine\DBAL\Platforms\SqlitePlatform; -use InvalidArgumentException; use PHPUnit\Framework\Assert; use function array_keys; use function array_map; use function array_values; -use function explode; use function extension_loaded; use function file_exists; use function implode; use function in_array; use function is_string; -use function is_subclass_of; -use function sprintf; use function strlen; use function strpos; use function substr; @@ -66,13 +63,10 @@ public static function getConnection(): Connection $params = self::getConnectionParams(); - $connection = DriverManager::getConnection($params); - - if (isset($params['event_subscribers'])) { - self::addDbEventSubscribers($connection, explode(',', $params['event_subscribers'])); - } - - return $connection; + return DriverManager::getConnection( + $params, + self::createConfiguration($params['driver']), + ); } /** @return mixed[] */ @@ -141,28 +135,27 @@ private static function getFallbackConnectionParams(): array } return [ - 'driver' => 'pdo_sqlite', - 'memory' => true, - 'event_subscribers' => SQLiteSessionInit::class, + 'driver' => 'pdo_sqlite', + 'memory' => true, ]; } - /** @param list $subscribers */ - private static function addDbEventSubscribers(Connection $connection, array $subscribers): void + private static function createConfiguration(string $driver): Configuration { - $evm = $connection->getEventManager(); - - foreach ($subscribers as $subscriber) { - if (! is_subclass_of($subscriber, EventSubscriber::class)) { - throw new InvalidArgumentException(sprintf( - '"%s" is not a valid event subscriber. It must be a class that implements "%s".', - $subscriber, - EventSubscriber::class, - )); - } - - $evm->addEventSubscriber(new $subscriber()); + $configuration = new Configuration(); + + switch ($driver) { + case 'pdo_oci': + case 'oci8': + $configuration->setMiddlewares([new InitializeSession()]); + break; + case 'pdo_sqlite': + case 'sqlite3': + $configuration->setMiddlewares([new EnableForeignKeys()]); + break; } + + return $configuration; } /** @return mixed[] */ @@ -211,7 +204,6 @@ private static function mapConnectionParameters(array $configuration, string $pr 'unix_socket', 'path', 'charset', - 'event_subscribers', ] as $parameter ) { if (! isset($configuration[$prefix . $parameter])) {