Skip to content

Commit

Permalink
Deprecate extension via connection events
Browse files Browse the repository at this point in the history
  • Loading branch information
morozov committed Oct 22, 2022
1 parent 946db1d commit 01e837f
Show file tree
Hide file tree
Showing 17 changed files with 130 additions and 65 deletions.
10 changes: 10 additions & 0 deletions UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
1 change: 0 additions & 1 deletion ci/github/phpunit/oci8.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
<var name="db_password" value="oracle"/>
<var name="db_dbname" value="XE"/>
<var name="db_charset" value="AL32UTF8" />
<var name="db_event_subscribers" value="Doctrine\DBAL\Event\Listeners\OracleSessionInit"/>

<var name="tmpdb_driver" value="oci8"/>
<var name="tmpdb_host" value="localhost"/>
Expand Down
1 change: 0 additions & 1 deletion ci/github/phpunit/pdo_oci.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
<var name="db_password" value="oracle"/>
<var name="db_dbname" value="XE"/>
<var name="db_charset" value="AL32UTF8" />
<var name="db_event_subscribers" value="Doctrine\DBAL\Event\Listeners\OracleSessionInit"/>

<var name="tmpdb_driver" value="pdo_oci"/>
<var name="tmpdb_host" value="localhost"/>
Expand Down
1 change: 0 additions & 1 deletion ci/github/phpunit/pdo_sqlite.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

<var name="db_driver" value="pdo_sqlite"/>
<var name="db_memory" value="true"/>
<var name="db_event_subscribers" value="Doctrine\DBAL\Event\Listeners\SQLiteSessionInit"/>
</php>

<testsuites>
Expand Down
1 change: 0 additions & 1 deletion ci/github/phpunit/sqlite3.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

<var name="db_driver" value="sqlite3"/>
<var name="db_memory" value="true"/>
<var name="db_event_subscribers" value="Doctrine\DBAL\Event\Listeners\SQLiteSessionInit"/>
</php>

<testsuites>
Expand Down
30 changes: 0 additions & 30 deletions docs/en/reference/events.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
<?php
$evm = new EventManager();
$evm->addEventSubscriber(new OracleSessionInit([
'NLS_TIME_FORMAT' => 'HH24:MI:SS',
]));
$conn = DriverManager::getConnection($connectionParams, null, $evm);
Schema Events
-------------

Expand Down
10 changes: 10 additions & 0 deletions psalm.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@
<referencedClass name="Doctrine\DBAL\Event\TransactionBeginEventArgs"/>
<referencedClass name="Doctrine\DBAL\Event\TransactionCommitEventArgs"/>
<referencedClass name="Doctrine\DBAL\Event\TransactionRollBackEventArgs"/>
<referencedClass name="Doctrine\DBAL\Event\ConnectionEventArgs"/>
<referencedClass name="Doctrine\DBAL\Event\Listeners\OracleSessionInit"/>
<referencedClass name="Doctrine\DBAL\Event\Listeners\SQLSessionInit"/>
<referencedClass name="Doctrine\DBAL\Event\Listeners\SQLiteSessionInit"/>
</errorLevel>
</DeprecatedClass>
<DeprecatedConstant>
Expand All @@ -142,9 +146,15 @@
TODO: remove in 4.0.0
-->
<file name="src/Connection.php"/>
<file name="src/Connections/PrimaryReadReplicaConnection.php"/>
<file name="src/Event/Listeners/OracleSessionInit.php"/>
<file name="src/Event/Listeners/SQLSessionInit.php"/>
<file name="src/Event/Listeners/SQLiteSessionInit.php"/>
<file name="src/Platforms/AbstractPlatform.php"/>
<file name="src/Schema/AbstractSchemaManager.php"/>
<file name="tests/ConnectionTest.php"/>
<file name="tests/Events/OracleSessionInitTest.php"/>
<file name="tests/Events/SQLSessionInitTest.php"/>
<file name="tests/Functional/Schema/SchemaManagerFunctionalTestCase.php"/>
<file name="tests/Platforms/AbstractPlatformTestCase.php"/>
</errorLevel>
Expand Down
7 changes: 7 additions & 0 deletions src/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
8 changes: 8 additions & 0 deletions src/Connections/PrimaryReadReplicaConnection.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
Expand Down
28 changes: 28 additions & 0 deletions src/Driver/AbstractSQLiteDriver/Middleware/EnableForeignKeys.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

namespace Doctrine\DBAL\Driver\AbstractSQLiteDriver\Middleware;

use Doctrine\DBAL\Driver;
use Doctrine\DBAL\Driver\Connection;
use Doctrine\DBAL\Driver\Middleware;
use Doctrine\DBAL\Driver\Middleware\AbstractDriverMiddleware;

class EnableForeignKeys implements Middleware
{
public function wrap(Driver $driver): Driver
{
return new class ($driver) extends AbstractDriverMiddleware {
/**
* {@inheritDoc}
*/
public function connect(array $params): Connection
{
$connection = parent::connect($params);

$connection->exec('PRAGMA foreign_keys=ON');

return $connection;
}
};
}
}
36 changes: 36 additions & 0 deletions src/Driver/OCI8/Middleware/InitializeSession.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

namespace Doctrine\DBAL\Driver\OCI8\Middleware;

use Doctrine\DBAL\Driver;
use Doctrine\DBAL\Driver\Connection;
use Doctrine\DBAL\Driver\Middleware;
use Doctrine\DBAL\Driver\Middleware\AbstractDriverMiddleware;

class InitializeSession implements Middleware
{
public function wrap(Driver $driver): Driver
{
return new class ($driver) extends AbstractDriverMiddleware {
/**
* {@inheritDoc}
*/
public function connect(array $params): Connection
{
$connection = parent::connect($params);

$connection->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;
}
};
}
}
2 changes: 2 additions & 0 deletions src/Event/ConnectionEventArgs.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

/**
* Event Arguments used when a Driver connection is established inside Doctrine\DBAL\Connection.
*
* @deprecated
*/
class ConnectionEventArgs extends EventArgs
{
Expand Down
2 changes: 2 additions & 0 deletions src/Event/Listeners/OracleSessionInit.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down
2 changes: 2 additions & 0 deletions src/Event/Listeners/SQLSessionInit.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down
1 change: 1 addition & 0 deletions src/Event/Listeners/SQLiteSessionInit.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
/**
Expand Down
1 change: 1 addition & 0 deletions src/Events.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ private function __construct()
{
}

/** @deprecated */
public const postConnect = 'postConnect';

/** @deprecated */
Expand Down
54 changes: 23 additions & 31 deletions tests/TestUtil.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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[] */
Expand Down Expand Up @@ -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<string> $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[] */
Expand Down Expand Up @@ -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])) {
Expand Down

0 comments on commit 01e837f

Please sign in to comment.