Skip to content

Autogenerated migration keeps dropping and re-adding unrelated foreign keys #1483

Open
@Menelion

Description

@Menelion

Bug Report

Q A
BC Break no
Version 3.8.2

Summary

I'm using Symfony 7.2 and its Maker bundle. Under the hood the make:migration command calls doctrine:migrations:diff. For some reason, it keeps dropping and re-adding foreign keys on totally unrelated entities.
I'm using MariaDB 11.2.2 on this machine.

Current behavior

doctrine:migrations:diff drops and re-adds unrelated foreign keys (see steps to reproduce).

How to reproduce

  1. Either use make:entity in Symfony or add this entity manually:
<?php

namespace App\Entity;

use App\Repository\LanguageRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;

#[ORM\Entity(repositoryClass: LanguageRepository::class)]
#[ORM\Table(name: 'languages')]
#[UniqueEntity(fields: ['code'], message: 'There is already a language with this code')]
class Language
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\Column(type: Types::SMALLINT, options: ['unsigned' => true])]
    private ?int $position = null;

    #[ORM\Column(length: 20)]
    private ?string $code = null;

    #[ORM\Column(length: 100)]
    private ?string $englishName = null;

    #[ORM\Column(length: 100)]
    private ?string $nativeName = null;

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getPosition(): ?int
    {
        return $this->position;
    }

    public function setPosition(int $position): self
    {
        $this->position = $position;

        return $this;
    }

    public function getCode(): ?string
    {
        return $this->code;
    }

    public function setCode(string $code): self
    {
        $this->code = $code;

        return $this;
    }

    public function getEnglishName(): ?string
    {
        return $this->englishName;
    }

    public function setEnglishName(string $englishName): static
    {
        $this->englishName = $englishName;

        return $this;
    }

    public function getNativeName(): ?string
    {
        return $this->nativeName;
    }

    public function setNativeName(string $nativeName): static
    {
        $this->nativeName = $nativeName;

        return $this;
    }
}
  1. Run doctrine:migrations:diff --formatted. I'm getting this:
<?php

declare(strict_types=1);

namespace DoctrineMigrations;

use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;

final class Version20250109223941 extends AbstractMigration
{
    public function getDescription(): string
    {
        return 'Created languages table';
    }

    public function up(Schema $schema): void
    {
        $this->addSql('CREATE TABLE languages (
          id INT AUTO_INCREMENT NOT NULL,
          position SMALLINT UNSIGNED NOT NULL,
          code VARCHAR(20) NOT NULL,
          english_name VARCHAR(100) NOT NULL,
          native_name VARCHAR(100) NOT NULL,
          PRIMARY KEY(id)
        ) DEFAULT CHARACTER
        SET
          utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
        $this->addSql('ALTER TABLE reset_password_request DROP FOREIGN KEY FK_7CE748AA76ED395');
        $this->addSql('ALTER TABLE
           reset_password_request
        ADD
          CONSTRAINT FK_7CE748AA76ED395 FOREIGN KEY (user_id) REFERENCES users (id)');
    }

    public function down(Schema $schema): void
    {
        // this down() migration is auto-generated, please modify it to your needs
        $this->addSql('DROP TABLE languages');
        $this->addSql('ALTER TABLE reset_password_request DROP FOREIGN KEY FK_7CE748AA76ED395');
        $this->addSql('ALTER TABLE
          reset_password_request
        ADD
          CONSTRAINT FK_7CE748AA76ED395 FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE');
    }
}

the reset_password_request migration for reference:

<?php

declare(strict_types=1);

namespace DoctrineMigrations;

use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;

final class Version20250101232946 extends AbstractMigration
{
    public function getDescription(): string
    {
        return 'Added the reset password request table and isVerified column to the Users table';
    }

    public function up(Schema $schema): void
    {
        $this->addSql(
            'CREATE TABLE reset_password_request (
              id INT AUTO_INCREMENT NOT NULL,
              user_id INT NOT NULL,
              selector VARCHAR(20) NOT NULL,
              hashed_token VARCHAR(100) NOT NULL,
              requested_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\',
              expires_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\',
              INDEX IDX_7CE748AA76ED395 (user_id),
              PRIMARY KEY(id)
            )
            DEFAULT CHARACTER SET utf8mb4
            COLLATE `utf8mb4_unicode_ci`
            ENGINE = InnoDB
        ');

        $this->addSql(
            'ALTER TABLE
            reset_password_request
            ADD
            CONSTRAINT FK_7CE748AA76ED395 FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE
        ');

        $this->addSql('ALTER TABLE users ADD is_verified TINYINT(1) NOT NULL');
    }

    public function down(Schema $schema): void
    {
        $this->addSql('ALTER TABLE reset_password_request DROP FOREIGN KEY FK_7CE748AA76ED395');
        $this->addSql('DROP TABLE reset_password_request');
        $this->addSql('ALTER TABLE users DROP is_verified');
    }
}

Expected behavior

The reset_password_request table has nothing to do with this one at all, so it shouldn't be altered. There is no relations to users table either, it's just a standalone languages table.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions