diff --git a/.doctrine-project.json b/.doctrine-project.json index 2265c6015..fa7811c51 100644 --- a/.doctrine-project.json +++ b/.doctrine-project.json @@ -10,17 +10,23 @@ "slug": "4.0", "upcoming": true }, + { + "name": "3.10", + "branchName": "3.10.x", + "slug": "3.10", + "upcoming": true + }, { "name": "3.9", "branchName": "3.9.x", "slug": "3.9", - "upcoming": true + "current": true }, { "name": "3.8", "branchName": "3.8.x", "slug": "3.8", - "current": true + "maintained": false }, { "name": "3.7", diff --git a/.github/workflows/coding-standards.yml b/.github/workflows/coding-standards.yml index e72b8869e..34efb8a90 100644 --- a/.github/workflows/coding-standards.yml +++ b/.github/workflows/coding-standards.yml @@ -26,4 +26,4 @@ on: jobs: coding-standards: name: "Coding Standards" - uses: "doctrine/.github/.github/workflows/coding-standards.yml@7.2.2" + uses: "doctrine/.github/.github/workflows/coding-standards.yml@7.3.0" diff --git a/.github/workflows/composer-lint.yml b/.github/workflows/composer-lint.yml index 82dff6fc1..595f2edee 100644 --- a/.github/workflows/composer-lint.yml +++ b/.github/workflows/composer-lint.yml @@ -17,4 +17,4 @@ on: jobs: composer-lint: name: "Composer Lint" - uses: "doctrine/.github/.github/workflows/composer-lint.yml@7.2.2" + uses: "doctrine/.github/.github/workflows/composer-lint.yml@7.3.0" diff --git a/.github/workflows/release-on-milestone-closed.yml b/.github/workflows/release-on-milestone-closed.yml index c0bfaa865..951002cd7 100644 --- a/.github/workflows/release-on-milestone-closed.yml +++ b/.github/workflows/release-on-milestone-closed.yml @@ -8,7 +8,7 @@ on: jobs: release: name: "Git tag, release & create merge-up PR" - uses: "doctrine/.github/.github/workflows/release-on-milestone-closed.yml@7.2.2" + uses: "doctrine/.github/.github/workflows/release-on-milestone-closed.yml@7.3.0" secrets: GIT_AUTHOR_EMAIL: ${{ secrets.GIT_AUTHOR_EMAIL }} GIT_AUTHOR_NAME: ${{ secrets.GIT_AUTHOR_NAME }} diff --git a/.github/workflows/website-schema.yml b/.github/workflows/website-schema.yml index e51b4a588..3b30ece55 100644 --- a/.github/workflows/website-schema.yml +++ b/.github/workflows/website-schema.yml @@ -18,4 +18,4 @@ on: jobs: json-validate: name: "Validate JSON schema" - uses: "doctrine/.github/.github/workflows/website-schema.yml@7.2.2" + uses: "doctrine/.github/.github/workflows/website-schema.yml@7.3.0" diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 65d100b15..cb2422d6b 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -38,6 +38,9 @@ parameters: - message: '~Doctrine\\ORM\\Tools\\Console\\Helper\\EntityManagerHelper~' path: src/Tools/Console/ConsoleRunner.php + - + message: '#^Usage of deprecated trait Symfony\\Component\\VarExporter\\LazyProxyTrait in class Doctrine\\Migrations\\Provider\\LazySchema\:\nsince Symfony 7\.3, use native lazy objects instead$#' + path: src/Provider/LazySchema.php symfony: console_application_loader: tests/doctrine-migrations-phpstan-app.php diff --git a/src/Generator/DiffGenerator.php b/src/Generator/DiffGenerator.php index 240885ab5..b1798934f 100644 --- a/src/Generator/DiffGenerator.php +++ b/src/Generator/DiffGenerator.php @@ -42,6 +42,7 @@ public function generate( string $fqcn, string|null $filterExpression, bool $formatted = false, + bool|null $nowdocOutput = null, int $lineLength = 120, bool $checkDbPlatform = true, bool $fromEmptySchema = false, @@ -83,6 +84,7 @@ static function ($assetName) use ($filterExpression) { $up = $this->migrationSqlGenerator->generate( $upSql, $formatted, + $nowdocOutput, $lineLength, $checkDbPlatform, ); @@ -92,6 +94,7 @@ static function ($assetName) use ($filterExpression) { $down = $this->migrationSqlGenerator->generate( $downSql, $formatted, + $nowdocOutput, $lineLength, $checkDbPlatform, ); diff --git a/src/Generator/SqlGenerator.php b/src/Generator/SqlGenerator.php index 8738256b5..4fa2ca8cd 100644 --- a/src/Generator/SqlGenerator.php +++ b/src/Generator/SqlGenerator.php @@ -19,6 +19,7 @@ use function str_repeat; use function stripos; use function strlen; +use function var_export; /** * The SqlGenerator class is responsible for generating the body of the up() and down() methods for a migration @@ -40,12 +41,14 @@ public function __construct( public function generate( array $sql, bool $formatted = false, + bool|null $nowdocOutput = null, int $lineLength = 120, bool $checkDbPlatform = true, ): string { $code = []; $storageConfiguration = $this->configuration->getMetadataStorageConfiguration(); + $maxLength = $lineLength - 18 - 8; // max - php code length - indentation foreach ($sql as $query) { if ( $storageConfiguration instanceof TableMetadataStorageConfiguration @@ -54,18 +57,18 @@ public function generate( continue; } - if ($formatted) { - $maxLength = $lineLength - 18 - 8; // max - php code length - indentation - - if (strlen($query) > $maxLength) { - $query = $this->formatQuery($query); - } + if ($formatted && strlen($query) > $maxLength) { + $query = $this->formatQuery($query); } - $code[] = sprintf( - "\$this->addSql(<<<'SQL'\n%s\nSQL);", - preg_replace('/^/m', str_repeat(' ', 4), $query), - ); + if ($nowdocOutput === true || ($nowdocOutput !== false && $formatted && strlen($query) > $maxLength )) { + $code[] = sprintf( + "\$this->addSql(<<<'SQL'\n%s\nSQL);", + preg_replace('/^/m', str_repeat(' ', 4), $query), + ); + } else { + $code[] = sprintf('$this->addSql(%s);', var_export($query, true)); + } } if (count($code) !== 0 && $checkDbPlatform && $this->configuration->isDatabasePlatformChecked()) { diff --git a/src/SchemaDumper.php b/src/SchemaDumper.php index f1938c9cf..cbe6e3e01 100644 --- a/src/SchemaDumper.php +++ b/src/SchemaDumper.php @@ -56,6 +56,7 @@ public function dump( string $fqcn, array $excludedTablesRegexes = [], bool $formatted = false, + bool $nowdocOutput = false, int $lineLength = 120, ): string { $schema = $this->schemaManager->introspectSchema(); @@ -73,6 +74,7 @@ public function dump( $upCode = $this->migrationSqlGenerator->generate( $upSql, $formatted, + $nowdocOutput, $lineLength, ); @@ -85,6 +87,7 @@ public function dump( $downCode = $this->migrationSqlGenerator->generate( $downSql, $formatted, + $nowdocOutput, $lineLength, ); diff --git a/src/Tools/Console/Command/DiffCommand.php b/src/Tools/Console/Command/DiffCommand.php index 04bb9b8fc..ec82d8ccc 100644 --- a/src/Tools/Console/Command/DiffCommand.php +++ b/src/Tools/Console/Command/DiffCommand.php @@ -63,6 +63,12 @@ protected function configure(): void InputOption::VALUE_NONE, 'Format the generated SQL.', ) + ->addOption( + 'nowdoc', + null, + InputOption::VALUE_NEGATABLE, + 'Output the generated SQL as a nowdoc string (always active for formatted queries).', + ) ->addOption( 'line-length', null, @@ -102,6 +108,7 @@ protected function execute( } $formatted = filter_var($input->getOption('formatted'), FILTER_VALIDATE_BOOLEAN); + $nowdocOutput = filter_var($input->getOption('nowdoc'), FILTER_VALIDATE_BOOLEAN); $lineLength = (int) $input->getOption('line-length'); $allowEmptyDiff = $input->getOption('allow-empty-diff'); $checkDbPlatform = filter_var($input->getOption('check-database-platform'), FILTER_VALIDATE_BOOLEAN); @@ -135,6 +142,7 @@ protected function execute( $fqcn, $filterExpression, $formatted, + $nowdocOutput, $lineLength, $checkDbPlatform, $fromEmptySchema, diff --git a/src/Tools/Console/Command/DumpSchemaCommand.php b/src/Tools/Console/Command/DumpSchemaCommand.php index 963a32c9d..129bac6a1 100644 --- a/src/Tools/Console/Command/DumpSchemaCommand.php +++ b/src/Tools/Console/Command/DumpSchemaCommand.php @@ -14,9 +14,12 @@ use function addslashes; use function class_exists; +use function filter_var; use function sprintf; use function str_contains; +use const FILTER_VALIDATE_BOOLEAN; + /** * The DumpSchemaCommand class is responsible for dumping your current database schema to a migration class. This is * intended to be used in conjunction with the RollupCommand. @@ -49,6 +52,12 @@ protected function configure(): void InputOption::VALUE_NONE, 'Format the generated SQL.', ) + ->addOption( + 'nowdoc', + null, + InputOption::VALUE_NONE, + 'Output the generated SQL as a nowdoc string (always active for formatted queries).', + ) ->addOption( 'namespace', null, @@ -75,8 +84,9 @@ public function execute( InputInterface $input, OutputInterface $output, ): int { - $formatted = $input->getOption('formatted'); - $lineLength = (int) $input->getOption('line-length'); + $formatted = filter_var($input->getOption('formatted'), FILTER_VALIDATE_BOOLEAN); + $nowdocOutput = filter_var($input->getOption('nowdoc'), FILTER_VALIDATE_BOOLEAN); + $lineLength = (int) $input->getOption('line-length'); $schemaDumper = $this->getDependencyFactory()->getSchemaDumper(); @@ -98,6 +108,7 @@ public function execute( $fqcn, $input->getOption('filter-tables'), $formatted, + $nowdocOutput, $lineLength, ); diff --git a/tests/Generator/DiffGeneratorTest.php b/tests/Generator/DiffGeneratorTest.php index 48ad71db5..f9095734b 100644 --- a/tests/Generator/DiffGeneratorTest.php +++ b/tests/Generator/DiffGeneratorTest.php @@ -102,7 +102,7 @@ public function testGenerate(): void ->with(self::logicalOr( self::equalTo(['UPDATE table SET value = 2']), self::equalTo(['UPDATE table SET value = 1']), - ), true, 80) + ), true, false, 80) ->willReturnOnConsecutiveCalls('test1', 'test2'); $this->migrationGenerator->expects(self::once()) @@ -114,6 +114,7 @@ public function testGenerate(): void '1234', '/table_name1/', true, + false, 80, )); } @@ -169,7 +170,7 @@ public function testGenerateFromEmptySchema(): void ->with(self::logicalOr( self::equalTo(['CREATE TABLE table_name']), self::equalTo(['DROP TABLE table_name']), - ), false, 120, true) + ), false, false, 120, true) ->willReturnOnConsecutiveCalls('test up', 'test down'); $this->migrationGenerator->expects(self::once()) @@ -177,7 +178,7 @@ public function testGenerateFromEmptySchema(): void ->with('2345', 'test up', 'test down') ->willReturn('path2'); - self::assertSame('path2', $this->migrationDiffGenerator->generate('2345', null, false, 120, true, true)); + self::assertSame('path2', $this->migrationDiffGenerator->generate('2345', null, false, false, 120, true, true)); } protected function setUp(): void diff --git a/tests/Generator/SqlGeneratorTest.php b/tests/Generator/SqlGeneratorTest.php index 422a1eb4c..d5a4ab90f 100644 --- a/tests/Generator/SqlGeneratorTest.php +++ b/tests/Generator/SqlGeneratorTest.php @@ -51,24 +51,37 @@ public function testGenerate(): void "Migration can only be executed safely on '\\$expectedPlatform'." ); - \$this->addSql(<<<'SQL' - SELECT 1 - SQL); - \$this->addSql(<<<'SQL' - SELECT 2 - SQL); + \$this->addSql('SELECT 1'); + \$this->addSql('SELECT 2'); \$this->addSql(<<<'SQL' %s SQL); CODE, ); - $code = $migrationSqlGenerator->generate($this->sql, true, 80); + $code = $migrationSqlGenerator->generate($this->sql, true, null, 80); self::assertSame($expectedCode, $code); } - public function testGenerationWithoutCheckingDatabasePlatform(): void + public function testGenerationWithoutFormatting(): void + { + $this->configuration->setCheckDatabasePlatform(true); + + $expectedCode = $this->prepareGeneratedCode( + <<<'CODE' + $this->addSql('SELECT 1'); + $this->addSql('SELECT 2'); + $this->addSql('%s'); + CODE, + formatted: false, + ); + + $code = $this->migrationSqlGenerator->generate($this->sql, false, null, 80, false); + self::assertSame($expectedCode, $code); + } + + public function testGenerationWithNowDocOutput(): void { $this->configuration->setCheckDatabasePlatform(true); @@ -84,9 +97,47 @@ public function testGenerationWithoutCheckingDatabasePlatform(): void %s SQL); CODE, + formatted: false, + ); + + $code = $this->migrationSqlGenerator->generate($this->sql, false, true, 80, false); + self::assertSame($expectedCode, $code); + } + + public function testGenerationWithNoNowDocFormatting(): void + { + $this->configuration->setCheckDatabasePlatform(true); + + $expectedCode = $this->prepareGeneratedCode( + <<<'CODE' + $this->addSql('SELECT 1'); + $this->addSql('SELECT 2'); + $this->addSql('%s'); + CODE, + formatted: true, + nowdoc: false, + ); + + $code = $this->migrationSqlGenerator->generate($this->sql, true, false, 80, false); + + self::assertSame($expectedCode, $code); + } + + public function testGenerationWithoutCheckingDatabasePlatform(): void + { + $this->configuration->setCheckDatabasePlatform(true); + + $expectedCode = $this->prepareGeneratedCode( + <<<'CODE' + $this->addSql('SELECT 1'); + $this->addSql('SELECT 2'); + $this->addSql(<<<'SQL' + %s + SQL); + CODE, ); - $code = $this->migrationSqlGenerator->generate($this->sql, true, 80, false); + $code = $this->migrationSqlGenerator->generate($this->sql, true, null, 80, false); self::assertSame($expectedCode, $code); } @@ -97,19 +148,15 @@ public function testGenerationWithoutCheckingDatabasePlatformWithConfiguration() $expectedCode = $this->prepareGeneratedCode( <<<'CODE' - $this->addSql(<<<'SQL' - SELECT 1 - SQL); - $this->addSql(<<<'SQL' - SELECT 2 - SQL); + $this->addSql('SELECT 1'); + $this->addSql('SELECT 2'); $this->addSql(<<<'SQL' %s SQL); CODE, ); - $code = $this->migrationSqlGenerator->generate($this->sql, true, 80); + $code = $this->migrationSqlGenerator->generate($this->sql, true, null, 80); self::assertSame($expectedCode, $code); } @@ -127,7 +174,7 @@ protected function setUp(): void ); } - private function prepareGeneratedCode(string $expectedCode): string + private function prepareGeneratedCode(string $expectedCode, bool $formatted = true, bool $nowdoc = true): string { $this->sql = [ 'SELECT 1', @@ -138,15 +185,21 @@ private function prepareGeneratedCode(string $expectedCode): string $this->metadataConfig->setTableName('migrations_table_name'); + if ($formatted) { + $formattedSql = (new SqlFormatter(new NullHighlighter()))->format($this->sql[2]); + if ($nowdoc) { + $formattedSql = implode( + "\n" . str_repeat(' ', 4), + explode("\n", $formattedSql), + ); + } + + return sprintf($expectedCode, $formattedSql); + } + return sprintf( $expectedCode, - implode( - "\n" . str_repeat(' ', 4), - explode( - "\n", - (new SqlFormatter(new NullHighlighter()))->format($this->sql[2]), - ), - ), + $this->sql[2], ); } } diff --git a/tests/Tools/Console/Command/DiffCommandTest.php b/tests/Tools/Console/Command/DiffCommandTest.php index 282113376..0ac6f6588 100644 --- a/tests/Tools/Console/Command/DiffCommandTest.php +++ b/tests/Tools/Console/Command/DiffCommandTest.php @@ -65,12 +65,13 @@ public function testExecute(): void $this->migrationDiffGenerator->expects(self::once()) ->method('generate') - ->with('FooNs\\Version1234', 'filter expression', true, 80) + ->with('FooNs\\Version1234', 'filter expression', true, false, 80) ->willReturn('/path/to/migration.php'); $this->diffCommandTester->execute([ '--filter-expression' => 'filter expression', '--formatted' => true, + '--nowdoc' => false, '--line-length' => 80, '--allow-empty-diff' => true, '--check-database-platform' => true, diff --git a/tests/Tools/Console/Command/DumpSchemaCommandTest.php b/tests/Tools/Console/Command/DumpSchemaCommandTest.php index 3724c4f7d..494c3c1b7 100644 --- a/tests/Tools/Console/Command/DumpSchemaCommandTest.php +++ b/tests/Tools/Console/Command/DumpSchemaCommandTest.php @@ -77,12 +77,13 @@ public function testExecute(): void $this->schemaDumper->expects(self::once()) ->method('dump') - ->with('FooNs\\Version1234', ['/foo/'], true, 80); + ->with('FooNs\\Version1234', ['/foo/'], true, false, 80); $this->dumpSchemaCommandTester->execute([ '--filter-tables' => ['/foo/'], '--line-length' => 80, '--formatted' => true, + '--nowdoc' => false, ]); $output = $this->dumpSchemaCommandTester->getDisplay(true);