diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 393f5f822..b337bfaac 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -28,6 +28,9 @@ jobs: strategy: matrix: + dbal-version: + - "^2.11" + - "^3.0" php-version: - "7.2" - "7.3" @@ -38,6 +41,9 @@ jobs: include: - deps: "lowest" php-version: "7.2" + exclude: + - dbal-version: "^3.0" + php-version: "7.2" steps: - name: "Checkout" @@ -60,6 +66,10 @@ jobs: run: "composer self-update --1" if: "${{ matrix.deps == 'lowest' }}" + - name: "Require the right DBAL version" + run: "composer require doctrine/dbal:${{ matrix.dbal-version }} --no-update" + if: "${{ matrix.dbal-version }}" + - name: "Install dependencies with Composer" uses: "ramsey/composer-install@v1" with: diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index f5eaf5ebb..029dc0c3f 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -16,10 +16,16 @@ jobs: strategy: matrix: + dbal-version: + - "^2.11" + - "^3.0" php-version: - "7.2" - "7.4" - "8.0" + exclude: + - dbal-version: "^3.0" + php-version: "7.2" steps: - name: "Checkout code" @@ -32,10 +38,17 @@ jobs: php-version: "${{ matrix.php-version }}" extensions: "pdo_sqlite" + - name: "Require the right DBAL version" + run: "composer require doctrine/dbal:${{ matrix.dbal-version }} --no-update" + - name: "Install dependencies with Composer" uses: "ramsey/composer-install@v1" with: dependency-versions: "${{ matrix.dependencies }}" - - name: "Run a static analysis with phpstan/phpstan" - run: "vendor/bin/phpstan analyse" + - name: "Run a static analysis with phpstan/phpstan (dbal v2)" + run: "vendor/bin/phpstan analyse -c phpstan-dbal-2.neon.dist" + if: "contains(matrix.dbal-version, '^2.')" + - name: "Run a static analysis with phpstan/phpstan (dbal v3)" + run: "vendor/bin/phpstan analyse -c phpstan-dbal-3.neon.dist" + if: "contains(matrix.dbal-version, '^3.')" diff --git a/composer.json b/composer.json index 18fec970b..1e675582b 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,7 @@ "require": { "php": "^7.2 || ^8.0", "composer/package-versions-deprecated": "^1.8", - "doctrine/dbal": "^2.11", + "doctrine/dbal": "^2.11 || ^3.0", "doctrine/deprecations": "^0.5.3", "doctrine/event-manager": "^1.0", "friendsofphp/proxy-manager-lts": "^1.0", diff --git a/lib/Doctrine/Migrations/AbstractMigration.php b/lib/Doctrine/Migrations/AbstractMigration.php index d09af6922..c06d88194 100644 --- a/lib/Doctrine/Migrations/AbstractMigration.php +++ b/lib/Doctrine/Migrations/AbstractMigration.php @@ -5,7 +5,7 @@ namespace Doctrine\Migrations; use Doctrine\DBAL\Connection; -use Doctrine\DBAL\DBALException; +use Doctrine\DBAL\Exception as DBALException; use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Schema\AbstractSchemaManager; use Doctrine\DBAL\Schema\Schema; @@ -16,6 +16,7 @@ use Doctrine\Migrations\Query\Query; use Psr\Log\LoggerInterface; +use function method_exists; use function sprintf; /** @@ -42,7 +43,9 @@ abstract class AbstractMigration public function __construct(Connection $connection, LoggerInterface $logger) { $this->connection = $connection; - $this->sm = $this->connection->getSchemaManager(); + $this->sm = method_exists($this->connection, 'createSchemaManager') + ? $this->connection->createSchemaManager() + : $this->connection->getSchemaManager(); $this->platform = $this->connection->getDatabasePlatform(); $this->logger = $logger; } diff --git a/lib/Doctrine/Migrations/DependencyFactory.php b/lib/Doctrine/Migrations/DependencyFactory.php index c91af0399..4d3153961 100644 --- a/lib/Doctrine/Migrations/DependencyFactory.php +++ b/lib/Doctrine/Migrations/DependencyFactory.php @@ -5,6 +5,7 @@ namespace Doctrine\Migrations; use Doctrine\DBAL\Connection; +use Doctrine\DBAL\Schema\AbstractSchemaManager; use Doctrine\Migrations\Configuration\Configuration; use Doctrine\Migrations\Configuration\Connection\ConnectionLoader; use Doctrine\Migrations\Configuration\EntityManager\EntityManagerLoader; @@ -51,6 +52,7 @@ use function array_key_exists; use function call_user_func; +use function method_exists; use function preg_quote; use function sprintf; @@ -231,7 +233,7 @@ public function getSchemaDumper(): SchemaDumper return new SchemaDumper( $this->getConnection()->getDatabasePlatform(), - $this->getConnection()->getSchemaManager(), + $this->getSchemaManager($this->getConnection()), $this->getMigrationGenerator(), $this->getMigrationSqlGenerator(), $excludedTables @@ -239,11 +241,18 @@ public function getSchemaDumper(): SchemaDumper }); } + private function getSchemaManager(Connection $connection): AbstractSchemaManager + { + return method_exists($connection, 'createSchemaManager') + ? $connection->createSchemaManager() + : $connection->getSchemaManager(); + } + private function getEmptySchemaProvider(): SchemaProvider { return $this->getDependency(EmptySchemaProvider::class, function (): SchemaProvider { return new EmptySchemaProvider( - $this->getConnection()->getSchemaManager() + $this->getSchemaManager($this->getConnection()) ); }); } @@ -275,7 +284,7 @@ public function getDiffGenerator(): DiffGenerator return $this->getDependency(DiffGenerator::class, function (): DiffGenerator { return new DiffGenerator( $this->getConnection()->getConfiguration(), - $this->getConnection()->getSchemaManager(), + $this->getSchemaManager($this->getConnection()), $this->getSchemaProvider(), $this->getConnection()->getDatabasePlatform(), $this->getMigrationGenerator(), @@ -290,7 +299,7 @@ public function getSchemaDiffProvider(): SchemaDiffProvider return $this->getDependency(SchemaDiffProvider::class, function (): LazySchemaDiffProvider { return LazySchemaDiffProvider::fromDefaultProxyFactoryConfiguration( new DBALSchemaDiffProvider( - $this->getConnection()->getSchemaManager(), + $this->getSchemaManager($this->getConnection()), $this->getConnection()->getDatabasePlatform() ) ); diff --git a/lib/Doctrine/Migrations/Tools/Console/Command/ExecuteCommand.php b/lib/Doctrine/Migrations/Tools/Console/Command/ExecuteCommand.php index 77f5d9dcc..c5c802212 100644 --- a/lib/Doctrine/Migrations/Tools/Console/Command/ExecuteCommand.php +++ b/lib/Doctrine/Migrations/Tools/Console/Command/ExecuteCommand.php @@ -114,9 +114,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int $migratorConfigurationFactory = $this->getDependencyFactory()->getConsoleInputMigratorConfigurationFactory(); $migratorConfiguration = $migratorConfigurationFactory->getMigratorConfiguration($input); - $question = sprintf( + $databaseName = (string) $this->getDependencyFactory()->getConnection()->getDatabase(); + $question = sprintf( 'WARNING! You are about to execute a migration in database "%s" that could result in schema changes and data loss. Are you sure you wish to continue?', - $this->getDependencyFactory()->getConnection()->getDatabase() ?? '' + $databaseName === '' ? '' : $databaseName ); if (! $migratorConfiguration->isDryRun() && ! $this->canExecute($question, $input)) { $this->io->error('Migration cancelled!'); diff --git a/lib/Doctrine/Migrations/Tools/Console/Command/MigrateCommand.php b/lib/Doctrine/Migrations/Tools/Console/Command/MigrateCommand.php index 977b68cf6..aa58197b6 100644 --- a/lib/Doctrine/Migrations/Tools/Console/Command/MigrateCommand.php +++ b/lib/Doctrine/Migrations/Tools/Console/Command/MigrateCommand.php @@ -129,9 +129,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int $migratorConfigurationFactory = $this->getDependencyFactory()->getConsoleInputMigratorConfigurationFactory(); $migratorConfiguration = $migratorConfigurationFactory->getMigratorConfiguration($input); - $question = sprintf( + $databaseName = (string) $this->getDependencyFactory()->getConnection()->getDatabase(); + $question = sprintf( 'WARNING! You are about to execute a migration in database "%s" that could result in schema changes and data loss. Are you sure you wish to continue?', - $this->getDependencyFactory()->getConnection()->getDatabase() ?? '' + $databaseName === '' ? '' : $databaseName ); if (! $migratorConfiguration->isDryRun() && ! $this->canExecute($question, $input)) { $this->io->error('Migration cancelled!'); diff --git a/phpstan.neon.dist b/phpstan-common.neon.dist similarity index 87% rename from phpstan.neon.dist rename to phpstan-common.neon.dist index 40aebd634..7a41be19d 100644 --- a/phpstan.neon.dist +++ b/phpstan-common.neon.dist @@ -3,7 +3,7 @@ parameters: paths: - %currentWorkingDirectory%/lib - %currentWorkingDirectory%/tests - excludes_analyse: + excludePaths: - %currentWorkingDirectory%/tests/Doctrine/Migrations/Tests/Configuration/ConfigurationTestSource/Migrations/Version123.php ignoreErrors: - '~Variable method call on Doctrine\\Migrations\\AbstractMigration~' @@ -13,6 +13,7 @@ parameters: - message: '~^Variable property access on SimpleXMLElement\.$~' path: %currentWorkingDirectory%/lib/Doctrine/Migrations/Configuration/Migration/XmlFile.php + - message: '~^Call to function is_bool\(\) with bool will always evaluate to true\.$~' path: %currentWorkingDirectory%/lib/Doctrine/Migrations/InlineParameterFormatter.php @@ -23,11 +24,7 @@ parameters: message: '~^Method Doctrine\\Migrations\\Tests\\Stub\\DoctrineRegistry::getService\(\) should return Doctrine\\Persistence\\ObjectManager but returns Doctrine\\DBAL\\Connection\|Doctrine\\ORM\\EntityManager~' path: %currentWorkingDirectory%/tests/Doctrine/Migrations/Tests/Stub/DoctrineRegistry.php - '~Call to method getVersion\(\) of deprecated class PackageVersions\\Versions\:.*~' - - - message: '~^Instantiation of deprecated class~' - paths: - - tests/Doctrine/Migrations/Tests/Tools/Console/legacy-config-dbal/cli-config.php - - tests/Doctrine/Migrations/Tests/Tools/Console/legacy-config-wrong/cli-config.php + # Requires PHPUnit 9 - message: '~assert.*Reg~' diff --git a/phpstan-dbal-2.neon.dist b/phpstan-dbal-2.neon.dist new file mode 100644 index 000000000..ede0697c7 --- /dev/null +++ b/phpstan-dbal-2.neon.dist @@ -0,0 +1,19 @@ +includes: + - phpstan-common.neon.dist + +parameters: + ignoreErrors: + + - + message: '~^Fetching class constant class of deprecated class Doctrine\\DBAL\\Tools\\Console\\Helper\\ConnectionHelper~' + path: %currentWorkingDirectory%/tests/Doctrine/Migrations/Tests/Tools/Console/ConsoleRunnerTest.php + + - + message: "~^Casting to string something that's already string~" + path: %currentWorkingDirectory%/lib/Doctrine/Migrations/Tools/Console/Command/*Command.php + + - + message: '~^Instantiation of deprecated class~' + paths: + - tests/Doctrine/Migrations/Tests/Tools/Console/legacy-config-dbal/cli-config.php + - tests/Doctrine/Migrations/Tests/Tools/Console/legacy-config-wrong/cli-config.php diff --git a/phpstan-dbal-3.neon.dist b/phpstan-dbal-3.neon.dist new file mode 100644 index 000000000..f84ec0844 --- /dev/null +++ b/phpstan-dbal-3.neon.dist @@ -0,0 +1,25 @@ +includes: + - phpstan-common.neon.dist + +parameters: + + ignoreErrors: + - "~Call to function method_exists\\(\\) with Doctrine\\\\DBAL\\\\Connection and 'createSchemaManager' will always evaluate to true~" + - '~^Call to deprecated method getSchemaManager\(\) of class Doctrine\\DBAL\\Connection~' + - + message: '~^Parameter.* class Symfony\\Component\\Console\\Helper\\HelperSet constructor expects ~' + paths: + - tests/Doctrine/Migrations/Tests/Tools/Console/legacy-config-dbal/cli-config.php + - tests/Doctrine/Migrations/Tests/Tools/Console/legacy-config-wrong/cli-config.php + - + message: '~^Class Doctrine\\DBAL\\Tools\\Console\\Helper\\ConnectionHelper not found~' + path: lib/Doctrine/Migrations/Tools/Console/ConsoleRunner.php + - + message: '~^Call to method getConnection\(\) on an unknown class Doctrine\\DBAL\\Tools\\Console\\Helper\\ConnectionHelper~' + path: lib/Doctrine/Migrations/Tools/Console/ConsoleRunner.php + - + message: '~Instantiated class Doctrine\\DBAL\\Tools\\Console\\Helper\\ConnectionHelper not found~' + paths: + - tests/Doctrine/Migrations/Tests/Tools/Console/legacy-config-dbal/cli-config.php + - tests/Doctrine/Migrations/Tests/Tools/Console/legacy-config-wrong/cli-config.php + diff --git a/tests/Doctrine/Migrations/Tests/Provider/OrmSchemaProviderTest.php b/tests/Doctrine/Migrations/Tests/Provider/OrmSchemaProviderTest.php index caf33cd3f..1de6cd869 100644 --- a/tests/Doctrine/Migrations/Tests/Provider/OrmSchemaProviderTest.php +++ b/tests/Doctrine/Migrations/Tests/Provider/OrmSchemaProviderTest.php @@ -35,15 +35,6 @@ public function testCreateSchemaFetchesMetadataFromEntityManager(): void { $schema = $this->ormProvider->createSchema(); - self::assertSame( - [ - 'public.a', - 'public.b', - 'public.c', - ], - $schema->getTableNames() - ); - foreach (['a', 'b', 'c'] as $expectedTable) { $table = $schema->getTable($expectedTable); self::assertTrue($table->hasColumn('id')); diff --git a/tests/Doctrine/Migrations/Tests/Tools/Console/ConsoleRunnerTest.php b/tests/Doctrine/Migrations/Tests/Tools/Console/ConsoleRunnerTest.php index 073aba295..3498dab0f 100644 --- a/tests/Doctrine/Migrations/Tests/Tools/Console/ConsoleRunnerTest.php +++ b/tests/Doctrine/Migrations/Tests/Tools/Console/ConsoleRunnerTest.php @@ -4,6 +4,7 @@ namespace Doctrine\Migrations\Tests\Tools\Console; +use Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper; use Doctrine\Migrations\DependencyFactory; use Doctrine\Migrations\Tools\Console\ConsoleRunner; use Doctrine\ORM\EntityManager; @@ -14,6 +15,7 @@ use Symfony\Component\Console\Helper\HelperSet; use function chdir; +use function class_exists; use function getcwd; use function realpath; use function sprintf; @@ -28,6 +30,10 @@ class ConsoleRunnerTest extends TestCase public function testCreateDependencyFactoryFromLegacyDbalHelper(): void { + if (! class_exists(ConnectionHelper::class)) { + self::markTestSkipped('DBAL 3.0 does not provide anymore the ConnectionHelper'); + } + $dir = getcwd(); if ($dir === false) { $dir = '.'; @@ -65,6 +71,10 @@ public function testCreateDependencyFactoryFromLegacyOrmHelper(): void public function testCreateDependencyFactoryFromWrongLegacyHelper(): void { + if (! class_exists(ConnectionHelper::class)) { + self::markTestSkipped('DBAL 3.0 does not provide anymore the ConnectionHelper'); + } + $this->expectException(RuntimeException::class); $dir = getcwd();