Deprecate unnamed foreign key constraints in $droppedForeignKeys of TableDiff#7143
Conversation
|
I added the test to |
54bae1a to
c2852f3
Compare
src/Platforms/SQLitePlatform.php
Outdated
|
|
||
| foreach ($diff->getDroppedForeignKeys() as $constraint) { | ||
| $constraintName = $constraint->getName(); | ||
| foreach ($diff->getDroppedForeignKeys() as $name => $constraint) { |
There was a problem hiding this comment.
This is against the effort made in #7102. The constraint name is represented by the constraint object itself, not by some array key.
There was a problem hiding this comment.
Got it, thanks for pointing that out! I’ll look into applying a different approach that aligns better with the changes from #7102 as soon as possible.
There was a problem hiding this comment.
It might be a good idea to just deprecate the scenario when the constraint being dropped doesn't have a name. Currently, we're not doing anything, which causes a bug. Making it work correctly would require a deeper redesign of schema management.
Just for context, the fundamental flaw is the following. The test attempts to perform a schema migration in the following steps:
- Define two versions of a table.
- Calculate a difference between them.
- Apply the difference.
The problem is that:
- The calculation of the difference is non-deterministic (you cannot reliably tell whether a given column was renamed or dropped and created). This doesn't apply to this specific case, but still.
- SQLite doesn't support
ALTER TABLE. The DBAL has to recreate it from scratch and migrate the data.
The combination of these flaws leads to the fact that we cannot migrate schemas with unnamed constraints. A proper design for SQLite would not involve the diff at all. For SQLite, it would use the expected table schema directly.
There was a problem hiding this comment.
Hi, thanks a lot for the detailed explanation! 😊
That makes sense. I’ll update the PR this weekend to only emit a deprecation notice in this case.
Thanks again! ❤️
c2852f3 to
3b3b7ca
Compare
3b3b7ca to
c809db7
Compare
|
Hi! 😄 |
e774f56 to
a656527
Compare
|
Hi @morozov, I hope you're doing well! 😄 I've updated this PR based on your suggestions from the previous one. I modified the deprecation message, updated the Please let me know if anything needs to be changed or corrected 😊 Thanks again! ❤️ |
a656527 to
3e16542
Compare
UPGRADE.md
Outdated
|
|
||
| ## Deprecated dropping unnamed constraints in SQLite | ||
|
|
||
| Dropping a constraint without specifying its name has been deprecated on the SQLite platform. |
There was a problem hiding this comment.
This will have to be reworded accordingly. Something like this:
Passing unnamed foreign key constraints as part of the
$droppedForeignKeysargument of theTableDiffconstructor has been deprecated.
src/Platforms/SQLitePlatform.php
Outdated
| $constraintName = $constraint->getName(); | ||
|
|
||
| if ($constraintName === '') { | ||
| Deprecation::trigger( |
There was a problem hiding this comment.
Whether a foreign key constraint is dropped on SQLite or any other platform, it's expected to have a name:
dbal/src/Platforms/AbstractPlatform.php
Lines 1372 to 1374 in aa6b906
The fact that TableDiff::getDroppedForeignKeys() can return unnamed constraints is essentially a bug as using it as is will result in invalid DDL.
I think we should move this deprecation to the TableDiff constructor. In 5.0.x, this deprecation will need to be promoted to an exception, and all callers of TableDiff::getDroppedForeignKeys() could make an assertion that the constraint being dropped does have a name before using it.
There was a problem hiding this comment.
Hi! 😄
Thanks so much for the suggestions ❤️
I’ve made the following changes in the test:
- Updated the test a bit, it now verifies that the deprecation is triggered in the constructor of
TableDiff. - Also, it checks that a foreign key is not dropped when the dropped foreign key doesn't have a name.
- Moved the test from
SQLiteSchemaManagerTesttoSchemaManagerFunctionalTestCaseso it runs across all platforms.
I do have one question. I’m still getting familiar with Doctrine DBAL 😅
Do you think this check is necessary?
if ($constraintName === null || $constraintName === '') {Or would just checking $constraintName === null be enough? 🤔
Thanks again for your help! 😊
3e16542 to
cdb1a22
Compare
src/Platforms/AbstractPlatform.php
Outdated
| foreach ($diff->getDroppedForeignKeys() as $foreignKey) { | ||
| $constraintName = $foreignKey->getObjectName()?->toString(); | ||
| if ($constraintName === null || $constraintName === '') { | ||
| continue; |
There was a problem hiding this comment.
We don't want to do this. It is better to have invalid DDL generated, so the user sees that something is wrong, rather then get an invalid input silently ignored.
src/Schema/TableDiff.php
Outdated
| $constraintName = $droppedForeignKey->getObjectName()?->toString(); | ||
| if ($constraintName === null || $constraintName === '') { |
There was a problem hiding this comment.
We cannot use getObjectName() in the library code in 4.4.x since it can throw an exception, if the name is invalid and cannot be parsed using the 5.0.x logic, but can be using the 4.4.x one. Please use if ($droppedForeignKey->getName() === '') instead.
| self::assertSame(2, $columns['column_char']->getLength()); | ||
| } | ||
|
|
||
| public function testAlterTableWithUnnamedForeignKey(): void |
There was a problem hiding this comment.
Please replace this with a TableDiff constructor test.
bbfeaff to
77a9f60
Compare
$droppedForeignKeys of TableDiff
tests/Schema/TableDiffTest.php
Outdated
| ->create(); | ||
|
|
||
| $droppedForeignKeys = ForeignKeyConstraint::editor() | ||
| ->setUnquotedReferencingColumnNames('c1', 'c2') |
There was a problem hiding this comment.
c2 can be removed from the definition: it's not needed to reproduce the issue and it doesn't exist on the referencing table.
… `TableDiff` DroppedForeignKey must have a constraint name to ensure reliable schema diffing and migration generation. A deprecation warning is now triggered if the name is missing.
77a9f60 to
5d56d2e
Compare
|
Thanks, @santysisi! |
|
|
||
| # Upgrade to 4.4 | ||
|
|
||
| ## Deprecated dropping unnamed constraints in SQLite |
There was a problem hiding this comment.
@santysisi Does it still only apply for SQLite?
| ## Deprecated dropping unnamed constraints in SQLite | |
| ## Deprecated dropping unnamed constraints |
There was a problem hiding this comment.
You're right, that was my mistake.
Thanks so much for catching that! 🙏
I've opened this PR to resolve the issue
Summary
This PR introduces a deprecation notice when a unnamed foreign key constraints in
$droppedForeignKeysis passed in the constructor ofTableDiff.