Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/Phinx/Db/Adapter/PostgresAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -1388,6 +1388,10 @@
$def .= " ON UPDATE {$foreignKey->getOnUpdate()}";
}

if ($foreignKey->getDeferrableMode()) {
$def .= " {$foreignKey->getDeferrableMode()}";

Check warning on line 1392 in src/Phinx/Db/Adapter/PostgresAdapter.php

View check run for this annotation

Codecov / codecov/patch

src/Phinx/Db/Adapter/PostgresAdapter.php#L1391-L1392

Added lines #L1391 - L1392 were not covered by tests
}

return $def;
}

Expand Down
46 changes: 45 additions & 1 deletion src/Phinx/Db/Table/ForeignKey.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,14 @@ class ForeignKey
public const RESTRICT = 'RESTRICT';
public const SET_NULL = 'SET NULL';
public const NO_ACTION = 'NO ACTION';
public const DEFERRED = 'DEFERRABLE INITIALLY DEFERRED';
public const IMMEDIATE = 'DEFERRABLE INITIALLY IMMEDIATE';
public const NOT_DEFERRED = 'NOT DEFERRABLE';

/**
* @var array<string>
*/
protected static array $validOptions = ['delete', 'update', 'constraint'];
protected static array $validOptions = ['delete', 'update', 'constraint', 'deferrable'];

/**
* @var string[]
Expand Down Expand Up @@ -52,6 +55,7 @@ class ForeignKey
* @var string|null
*/
protected ?string $constraint = null;
protected ?string $deferrableMode = null;

/**
* Sets the foreign key columns.
Expand Down Expand Up @@ -195,6 +199,27 @@ public function getConstraint(): ?string
return $this->constraint;
}

/**
* Sets deferrable mode for the foreign key.
*
* @param string $deferrableMode Constraint
* @return $this
*/
public function setDeferrableMode(string $deferrableMode)
{
$this->deferrableMode = $this->normalizeDeferrable($deferrableMode);

return $this;
}

/**
* Gets deferrable mode for the foreign key.
*/
public function getDeferrableMode(): ?string
{
return $this->deferrableMode;
}

/**
* Utility method that maps an array of index options to this objects methods.
*
Expand All @@ -214,6 +239,8 @@ public function setOptions(array $options)
$this->setOnDelete($value);
} elseif ($option === 'update') {
$this->setOnUpdate($value);
} elseif ($option === 'deferrable') {
$this->setDeferrableMode($value);
} else {
$method = 'set' . ucfirst($option);
$this->$method($value);
Expand All @@ -239,4 +266,21 @@ protected function normalizeAction(string $action): string

return constant($constantName);
}

/**
* From passed value checks if it's correct and fixes if needed
*
* @param string $deferrable Deferrable
* @throws \InvalidArgumentException
* @return string
*/
protected function normalizeDeferrable(string $deferrable): string
{
$constantName = 'static::' . strtoupper(trim($deferrable));
if (!defined($constantName)) {
throw new InvalidArgumentException('Unknown action passed: ' . $deferrable);
}

return constant($constantName);
}
}
21 changes: 21 additions & 0 deletions tests/Phinx/Db/Adapter/PostgresAdapterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1612,6 +1612,27 @@ public function testAddForeignKey()
$this->assertTrue($this->adapter->hasForeignKey($table->getName(), ['ref_table_id']));
}

public function testAddForeignKeyDeferrable()
{
$refTable = new Table('ref_table', [], $this->adapter);
$refTable->addColumn('field1', 'string')->save();

$table = new Table('table', [], $this->adapter);
$table
->addColumn('ref_table_id', 'integer')
->addForeignKey(
['ref_table_id'],
'ref_table',
['id'],
[
'deferrable' => 'DEFERRED',
]
)
->save();

$this->assertTrue($this->adapter->hasForeignKey($table->getName(), ['ref_table_id']));
}

public function testAddForeignKeyWithSchema()
{
$this->adapter->createSchema('schema1');
Expand Down
42 changes: 42 additions & 0 deletions tests/Phinx/Db/Table/ForeignKeyTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,36 @@ public function testBothActionsCanBeSetThroughOptions($dirtyValue, $valueOfConst
$this->assertEquals($valueOfConstant, $this->fk->getOnUpdate());
}

/**
* @param string $dirtyValue
* @param string $valueOfConstant
* @dataProvider deferrableProvider
*/
public function testDeferrableCanBeSetThroughSetters(string $dirtyValue, string $valueOfConstant): void
{
$this->fk->setDeferrableMode($dirtyValue);
$this->assertEquals($valueOfConstant, $this->fk->getDeferrableMode());
}

/**
* @param string $dirtyValue
* @param string $valueOfConstant
* @dataProvider deferrableProvider
*/
public function testDeferrableCanBeSetThroughOptions(string $dirtyValue, string $valueOfConstant): void
{
$this->fk->setOptions([
'deferrable' => $dirtyValue,
]);
$this->assertEquals($valueOfConstant, $this->fk->getDeferrableMode());
}

public function testThrowsErrorForInvalidDeferrableValue(): void
{
$this->expectException(InvalidArgumentException::class);
$this->fk->setDeferrableMode('invalid_value');
}

public function testUnknownActionsNotAllowedThroughSetter()
{
$this->expectException(InvalidArgumentException::class);
Expand Down Expand Up @@ -95,6 +125,18 @@ public function actionsProvider()
];
}

public function deferrableProvider(): array
{
return [
['DEFERRED', ForeignKey::DEFERRED],
['IMMEDIATE', ForeignKey::IMMEDIATE],
['NOT_DEFERRED', ForeignKey::NOT_DEFERRED],
['Deferred', ForeignKey::DEFERRED],
['Immediate', ForeignKey::IMMEDIATE],
['Not_deferred', ForeignKey::NOT_DEFERRED],
];
}

public function testSetOptionThrowsExceptionIfOptionIsNotString()
{
$this->expectException(RuntimeException::class);
Expand Down
Loading