Skip to content

Commit 9f3bad3

Browse files
committed
fix: pass join column options to FK
1 parent 9d99850 commit 9f3bad3

File tree

5 files changed

+111
-0
lines changed

5 files changed

+111
-0
lines changed

.DS_Store

6 KB
Binary file not shown.

docs/en/reference/attributes-reference.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,7 @@ Optional parameters:
686686
make foreign keys work.
687687
- **options**:
688688
See "options" attribute on :ref:`#[Column] <attrref_column>`.
689+
It's possible to add other options, for example (PostgreSQL) `['deferrable' => true, 'deferred' => true]`.
689690

690691
Example:
691692

src/Tools/SchemaTool.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,14 @@
3838
use function array_flip;
3939
use function array_intersect_key;
4040
use function array_map;
41+
use function array_replace;
4142
use function assert;
4243
use function class_exists;
4344
use function count;
4445
use function current;
4546
use function implode;
4647
use function in_array;
48+
use function is_array;
4749
use function is_numeric;
4850
use function method_exists;
4951
use function strtolower;
@@ -715,6 +717,10 @@ private function gatherRelationJoinColumns(
715717
$uniqueConstraints[] = ['columns' => [$quotedColumnName]];
716718
}
717719

720+
if (is_array($joinColumn->options)) {
721+
$fkOptions = array_replace($fkOptions, $joinColumn->options);
722+
}
723+
718724
if (isset($joinColumn->onDelete)) {
719725
$fkOptions['onDelete'] = $joinColumn->onDelete;
720726
}

tests/Tests/ORM/Functional/SchemaTool/PostgreSqlSchemaToolTest.php

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,13 @@
1111
use Doctrine\ORM\Mapping\Id;
1212
use Doctrine\ORM\Mapping\JoinColumn;
1313
use Doctrine\ORM\Mapping\ManyToOne;
14+
use Doctrine\ORM\Mapping\OneToOne;
1415
use Doctrine\ORM\Mapping\Table;
1516
use Doctrine\Tests\OrmFunctionalTestCase;
1617
use PHPUnit\Framework\Attributes\Group;
1718

1819
use function array_filter;
20+
use function array_slice;
1921
use function implode;
2022
use function str_starts_with;
2123

@@ -42,6 +44,60 @@ public function testUpdateSchemaWithPostgreSQLSchema(): void
4244

4345
self::assertCount(0, $sql, implode("\n", $sql));
4446
}
47+
48+
public function testUpdateSchemaWithJoinColumnWithOptions(): void
49+
{
50+
$sql = $this->getUpdateSchemaSqlForModels(
51+
TestEntityWithJoinColumnWithOptions::class,
52+
TestEntityWithJoinColumnWithOptionsRelation::class,
53+
);
54+
55+
$this->assertSame([
56+
'CREATE TABLE test (id INT NOT NULL, testRelation1_id INT DEFAULT NULL, testRelation2_id INT DEFAULT NULL, PRIMARY KEY(id))',
57+
'CREATE UNIQUE INDEX UNIQ_D87F7E0C331521C6 ON test (testRelation1_id)',
58+
'CREATE UNIQUE INDEX UNIQ_D87F7E0C21A08E28 ON test (testRelation2_id)',
59+
'CREATE TABLE test_relation (id INT NOT NULL, PRIMARY KEY(id))',
60+
'ALTER TABLE test ADD CONSTRAINT FK_D87F7E0C331521C6 FOREIGN KEY (testRelation1_id) REFERENCES test_relation (id) DEFERRABLE INITIALLY DEFERRED',
61+
'ALTER TABLE test ADD CONSTRAINT FK_D87F7E0C21A08E28 FOREIGN KEY (testRelation2_id) REFERENCES test_relation (id) NOT DEFERRABLE INITIALLY IMMEDIATE',
62+
], array_slice($sql, 0, 5));
63+
64+
foreach ($sql as $query) {
65+
$this->_em->getConnection()->executeQuery($query);
66+
}
67+
68+
$sql = $this->getUpdateSchemaSqlForModels(
69+
TestEntityWithJoinColumnWithOptions::class,
70+
TestEntityWithJoinColumnWithOptionsRelation::class,
71+
);
72+
73+
$this->assertSame([], $sql);
74+
}
75+
}
76+
77+
#[Table('test')]
78+
#[Entity]
79+
class TestEntityWithJoinColumnWithOptions
80+
{
81+
#[Id]
82+
#[Column]
83+
private int $id;
84+
85+
#[OneToOne(targetEntity: TestEntityWithJoinColumnWithOptionsRelation::class)]
86+
#[JoinColumn(options: ['deferrable' => true, 'deferred' => true])]
87+
private TestEntityWithJoinColumnWithOptionsRelation $testRelation1;
88+
89+
#[OneToOne(targetEntity: TestEntityWithJoinColumnWithOptionsRelation::class)]
90+
#[JoinColumn]
91+
private TestEntityWithJoinColumnWithOptionsRelation $testRelation2;
92+
}
93+
94+
#[Table('test_relation')]
95+
#[Entity]
96+
class TestEntityWithJoinColumnWithOptionsRelation
97+
{
98+
#[Id]
99+
#[Column]
100+
private int $id;
45101
}
46102

