Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace DBAL EventManager with configuration middleware #1114

Merged
merged 4 commits into from
Aug 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions bootstrap-types.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@
use Atk4\Data\Type\LocalObjectType;
use Atk4\Data\Type\MoneyType;
use Atk4\Data\Type\Types;
use Doctrine\DBAL\Platforms\SqlitePlatform;
use Doctrine\DBAL\Types as DbalTypes;

// force Doctrine\DBAL\Platforms\SQLitePlatform class load as in DBAL 3.x it is named with a different case
// remove once DBAL 3.x support is dropped
new SqlitePlatform();

DbalTypes\Type::addType(Types::LOCAL_OBJECT, LocalObjectType::class);
DbalTypes\Type::addType(Types::MONEY, MoneyType::class);
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,13 @@
"require": {
"php": ">=7.4 <8.3",
"atk4/core": "dev-develop",
"doctrine/dbal": "~3.4.5 || ~3.5.1 || ~3.6.0",
"doctrine/dbal": "~3.5.1 || ~3.6.0",
"mvorisek/atk4-hintable": "~1.9.0"
},
"require-release": {
"php": ">=7.4 <8.3",
"atk4/core": "~5.0.0",
"doctrine/dbal": "~3.4.5 || ~3.5.1 || ~3.6.0",
"doctrine/dbal": "~3.5.1 || ~3.6.0",
"mvorisek/atk4-hintable": "~1.9.0"
},
"require-dev": {
Expand Down
12 changes: 4 additions & 8 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,11 @@ parameters:
path: '*'
count: 3

# TODO for DBAL 4.0 upgrade
# FC for DBAL 4.0, remove once DBAL 3.x support is dropped
-
message: '~^Instantiation of deprecated class Doctrine\\DBAL\\Event\\Listeners\\OracleSessionInit:\nUse \{@see \\Doctrine\\DBAL\\Driver\\OCI8\\Middleware\\InitializeSession\} instead\.$~'
path: 'src/Persistence/Sql/Oracle/Connection.php'
count: 1
-
message: '~^(Fetching deprecated class constant postConnect of class Doctrine\\DBAL\\Events\.|Fetching class constant postConnect of deprecated class Doctrine\\DBAL\\Events\.|Parameter \$args of method postConnect\(\) in anonymous class has typehint with deprecated class Doctrine\\DBAL\\Event\\ConnectionEventArgs\.)$~'
path: 'src/Persistence/Sql/Sqlite/Connection.php'
count: 3
message: '~^Class Doctrine\\DBAL\\Platforms\\SqlitePlatform referenced with incorrect case: Doctrine\\DBAL\\Platforms\\SQLitePlatform\.$~'
path: '*'
count: 33

# TODO these rules are generated, this ignores should be fixed in the code
# for src/Schema/TestCase.php
Expand Down
22 changes: 7 additions & 15 deletions src/Persistence/Sql/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
namespace Atk4\Data\Persistence\Sql;

use Atk4\Core\DiContainerTrait;
use Doctrine\Common\EventManager;
use Doctrine\DBAL\Configuration as DbalConfiguration;
use Doctrine\DBAL\Configuration;
use Doctrine\DBAL\Connection as DbalConnection;
use Doctrine\DBAL\ConnectionException as DbalConnectionException;
use Doctrine\DBAL\Driver as DbalDriver;
Expand Down Expand Up @@ -226,10 +225,10 @@ private static function getDriverNameFromDbalDriverConnection(DbalDriverConnecti
return null; // @phpstan-ignore-line
}

protected static function createDbalConfiguration(): DbalConfiguration
protected static function createDbalConfiguration(): Configuration
{
$dbalConfiguration = new DbalConfiguration();
$dbalConfiguration->setMiddlewares([
$configuration = new Configuration();
$configuration->setMiddlewares([
new class() implements DbalMiddleware {
public function wrap(DbalDriver $driver): DbalDriver
{
Expand All @@ -238,12 +237,7 @@ public function wrap(DbalDriver $driver): DbalDriver
},
]);

return $dbalConfiguration;
}

protected static function createDbalEventManager(): EventManager
{
return new EventManager();
return $configuration;
}

/**
Expand All @@ -260,8 +254,7 @@ protected static function connectFromDsn(array $dsn): DbalDriverConnection

$dbalConnection = DriverManager::getConnection(
$dsn, // @phpstan-ignore-line
(static::class)::createDbalConfiguration(),
(static::class)::createDbalEventManager()
(static::class)::createDbalConfiguration()
);

return $dbalConnection->getWrappedConnection(); // @phpstan-ignore-line https://github.com/doctrine/dbal/issues/5199
Expand All @@ -271,8 +264,7 @@ protected static function connectFromDbalDriverConnection(DbalDriverConnection $
{
$dbalConnection = DriverManager::getConnection(
['driver' => self::getDriverNameFromDbalDriverConnection($dbalDriverConnection)],
(static::class)::createDbalConfiguration(),
(static::class)::createDbalEventManager()
(static::class)::createDbalConfiguration()
);
\Closure::bind(function () use ($dbalConnection, $dbalDriverConnection): void {
$dbalConnection->_conn = $dbalDriverConnection;
Expand Down
8 changes: 4 additions & 4 deletions src/Persistence/Sql/DbalDriverMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Platforms\OraclePlatform;
use Doctrine\DBAL\Platforms\PostgreSQLPlatform;
use Doctrine\DBAL\Platforms\SqlitePlatform;
use Doctrine\DBAL\Platforms\SQLitePlatform;
use Doctrine\DBAL\Platforms\SQLServerPlatform;
use Doctrine\DBAL\Query as DbalQuery;
use Doctrine\DBAL\Schema\AbstractSchemaManager;
Expand All @@ -28,8 +28,8 @@ class DbalDriverMiddleware extends AbstractDriverMiddleware
{
protected function replaceDatabasePlatform(AbstractPlatform $platform): AbstractPlatform
{
if ($platform instanceof SqlitePlatform) {
$platform = new class() extends SqlitePlatform {
if ($platform instanceof SQLitePlatform) {
$platform = new class() extends SQLitePlatform {
use Sqlite\PlatformTrait;
};
} elseif ($platform instanceof PostgreSQLPlatform) {
Expand Down Expand Up @@ -64,7 +64,7 @@ public function createDatabasePlatformForVersion($version): AbstractPlatform
*/
public function getSchemaManager(DbalConnection $connection, AbstractPlatform $platform): AbstractSchemaManager
{
if ($platform instanceof SqlitePlatform) {
if ($platform instanceof SQLitePlatform) {
return new class($connection, $platform) extends SqliteSchemaManager { // @phpstan-ignore-line
use Sqlite\SchemaManagerTrait;
};
Expand Down
6 changes: 3 additions & 3 deletions src/Persistence/Sql/Expression.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
use Doctrine\DBAL\ParameterType;
use Doctrine\DBAL\Platforms\OraclePlatform;
use Doctrine\DBAL\Platforms\PostgreSQLPlatform;
use Doctrine\DBAL\Platforms\SqlitePlatform;
use Doctrine\DBAL\Platforms\SQLitePlatform;
use Doctrine\DBAL\Platforms\SQLServerPlatform;
use Doctrine\DBAL\Result as DbalResult;

Expand Down Expand Up @@ -287,9 +287,9 @@ protected function escapeStringLiteral(string $value): string
$sqlLeft = 'CAST(' . $sqlLeft . ' AS NVARCHAR(MAX))';
}

return ($platform instanceof SqlitePlatform ? '(' : 'CONCAT(')
return ($platform instanceof SQLitePlatform ? '(' : 'CONCAT(')
. $sqlLeft
. ($platform instanceof SqlitePlatform ? ' || ' : ', ')
. ($platform instanceof SQLitePlatform ? ' || ' : ', ')
. $buildConcatSqlFx($partsRight)
. ')';
}
Expand Down
65 changes: 47 additions & 18 deletions src/Persistence/Sql/Oracle/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,63 @@
namespace Atk4\Data\Persistence\Sql\Oracle;

use Atk4\Data\Persistence\Sql\Connection as BaseConnection;
use Doctrine\Common\EventManager;
use Doctrine\DBAL\Event\Listeners\OracleSessionInit;
use Doctrine\DBAL\Configuration;
use Doctrine\DBAL\Driver;
use Doctrine\DBAL\Driver\Connection as DriverConnection;
use Doctrine\DBAL\Driver\Middleware;
use Doctrine\DBAL\Driver\Middleware\AbstractDriverMiddleware;

class Connection extends BaseConnection
{
protected string $expressionClass = Expression::class;
protected string $queryClass = Query::class;

protected static function createDbalEventManager(): EventManager
protected static function createDbalConfiguration(): Configuration
{
$evm = parent::createDbalEventManager();
$configuration = parent::createDbalConfiguration();

// setup connection globalization to use standard datetime format incl. microseconds support
// and make comparison of character types case insensitive
$dateFormat = 'YYYY-MM-DD';
$timeFormat = 'HH24:MI:SS.FF6';
$tzFormat = 'TZH:TZM';
$evm->addEventSubscriber(new OracleSessionInit([
'NLS_DATE_FORMAT' => $dateFormat,
'NLS_TIME_FORMAT' => $timeFormat,
'NLS_TIMESTAMP_FORMAT' => $dateFormat . ' ' . $timeFormat,
'NLS_TIME_TZ_FORMAT' => $timeFormat . ' ' . $tzFormat,
'NLS_TIMESTAMP_TZ_FORMAT' => $dateFormat . ' ' . $timeFormat . ' ' . $tzFormat,
'NLS_COMP' => 'LINGUISTIC',
'NLS_SORT' => 'BINARY_CI',
]));

return $evm;
// based on https://github.com/doctrine/dbal/blob/3.6.5/src/Driver/OCI8/Middleware/InitializeSession.php
$initializeSessionMiddleware = new class() implements Middleware {
public function wrap(Driver $driver): Driver
{
return new class($driver) extends AbstractDriverMiddleware {
public function connect(
#[\SensitiveParameter]
array $params
): DriverConnection {
$connection = parent::connect($params);

$dateFormat = 'YYYY-MM-DD';
$timeFormat = 'HH24:MI:SS.FF6';
$tzFormat = 'TZH:TZM';

$vars = [];
foreach ([
'NLS_DATE_FORMAT' => $dateFormat,
'NLS_TIME_FORMAT' => $timeFormat,
'NLS_TIMESTAMP_FORMAT' => $dateFormat . ' ' . $timeFormat,
'NLS_TIME_TZ_FORMAT' => $timeFormat . ' ' . $tzFormat,
'NLS_TIMESTAMP_TZ_FORMAT' => $dateFormat . ' ' . $timeFormat . ' ' . $tzFormat,
'NLS_NUMERIC_CHARACTERS' => '.,',
'NLS_COMP' => 'LINGUISTIC',
'NLS_SORT' => 'BINARY_CI',
] as $k => $v) {
$vars[] = $k . " = '" . $v . "'";
}

$connection->exec('ALTER SESSION SET ' . implode(' ', $vars));

return $connection;
}
};
}
};

$configuration->setMiddlewares([...$configuration->getMiddlewares(), $initializeSessionMiddleware]);

return $configuration;
}

public function lastInsertId(string $sequence = null): string
Expand Down
25 changes: 6 additions & 19 deletions src/Persistence/Sql/Sqlite/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,20 @@
namespace Atk4\Data\Persistence\Sql\Sqlite;

use Atk4\Data\Persistence\Sql\Connection as BaseConnection;
use Doctrine\Common\EventManager;
use Doctrine\Common\EventSubscriber;
use Doctrine\DBAL\Event\ConnectionEventArgs;
use Doctrine\DBAL\Events;
use Doctrine\DBAL\Configuration;
use Doctrine\DBAL\Driver\AbstractSQLiteDriver\Middleware\EnableForeignKeys;

class Connection extends BaseConnection
{
protected string $expressionClass = Expression::class;
protected string $queryClass = Query::class;

protected static function createDbalEventManager(): EventManager
protected static function createDbalConfiguration(): Configuration
{
$evm = parent::createDbalEventManager();
$configuration = parent::createDbalConfiguration();

// setup connection to always check foreign keys
$evm->addEventSubscriber(new class() implements EventSubscriber {
public function getSubscribedEvents(): array
{
return [Events::postConnect];
}
$configuration->setMiddlewares([...$configuration->getMiddlewares(), new EnableForeignKeys()]);

public function postConnect(ConnectionEventArgs $args): void
{
$args->getConnection()->executeStatement('PRAGMA foreign_keys = 1');
}
});

return $evm;
return $configuration;
}
}
4 changes: 2 additions & 2 deletions src/Schema/Migrator.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
use Doctrine\DBAL\Platforms\MySQLPlatform;
use Doctrine\DBAL\Platforms\OraclePlatform;
use Doctrine\DBAL\Platforms\PostgreSQLPlatform;
use Doctrine\DBAL\Platforms\SqlitePlatform;
use Doctrine\DBAL\Platforms\SQLitePlatform;
use Doctrine\DBAL\Platforms\SQLServerPlatform;
use Doctrine\DBAL\Schema\AbstractAsset;
use Doctrine\DBAL\Schema\AbstractSchemaManager;
Expand Down Expand Up @@ -253,7 +253,7 @@ public function field(string $fieldName, array $options = []): self
}

if (in_array($type, ['string', 'text'], true)) {
if ($this->getDatabasePlatform() instanceof SqlitePlatform) {
if ($this->getDatabasePlatform() instanceof SQLitePlatform) {
$column->setPlatformOption('collation', 'NOCASE');
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/Schema/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
use Doctrine\DBAL\ParameterType;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Platforms\OraclePlatform;
use Doctrine\DBAL\Platforms\SqlitePlatform;
use Doctrine\DBAL\Platforms\SQLitePlatform;
use Doctrine\DBAL\Platforms\SQLServerPlatform;

abstract class TestCase extends BaseTestCase
Expand Down Expand Up @@ -114,7 +114,7 @@ function ($matches) use ($platform) {
$sql
);

if ($platform instanceof SqlitePlatform && $convertedSql !== $sql) {
if ($platform instanceof SQLitePlatform && $convertedSql !== $sql) {
self::assertSame($sql, $convertedSql);
}

Expand Down
12 changes: 6 additions & 6 deletions tests/ExpressionSqlTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use Atk4\Data\Model;
use Atk4\Data\Schema\TestCase;
use Doctrine\DBAL\Platforms\OraclePlatform;
use Doctrine\DBAL\Platforms\SqlitePlatform;
use Doctrine\DBAL\Platforms\SQLitePlatform;

class ExpressionSqlTest extends TestCase
{
Expand All @@ -33,7 +33,7 @@ public function testBasic(): void
$i->addField('total_vat', ['type' => 'float']);
$i->addExpression('total_gross', ['expr' => '[total_net] + [total_vat]', 'type' => 'float']);

if ($this->getDatabasePlatform() instanceof SqlitePlatform) {
if ($this->getDatabasePlatform() instanceof SQLitePlatform) {
self::assertSame(
'select `id`, `total_net`, `total_vat`, (`total_net` + `total_vat`) `total_gross` from `invoice`',
$i->action('select')->render()[0]
Expand All @@ -50,7 +50,7 @@ public function testBasic(): void

$i->addExpression('double_total_gross', ['expr' => '[total_gross] * 2', 'type' => 'float']);

if ($this->getDatabasePlatform() instanceof SqlitePlatform) {
if ($this->getDatabasePlatform() instanceof SQLitePlatform) {
self::assertSame(
'select `id`, `total_net`, `total_vat`, (`total_net` + `total_vat`) `total_gross`, ((`total_net` + `total_vat`) * 2) `double_total_gross` from `invoice`',
$i->action('select')->render()[0]
Expand All @@ -77,7 +77,7 @@ public function testBasicCallback(): void
return '[total_net] + [total_vat]';
}, 'type' => 'float']);

if ($this->getDatabasePlatform() instanceof SqlitePlatform) {
if ($this->getDatabasePlatform() instanceof SQLitePlatform) {
self::assertSame(
'select `id`, `total_net`, `total_vat`, (`total_net` + `total_vat`) `total_gross` from `invoice`',
$i->action('select')->render()[0]
Expand Down Expand Up @@ -107,7 +107,7 @@ public function testQuery(): void
$i->addField('total_vat', ['type' => 'float']);
$i->addExpression('sum_net', ['expr' => $i->action('fx', ['sum', 'total_net']), ['type' => 'integer']]);

if ($this->getDatabasePlatform() instanceof SqlitePlatform) {
if ($this->getDatabasePlatform() instanceof SQLitePlatform) {
self::assertSame(
'select `id`, `total_net`, `total_vat`, (select sum(`total_net`) from `invoice`) `sum_net` from `invoice`',
$i->action('select')->render()[0]
Expand Down Expand Up @@ -141,7 +141,7 @@ public function testExpressions(): void
$m->addField('surname');
$m->addField('cached_name');

if ($this->getDatabasePlatform() instanceof SqlitePlatform || $this->getDatabasePlatform() instanceof OraclePlatform) {
if ($this->getDatabasePlatform() instanceof SQLitePlatform || $this->getDatabasePlatform() instanceof OraclePlatform) {
$concatExpr = '[name] || \' \' || [surname]';
} else {
$concatExpr = 'CONCAT([name], \' \', [surname])';
Expand Down
Loading