Skip to content

Commit

Permalink
[TASK] Ensure Doctrine DBAL 3 and 4 dual support
Browse files Browse the repository at this point in the history
* [1] Doctrine DBAL 4 removed `SqliteManager->createDatabase()`
  and `SqliteManager->dropDatabase()`. The engine is createing
  the SQLite file on connect, but do not remove it on close.
  The `Testbase->setUpTestDatabase()` code is modified to delete
  the sqlite file directly, and let the engine handle the sqlite
  file creation on connect.

* [2] Doctrine DBAL 4 changed the casing of some classes, for
  exmaple `SqlitePlatform` to `SQLitePlatform`, which is not an
  issue for code execution due to the case-insensitive nature of
  PHP - but static code analyser tools like PHPStan fall on their
  feed. Therefore, we use minor wrapping methods instead of php
  interfaceof checks directly to mitigate this and avoid jumping
  PHPStan baseline entry until Doctrine DBAL 4 is the minimal to
  support version.

  Note: The Doctrine DBAL 4 namespace casing is used.

[1] https://github.com/doctrine/dbal/blob/3.7.x/UPGRADE.md#deprecated-sqliteschemamanagercreatedatabase-and-dropdatabase-methods
[2] https://github.com/doctrine/dbal/blob/4.0.x/UPGRADE.md#bc-break-renamed-sqlite-platform-classes

Releases: main
  • Loading branch information
sbuerk committed Jan 11, 2024
1 parent e5d758c commit c9f5d6e
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
namespace TYPO3\TestingFramework\Core\Functional\Framework\DataHandling\Snapshot;

use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Platforms\SqlitePlatform as DoctrineSQLitePlatform;

/**
* Implement the database snapshot and callback logic.
Expand Down Expand Up @@ -62,7 +61,7 @@ private function __construct(string $sqliteDir, string $identifier)
*/
public function create(DatabaseAccessor $accessor, Connection $connection): void
{
if ($connection->getDatabasePlatform() instanceof DoctrineSQLitePlatform) {
if ($this->isSQLite($connection)) {
// With sqlite, we simply copy the db-file to a different place
$connection->close();
copy(
Expand All @@ -88,7 +87,7 @@ public function create(DatabaseAccessor $accessor, Connection $connection): void
*/
public function restore(DatabaseAccessor $accessor, Connection $connection): void
{
if ($connection->getDatabasePlatform() instanceof DoctrineSQLitePlatform) {
if ($this->isSQLite($connection)) {
$connection->close();
copy(
$this->sqliteDir . 'test_' . $this->identifier . '.snapshot.sqlite',
Expand All @@ -101,4 +100,17 @@ public function restore(DatabaseAccessor $accessor, Connection $connection): voi
$accessor->import($this->inMemoryImport);
}
}

/**
* @todo Replace usages by direct instanceof checks when TYPO3 v13.0 / Doctrine DBAL 4 is lowes supported version.
*
* @param Connection $connection
* @return bool
* @throws \Doctrine\DBAL\Exception
*/
private function isSQLite(Connection $connection): bool
{
/** @phpstan-ignore-next-line */
return $connection->getDatabasePlatform() instanceof \Doctrine\DBAL\Platforms\SQLitePlatform;
}
}
43 changes: 30 additions & 13 deletions Classes/Core/Testbase.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@
*/

use Doctrine\DBAL\Configuration;
use Doctrine\DBAL\Connection as DoctrineConnection;
use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\Exception as DBALException;
use Doctrine\DBAL\Platforms\MariaDBPlatform as DoctrineMariaDBPlatform;
use Doctrine\DBAL\Platforms\MySQLPlatform as DoctrineMySQLPlatform;
use Doctrine\DBAL\Platforms\PostgreSQLPlatform as DoctrinePostgreSQLPlatform;
use Doctrine\DBAL\Platforms\SqlitePlatform as DoctrineSQLitePlatform;
use Doctrine\DBAL\Schema\DefaultSchemaManagerFactory;
use Doctrine\DBAL\Schema\SchemaManagerFactory;
use Psr\Container\ContainerInterface;
Expand Down Expand Up @@ -673,21 +673,25 @@ public function setUpTestDatabase(string $databaseName, string $originalDatabase
);
$configuration->setSchemaManagerFactory($coreSchemaFactory);
}
$connection = DriverManager::getConnection($connectionParameters, $configuration);
$schemaManager = $connection->createSchemaManager();
$platform = $connection->getDatabasePlatform();
$isSQLite = $platform instanceof DoctrineSQLitePlatform;
$driverConnection = DriverManager::getConnection($connectionParameters, $configuration);
$schemaManager = $driverConnection->createSchemaManager();
$platform = $driverConnection->getDatabasePlatform();
$isSQLite = self::isSQLite($driverConnection);

if ($isSQLite) {
// This is the "path" option in sqlite: one file = one db
$schemaManager->dropDatabase($databaseName);
} elseif (in_array($databaseName, $schemaManager->listDatabases(), true)) {
// Suppress listDatabases() call on sqlite which is not implemented there, but
// check db existence on all other platforms before drop call
// doctrine/dbal no longer supports createDatabase() and dropDatabase() statements. Guard it.
if (!$isSQLite && in_array($databaseName, $schemaManager->listDatabases(), true)) {
$schemaManager->dropDatabase($databaseName);
} elseif ($isSQLite && is_file($databaseName)) {
// Remove the sqlite file. Prior to Doctrine DBAL 4 the SqliteSchemaManager supported the
// `dropDatabase()` method removing the file. Due to the removal we do it directly now.
@unlink($databaseName);
}
try {
$schemaManager->createDatabase($databaseName);
// doctrine/dbal no longer supports createDatabase() and dropDatabase() statements. Guard it.
// The engine will create the database file automatically.
if (!$isSQLite) {
$schemaManager->createDatabase($databaseName);
}
} catch (DBALException $e) {
$user = $GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['user'];
$host = $GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['host'];
Expand Down Expand Up @@ -912,7 +916,7 @@ public static function resetTableSequences(Connection $connection, string $table
)
);
}
} elseif ($platform instanceof DoctrineSQLitePlatform) {
} elseif (self::isSQLite($connection)) {
// Drop eventually existing sqlite sequence for this table
$connection->executeStatement(
sprintf(
Expand Down Expand Up @@ -997,4 +1001,17 @@ protected function exitWithMessage($message): void
echo $message . chr(10);
exit(1);
}

/**
* @todo Replace usages by direct instanceof checks when TYPO3 v13.0 / Doctrine DBAL 4 is lowes supported version.
*
* @param Connection|DoctrineConnection $connection
* @return bool
* @throws DBALException
*/
private static function isSQLite(Connection|DoctrineConnection $connection): bool
{
/** @phpstan-ignore-next-line */
return $connection->getDatabasePlatform() instanceof \Doctrine\DBAL\Platforms\SQLitePlatform;
}
}

0 comments on commit c9f5d6e

Please sign in to comment.