47103
#[Table(name: 'stonewood.screen')]

tests/Tests/ORM/Tools/SchemaToolTest.php

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace Doctrine\Tests\ORM\Tools;
66

77
use Doctrine\Common\Collections\Collection;
8+
use Doctrine\DBAL\Platforms\PostgreSQLPlatform;
89
use Doctrine\DBAL\Schema\ForeignKeyConstraintEditor;
910
use Doctrine\DBAL\Schema\Index as DbalIndex;
1011
use Doctrine\DBAL\Schema\Index\IndexedColumn;
@@ -452,6 +453,53 @@ private static function columnIsIndexed(DbalTable $table, string $column): bool
452453

453454
return false;
454455
}
456+
457+
public function testJoinColumnWithOptions(): void
458+
{
459+
$em = $this->getTestEntityManager();
460+
$schemaTool = new SchemaTool($em);
461+
462+
$classes = [
463+
$em->getClassMetadata(TestEntityWithJoinColumnWithOptions::class),
464+
$em->getClassMetadata(TestEntityWithJoinColumnWithOptionsRelation::class),
465+
];
466+
467+
$schema = $schemaTool->getSchemaFromMetadata($classes);
468+
469+
self::assertSame(['deferrable' => true, 'deferred' => true], $schema->getTable('test')->getForeignKey('FK_D87F7E0C331521C6')->getOptions());
470+
self::assertSame([], $schema->getTable('test')->getForeignKey('FK_D87F7E0C21A08E28')->getOptions());
471+
472+
$sql = $schema->toSql(new PostgreSQLPlatform());
473+
474+
$this->assertSame('ALTER TABLE test ADD CONSTRAINT FK_D87F7E0C331521C6 FOREIGN KEY (testRelation1_id) REFERENCES test_relation (id) DEFERRABLE INITIALLY DEFERRED', $sql[count($sql) - 2]);
475+
$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]);
476+
}
477+
}
478+
479+
#[Table('test')]
480+
#[Entity]
481+
class TestEntityWithJoinColumnWithOptions
482+
{
483+
#[Id]
484+
#[Column]
485+
private int $id;
486+
487+
#[OneToOne(targetEntity: TestEntityWithJoinColumnWithOptionsRelation::class)]
488+
#[JoinColumn(options: ['deferrable' => true, 'deferred' => true])]
489+
private TestEntityWithJoinColumnWithOptionsRelation $testRelation1;
490+
491+
#[OneToOne(targetEntity: TestEntityWithJoinColumnWithOptionsRelation::class)]
492+
#[JoinColumn]
493+
private TestEntityWithJoinColumnWithOptionsRelation $testRelation2;
494+
}
495+
496+
#[Table('test_relation')]
497+
#[Entity]
498+
class TestEntityWithJoinColumnWithOptionsRelation
499+
{
500+
#[Id]
501+
#[Column]
502+
private int $id;
455503
}
456504

457505
#[Table(options: ['foo' => 'bar', 'baz' => ['key' => 'val']])]

0 commit comments

Comments
 (0)