From cdbec7d2e8140c7d0a8822745bb026e557068c1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Vo=C5=99=C3=AD=C5=A1ek?= Date: Tue, 15 Aug 2023 21:46:24 +0200 Subject: [PATCH 1/4] use SQLitePlatform class name for FC --- bootstrap-types.php | 4 ++++ phpstan.neon.dist | 4 ++++ src/Persistence/Sql/DbalDriverMiddleware.php | 8 ++++---- src/Persistence/Sql/Expression.php | 6 +++--- src/Schema/Migrator.php | 4 ++-- src/Schema/TestCase.php | 4 ++-- tests/ExpressionSqlTest.php | 12 ++++++------ tests/ModelAggregateTest.php | 8 ++++---- tests/Persistence/Sql/ConnectionTest.php | 6 +++--- tests/RandomTest.php | 4 ++-- tests/Schema/TestCaseTest.php | 4 ++-- tests/ScopeTest.php | 6 +++--- tests/TypecastingTest.php | 4 ++-- 13 files changed, 41 insertions(+), 33 deletions(-) diff --git a/bootstrap-types.php b/bootstrap-types.php index 18d9ecbc4..12ad2ea30 100644 --- a/bootstrap-types.php +++ b/bootstrap-types.php @@ -7,7 +7,11 @@ 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 named as Doctrine\DBAL\Platforms\SqlitePlatform +new SqlitePlatform(); + DbalTypes\Type::addType(Types::LOCAL_OBJECT, LocalObjectType::class); DbalTypes\Type::addType(Types::MONEY, MoneyType::class); diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 034dfc542..fe4e80baf 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -37,6 +37,10 @@ parameters: count: 3 # TODO for DBAL 4.0 upgrade + - + message: '~^Class Doctrine\\DBAL\\Platforms\\SqlitePlatform referenced with incorrect case: Doctrine\\DBAL\\Platforms\\SQLitePlatform\.$~' + path: '*' + count: 33 - 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' diff --git a/src/Persistence/Sql/DbalDriverMiddleware.php b/src/Persistence/Sql/DbalDriverMiddleware.php index 04366c0d2..7f5af1b8c 100644 --- a/src/Persistence/Sql/DbalDriverMiddleware.php +++ b/src/Persistence/Sql/DbalDriverMiddleware.php @@ -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; @@ -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) { @@ -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; }; diff --git a/src/Persistence/Sql/Expression.php b/src/Persistence/Sql/Expression.php index 2fb194e1d..e3ab46e87 100644 --- a/src/Persistence/Sql/Expression.php +++ b/src/Persistence/Sql/Expression.php @@ -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; @@ -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) . ')'; } diff --git a/src/Schema/Migrator.php b/src/Schema/Migrator.php index fbb4a3b70..d4f20ad00 100644 --- a/src/Schema/Migrator.php +++ b/src/Schema/Migrator.php @@ -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; @@ -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'); } } diff --git a/src/Schema/TestCase.php b/src/Schema/TestCase.php index f5e070c38..5f0cd2257 100644 --- a/src/Schema/TestCase.php +++ b/src/Schema/TestCase.php @@ -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 @@ -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); } diff --git a/tests/ExpressionSqlTest.php b/tests/ExpressionSqlTest.php index e4dd289fd..4a7f918ea 100644 --- a/tests/ExpressionSqlTest.php +++ b/tests/ExpressionSqlTest.php @@ -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 { @@ -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] @@ -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] @@ -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] @@ -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] @@ -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])'; diff --git a/tests/ModelAggregateTest.php b/tests/ModelAggregateTest.php index fe17fb676..34a7871a9 100644 --- a/tests/ModelAggregateTest.php +++ b/tests/ModelAggregateTest.php @@ -8,7 +8,7 @@ use Atk4\Data\Model\Scope; use Atk4\Data\Model\Scope\Condition; use Atk4\Data\Schema\TestCase; -use Doctrine\DBAL\Platforms\SqlitePlatform; +use Doctrine\DBAL\Platforms\SQLitePlatform; class ModelAggregateTest extends TestCase { @@ -178,7 +178,7 @@ public function testGroupSelectCondition2(): void 'double', '>', // TODO Sqlite bind param does not work, expr needed, even if casted to float with DBAL type (comparison works only if casted to/bind as int) - $this->getDatabasePlatform() instanceof SqlitePlatform ? $aggregate->expr('10') : 10 + $this->getDatabasePlatform() instanceof SQLitePlatform ? $aggregate->expr('10') : 10 ); self::assertSame([ @@ -201,7 +201,7 @@ public function testGroupSelectCondition3(): void $aggregate->addCondition( 'double', // TODO Sqlite bind param does not work, expr needed, even if casted to float with DBAL type (comparison works only if casted to/bind as int) - $this->getDatabasePlatform() instanceof SqlitePlatform ? $aggregate->expr('38') : 38 + $this->getDatabasePlatform() instanceof SQLitePlatform ? $aggregate->expr('38') : 38 ); self::assertSame([ @@ -239,7 +239,7 @@ public function testGroupSelectScope(): void self::fixAllNonAggregatedFieldsInGroupBy($aggregate); // TODO Sqlite bind param does not work, expr needed, even if casted to float with DBAL type (comparison works only if casted to/bind as int) - $numExpr = $this->getDatabasePlatform() instanceof SqlitePlatform ? $aggregate->expr('4') : 4; + $numExpr = $this->getDatabasePlatform() instanceof SQLitePlatform ? $aggregate->expr('4') : 4; $scope = Scope::createAnd(new Condition('client_id', 2), new Condition('amount', $numExpr)); $aggregate->addCondition($scope); diff --git a/tests/Persistence/Sql/ConnectionTest.php b/tests/Persistence/Sql/ConnectionTest.php index bccd725f9..00f04554d 100644 --- a/tests/Persistence/Sql/ConnectionTest.php +++ b/tests/Persistence/Sql/ConnectionTest.php @@ -8,13 +8,13 @@ use Atk4\Data\Persistence; use Atk4\Data\Persistence\Sql\Connection; use Doctrine\DBAL\Platforms\AbstractPlatform; -use Doctrine\DBAL\Platforms\SqlitePlatform; +use Doctrine\DBAL\Platforms\SQLitePlatform; class DummyConnection extends Connection { public function getDatabasePlatform(): AbstractPlatform { - return new class() extends SqlitePlatform { + return new class() extends SQLitePlatform { public function getName() { return 'dummy'; @@ -27,7 +27,7 @@ class DummyConnection2 extends Connection { public function getDatabasePlatform(): AbstractPlatform { - return new class() extends SqlitePlatform { + return new class() extends SQLitePlatform { public function getName() { return 'dummy2'; diff --git a/tests/RandomTest.php b/tests/RandomTest.php index b813aaa00..ea152da76 100644 --- a/tests/RandomTest.php +++ b/tests/RandomTest.php @@ -10,7 +10,7 @@ use Atk4\Data\Model; use Atk4\Data\Persistence; use Atk4\Data\Schema\TestCase; -use Doctrine\DBAL\Platforms\SqlitePlatform; +use Doctrine\DBAL\Platforms\SQLitePlatform; class Model_Rate extends Model { @@ -508,7 +508,7 @@ public function testNoWriteActionDelete(): void public function testTableWithSchema(): void { - if ($this->getDatabasePlatform() instanceof SqlitePlatform) { + if ($this->getDatabasePlatform() instanceof SQLitePlatform) { $userSchema = 'db1'; $docSchema = 'db2'; $runWithDb = false; diff --git a/tests/Schema/TestCaseTest.php b/tests/Schema/TestCaseTest.php index 84c3edbce..d755143c8 100644 --- a/tests/Schema/TestCaseTest.php +++ b/tests/Schema/TestCaseTest.php @@ -7,7 +7,7 @@ use Atk4\Data\Model; use Atk4\Data\Schema\TestCase; use Doctrine\DBAL\Platforms\MySQLPlatform; -use Doctrine\DBAL\Platforms\SqlitePlatform; +use Doctrine\DBAL\Platforms\SQLitePlatform; class TestCaseTest extends TestCase { @@ -37,7 +37,7 @@ public function testLogQuery(): void ob_end_clean(); } - if (!$this->getDatabasePlatform() instanceof SqlitePlatform && !$this->getDatabasePlatform() instanceof MySQLPlatform) { + if (!$this->getDatabasePlatform() instanceof SQLitePlatform && !$this->getDatabasePlatform() instanceof MySQLPlatform) { return; } diff --git a/tests/ScopeTest.php b/tests/ScopeTest.php index c53f1011c..3176781ea 100644 --- a/tests/ScopeTest.php +++ b/tests/ScopeTest.php @@ -10,7 +10,7 @@ use Atk4\Data\Model\Scope\Condition; use Atk4\Data\Schema\TestCase; use Doctrine\DBAL\Platforms\MySQLPlatform; -use Doctrine\DBAL\Platforms\SqlitePlatform; +use Doctrine\DBAL\Platforms\SQLitePlatform; class SCountry extends Model { @@ -184,7 +184,7 @@ public function testConditionToWords(): void $condition = new Condition('country_id', 2); self::assertSame('Country ID is equal to 2 (\'Latvia\')', $condition->toWords($user)); - if ($this->getDatabasePlatform() instanceof SqlitePlatform || $this->getDatabasePlatform() instanceof MySQLPlatform) { + if ($this->getDatabasePlatform() instanceof SQLitePlatform || $this->getDatabasePlatform() instanceof MySQLPlatform) { $condition = new Condition('name', $user->expr('[surname]')); self::assertSame('Name is equal to expression \'`surname`\'', $condition->toWords($user)); } @@ -319,7 +319,7 @@ public function testConditionOnReferencedRecords(): void $user->addCondition('Tickets/user/country_id/Users/#', '>', 1); $user->addCondition('Tickets/user/country_id/Users/#', '>=', 2); $user->addCondition('Tickets/user/country_id/Users/country_id/Users/#', '>', 1); - if (!$this->getDatabasePlatform() instanceof SqlitePlatform) { + if (!$this->getDatabasePlatform() instanceof SQLitePlatform) { // not supported because of limitation/issue in Sqlite, the generated query fails // with error: "parser stack overflow" $user->addCondition('Tickets/user/country_id/Users/country_id/Users/name', '!=', null); // should be always true diff --git a/tests/TypecastingTest.php b/tests/TypecastingTest.php index cec8c8fb1..2eae1a8f0 100644 --- a/tests/TypecastingTest.php +++ b/tests/TypecastingTest.php @@ -8,7 +8,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 TypecastingTest extends TestCase { @@ -116,7 +116,7 @@ public function testType(): void $m->load(2)->set('float', 8.202343767574732)->save(); // pdo_sqlite in truncating float, see https://github.com/php/php-src/issues/8510 // fixed since PHP 8.1, but if converted in SQL to string explicitly, the result is still rounded to 15 significant digits - if (!$this->getDatabasePlatform() instanceof SqlitePlatform || \PHP_VERSION_ID >= 80100) { + if (!$this->getDatabasePlatform() instanceof SQLitePlatform || \PHP_VERSION_ID >= 80100) { self::assertSame(8.202343767574732, $m->load(2)->get('float')); } } From 6ef7c25dc654a4f712549eac72a930f532892f9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Vo=C5=99=C3=AD=C5=A1ek?= Date: Thu, 17 Aug 2023 00:24:37 +0200 Subject: [PATCH 2/4] Replace EventManager with configuration middleware --- composer.json | 4 +- phpstan.neon.dist | 8 --- src/Persistence/Sql/Connection.php | 22 +++----- src/Persistence/Sql/Oracle/Connection.php | 65 ++++++++++++++++------- src/Persistence/Sql/Sqlite/Connection.php | 25 +++------ 5 files changed, 62 insertions(+), 62 deletions(-) diff --git a/composer.json b/composer.json index 6141244f9..6feb9f9a5 100644 --- a/composer.json +++ b/composer.json @@ -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": { diff --git a/phpstan.neon.dist b/phpstan.neon.dist index fe4e80baf..cae0ee37b 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -41,14 +41,6 @@ parameters: message: '~^Class Doctrine\\DBAL\\Platforms\\SqlitePlatform referenced with incorrect case: Doctrine\\DBAL\\Platforms\\SQLitePlatform\.$~' path: '*' count: 33 - - - 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 # TODO these rules are generated, this ignores should be fixed in the code # for src/Schema/TestCase.php diff --git a/src/Persistence/Sql/Connection.php b/src/Persistence/Sql/Connection.php index a9cabbf4d..c961a2e67 100644 --- a/src/Persistence/Sql/Connection.php +++ b/src/Persistence/Sql/Connection.php @@ -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; @@ -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 { @@ -238,12 +237,7 @@ public function wrap(DbalDriver $driver): DbalDriver }, ]); - return $dbalConfiguration; - } - - protected static function createDbalEventManager(): EventManager - { - return new EventManager(); + return $configuration; } /** @@ -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 @@ -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; diff --git a/src/Persistence/Sql/Oracle/Connection.php b/src/Persistence/Sql/Oracle/Connection.php index a2ef9b611..f26ebc5a7 100644 --- a/src/Persistence/Sql/Oracle/Connection.php +++ b/src/Persistence/Sql/Oracle/Connection.php @@ -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 diff --git a/src/Persistence/Sql/Sqlite/Connection.php b/src/Persistence/Sql/Sqlite/Connection.php index 129753d83..7a4332a41 100644 --- a/src/Persistence/Sql/Sqlite/Connection.php +++ b/src/Persistence/Sql/Sqlite/Connection.php @@ -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; } } From 0b0f382720a37a68e5c30866e005e5abef76a9f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Vo=C5=99=C3=AD=C5=A1ek?= Date: Thu, 17 Aug 2023 00:30:15 +0200 Subject: [PATCH 3/4] improve FC comment --- bootstrap-types.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bootstrap-types.php b/bootstrap-types.php index 12ad2ea30..bc8a76a87 100644 --- a/bootstrap-types.php +++ b/bootstrap-types.php @@ -10,7 +10,8 @@ use Doctrine\DBAL\Platforms\SqlitePlatform; use Doctrine\DBAL\Types as DbalTypes; -// force Doctrine\DBAL\Platforms\SQLitePlatform class load as in DBAL 3.x named as Doctrine\DBAL\Platforms\SqlitePlatform +// 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); From 5a83f82761d843d7e2da272f2cbd7b9b3dc6cbc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Vo=C5=99=C3=AD=C5=A1ek?= Date: Thu, 17 Aug 2023 00:57:07 +0200 Subject: [PATCH 4/4] improve comment --- phpstan.neon.dist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index cae0ee37b..ee803158f 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -36,7 +36,7 @@ parameters: path: '*' count: 3 - # TODO for DBAL 4.0 upgrade + # FC for DBAL 4.0, remove once DBAL 3.x support is dropped - message: '~^Class Doctrine\\DBAL\\Platforms\\SqlitePlatform referenced with incorrect case: Doctrine\\DBAL\\Platforms\\SQLitePlatform\.$~' path: '*'