From 34e4481c631ac7631b0e24ee789247599e913141 Mon Sep 17 00:00:00 2001 From: Venca Krecl Date: Fri, 14 Jun 2024 11:58:39 +0200 Subject: [PATCH 1/5] fix: pass join column options to FK --- src/Tools/SchemaTool.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Tools/SchemaTool.php b/src/Tools/SchemaTool.php index 42b52df8c71..bd8091f1051 100644 --- a/src/Tools/SchemaTool.php +++ b/src/Tools/SchemaTool.php @@ -31,6 +31,7 @@ use function array_filter; use function array_flip; use function array_intersect_key; +use function array_merge; use function assert; use function count; use function current; @@ -712,6 +713,10 @@ private function gatherRelationJoinColumns( $uniqueConstraints[] = ['columns' => [$quotedColumnName]]; } + if ($joinColumn->options) { + $fkOptions = array_merge($fkOptions, $joinColumn->options); + } + if (isset($joinColumn->onDelete)) { $fkOptions['onDelete'] = $joinColumn->onDelete; } From 9bc6dd16cad1e0602bb0efe33c298d2b3eec0a0d Mon Sep 17 00:00:00 2001 From: Venca Krecl Date: Fri, 14 Jun 2024 13:19:56 +0200 Subject: [PATCH 2/5] test: add test --- tests/Tests/ORM/Tools/SchemaToolTest.php | 36 ++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tests/Tests/ORM/Tools/SchemaToolTest.php b/tests/Tests/ORM/Tools/SchemaToolTest.php index a1f3e77d70c..16aaad94869 100644 --- a/tests/Tests/ORM/Tools/SchemaToolTest.php +++ b/tests/Tests/ORM/Tools/SchemaToolTest.php @@ -391,6 +391,42 @@ public function testLoadUniqueConstraintWithoutName(): void self::assertTrue($tableIndex->isUnique()); self::assertSame(['field', 'anotherField'], $tableIndex->getColumns()); } + + public function testJoinColumnWithOptions(): void + { + $em = $this->getTestEntityManager(); + $schemaTool = new SchemaTool($em); + + $classes = [ + $em->getClassMetadata(TestEntityWithJoinColumnWithOptions::class), + $em->getClassMetadata(TestEntityWithJoinColumnWithOptionsRelation::class), + ]; + + $schema = $schemaTool->getSchemaFromMetadata($classes); + + self::assertSame(['deferrable' => true, 'deferred' => true], $schema->getTable('test')->getForeignKey('FK_D87F7E0C1E5D0459')->getOptions()); + } +} + +#[Table('test')] +#[Entity] +class TestEntityWithJoinColumnWithOptions +{ + #[Id] + #[Column] + private int $id; + + #[OneToOne(targetEntity: TestEntityWithJoinColumnWithOptionsRelation::class)] + #[JoinColumn(options: ['deferrable' => true, 'deferred' => true])] + private TestEntityWithJoinColumnWithOptionsRelation $test; +} + +#[Entity] +class TestEntityWithJoinColumnWithOptionsRelation +{ + #[Id] + #[Column] + private int $id; } #[Table(options: ['foo' => 'bar', 'baz' => ['key' => 'val']])] From 39d31022464565c724479fcc98dcf8e462b4938d Mon Sep 17 00:00:00 2001 From: Venca Krecl Date: Fri, 14 Jun 2024 13:28:22 +0200 Subject: [PATCH 3/5] docs: add example of options --- docs/en/reference/attributes-reference.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/reference/attributes-reference.rst b/docs/en/reference/attributes-reference.rst index 64f15ddbba5..57fe1e53f1d 100644 --- a/docs/en/reference/attributes-reference.rst +++ b/docs/en/reference/attributes-reference.rst @@ -686,6 +686,7 @@ Optional parameters: make foreign keys work. - **options**: See "options" attribute on :ref:`#[Column] `. + It's possible to add other options, for example (PostgreSQL) `['deferrable' => true, 'deferred' => true]`. Example: From 69fa1d68cb319c465e8ef29652141031952dc258 Mon Sep 17 00:00:00 2001 From: Venca Krecl Date: Tue, 18 Jun 2024 14:46:51 +0200 Subject: [PATCH 4/5] test: add test for sql result --- tests/Tests/ORM/Tools/SchemaToolTest.php | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/tests/Tests/ORM/Tools/SchemaToolTest.php b/tests/Tests/ORM/Tools/SchemaToolTest.php index 16aaad94869..b2d3f02362a 100644 --- a/tests/Tests/ORM/Tools/SchemaToolTest.php +++ b/tests/Tests/ORM/Tools/SchemaToolTest.php @@ -5,6 +5,7 @@ namespace Doctrine\Tests\ORM\Tools; use Doctrine\Common\Collections\Collection; +use Doctrine\DBAL\Platforms\PostgreSQLPlatform; use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Mapping\Column; use Doctrine\ORM\Mapping\Entity; @@ -404,7 +405,13 @@ public function testJoinColumnWithOptions(): void $schema = $schemaTool->getSchemaFromMetadata($classes); - self::assertSame(['deferrable' => true, 'deferred' => true], $schema->getTable('test')->getForeignKey('FK_D87F7E0C1E5D0459')->getOptions()); + self::assertSame(['deferrable' => true, 'deferred' => true], $schema->getTable('test')->getForeignKey('FK_D87F7E0C331521C6')->getOptions()); + self::assertSame([], $schema->getTable('test')->getForeignKey('FK_D87F7E0C21A08E28')->getOptions()); + + $sql = $schema->toSql(new PostgreSQLPlatform()); + + $this->assertSame('ALTER TABLE test ADD CONSTRAINT FK_D87F7E0C331521C6 FOREIGN KEY (testRelation1_id) REFERENCES test_relation (id) DEFERRABLE INITIALLY DEFERRED', $sql[count($sql) - 2]); + $this->assertSame('ALTER TABLE test ADD CONSTRAINT FK_D87F7E0C21A08E28 FOREIGN KEY (testRelation2_id) REFERENCES test_relation (id) NOT DEFERRABLE INITIALLY IMMEDIATE', $sql[count($sql) - 1]); } } @@ -418,9 +425,14 @@ class TestEntityWithJoinColumnWithOptions #[OneToOne(targetEntity: TestEntityWithJoinColumnWithOptionsRelation::class)] #[JoinColumn(options: ['deferrable' => true, 'deferred' => true])] - private TestEntityWithJoinColumnWithOptionsRelation $test; + private TestEntityWithJoinColumnWithOptionsRelation $testRelation1; + + #[OneToOne(targetEntity: TestEntityWithJoinColumnWithOptionsRelation::class)] + #[JoinColumn] + private TestEntityWithJoinColumnWithOptionsRelation $testRelation2; } +#[Table('test_relation')] #[Entity] class TestEntityWithJoinColumnWithOptionsRelation { From 6dfe0f3759db0ec0e2682de46ce4ba7d6bbf3126 Mon Sep 17 00:00:00 2001 From: Venca Krecl Date: Sun, 7 Jul 2024 22:15:49 +0200 Subject: [PATCH 5/5] test: add functional --- .../SchemaTool/PostgreSqlSchemaToolTest.php | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/tests/Tests/ORM/Functional/SchemaTool/PostgreSqlSchemaToolTest.php b/tests/Tests/ORM/Functional/SchemaTool/PostgreSqlSchemaToolTest.php index 61aef5d4040..a699c5aee43 100644 --- a/tests/Tests/ORM/Functional/SchemaTool/PostgreSqlSchemaToolTest.php +++ b/tests/Tests/ORM/Functional/SchemaTool/PostgreSqlSchemaToolTest.php @@ -11,11 +11,13 @@ use Doctrine\ORM\Mapping\Id; use Doctrine\ORM\Mapping\JoinColumn; use Doctrine\ORM\Mapping\ManyToOne; +use Doctrine\ORM\Mapping\OneToOne; use Doctrine\ORM\Mapping\Table; use Doctrine\Tests\OrmFunctionalTestCase; use PHPUnit\Framework\Attributes\Group; use function array_filter; +use function array_slice; use function implode; use function str_starts_with; @@ -42,6 +44,60 @@ public function testUpdateSchemaWithPostgreSQLSchema(): void self::assertCount(0, $sql, implode("\n", $sql)); } + + public function testUpdateSchemaWithJoinColumnWithOptions(): void + { + $sql = $this->getUpdateSchemaSqlForModels( + TestEntityWithJoinColumnWithOptions::class, + TestEntityWithJoinColumnWithOptionsRelation::class, + ); + + $this->assertSame([ + 'CREATE TABLE test (id INT NOT NULL, testRelation1_id INT DEFAULT NULL, testRelation2_id INT DEFAULT NULL, PRIMARY KEY(id))', + 'CREATE UNIQUE INDEX UNIQ_D87F7E0C331521C6 ON test (testRelation1_id)', + 'CREATE UNIQUE INDEX UNIQ_D87F7E0C21A08E28 ON test (testRelation2_id)', + 'CREATE TABLE test_relation (id INT NOT NULL, PRIMARY KEY(id))', + 'ALTER TABLE test ADD CONSTRAINT FK_D87F7E0C331521C6 FOREIGN KEY (testRelation1_id) REFERENCES test_relation (id) DEFERRABLE INITIALLY DEFERRED', + 'ALTER TABLE test ADD CONSTRAINT FK_D87F7E0C21A08E28 FOREIGN KEY (testRelation2_id) REFERENCES test_relation (id) NOT DEFERRABLE INITIALLY IMMEDIATE', + ], array_slice($sql, 0, 5)); + + foreach ($sql as $query) { + $this->_em->getConnection()->executeQuery($query); + } + + $sql = $this->getUpdateSchemaSqlForModels( + TestEntityWithJoinColumnWithOptions::class, + TestEntityWithJoinColumnWithOptionsRelation::class, + ); + + $this->assertSame([], $sql); + } +} + +#[Table('test')] +#[Entity] +class TestEntityWithJoinColumnWithOptions +{ + #[Id] + #[Column] + private int $id; + + #[OneToOne(targetEntity: TestEntityWithJoinColumnWithOptionsRelation::class)] + #[JoinColumn(options: ['deferrable' => true, 'deferred' => true])] + private TestEntityWithJoinColumnWithOptionsRelation $testRelation1; + + #[OneToOne(targetEntity: TestEntityWithJoinColumnWithOptionsRelation::class)] + #[JoinColumn] + private TestEntityWithJoinColumnWithOptionsRelation $testRelation2; +} + +#[Table('test_relation')] +#[Entity] +class TestEntityWithJoinColumnWithOptionsRelation +{ + #[Id] + #[Column] + private int $id; } #[Table(name: 'stonewood.screen')]