DoctrineEnumBundle icon indicating copy to clipboard operation
DoctrineEnumBundle copied to clipboard

doctrine:migrations:diff always regenerates enum creation

Open fkrauthan opened this issue 7 years ago • 29 comments

I am using Symfony 3.2 and a mysql database. I have the following problem everytime I run console doctrine:migrations:diff. The output always regenerates the enum field (and the teardown always "reverts" it back to regular varchar fields.

Here is an example output:

> C:\Dev\php\php-7.1\php.exe C:\Users\fkrauthan\PhpstormProjects\play-for-today\flowergame2\bin\console doctrine:migrations:diff
Generated new migration class to "C:\Users\fkrauthan\PhpstormProjects\play-for-today\flowergame2\app/migrations/Version20170107235007.php" from schema differences.
<?php

namespace Application\Migrations;

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

/**
 * Auto-generated Migration: Please modify to your needs!
 */
class Version20170107235007 extends AbstractMigration
{
    /**
     * @param Schema $schema
     */
    public function up(Schema $schema)
    {
        // this up() migration is auto-generated, please modify it to your needs
        $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.');

        $this->addSql('CREATE TABLE objects (id INT AUTO_INCREMENT NOT NULL, user_id INT DEFAULT NULL, object_type_id INT DEFAULT NULL, created_at DATETIME DEFAULT NULL, updated_at DATETIME DEFAULT NULL, INDEX IDX_B21ACCF3A76ED395 (user_id), INDEX IDX_B21ACCF3C5020C33 (object_type_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB');
        $this->addSql('ALTER TABLE objects ADD CONSTRAINT FK_B21ACCF3A76ED395 FOREIGN KEY (user_id) REFERENCES users (id)');
        $this->addSql('ALTER TABLE objects ADD CONSTRAINT FK_B21ACCF3C5020C33 FOREIGN KEY (object_type_id) REFERENCES object_types (id)');
        $this->addSql('ALTER TABLE compendium_entries CHANGE state state ENUM(\'seed\', \'germ\', \'mature\') NOT NULL');
        $this->addSql('ALTER TABLE flowers CHANGE state state ENUM(\'seed\', \'germ\', \'mature\') NOT NULL');
        $this->addSql('ALTER TABLE flower_graphic_sets CHANGE rarity rarity ENUM(\'common\', \'breed\', \'wild\', \'exclusive\') NOT NULL');
        $this->addSql('ALTER TABLE users CHANGE sort_option sort_option ENUM(\'old\', \'release\', \'new\', \'color\', \'species\') NOT NULL');
    }

    /**
     * @param Schema $schema
     */
    public function down(Schema $schema)
    {
        // this down() migration is auto-generated, please modify it to your needs
        $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.');

        $this->addSql('DROP TABLE objects');
        $this->addSql('ALTER TABLE compendium_entries CHANGE state state VARCHAR(255) NOT NULL COLLATE utf8_unicode_ci');
        $this->addSql('ALTER TABLE flower_graphic_sets CHANGE rarity rarity VARCHAR(255) NOT NULL COLLATE utf8_unicode_ci');
        $this->addSql('ALTER TABLE flowers CHANGE state state VARCHAR(255) NOT NULL COLLATE utf8_unicode_ci');
        $this->addSql('ALTER TABLE users CHANGE sort_option sort_option VARCHAR(255) NOT NULL COLLATE utf8_unicode_ci');
    }
}


Process finished with exit code 0 at 15:50:07.
Execution time: 962 ms.```

Any idea why this is happening? Right now every time I generate a new diff I have to manual remove the enum alters as reverting a migration would destroy my database schema.

fkrauthan avatar Jan 08 '17 06:01 fkrauthan

@fkrauthan

  1. What version of MySQL do you use?
  2. Can you show your migration where you tables with enums are created the first time. You should have such migration. Because as I understood your new migrations adds already added enums.

fre5h avatar Jan 10 '17 18:01 fre5h

I am using latest Mariadb version (a mysql drop in replacement).

And here is the initial migration where some of the enums got added for the first time:

<?php

namespace Application\Migrations;

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

/**
 * Auto-generated Migration: Please modify to your needs!
 */
class Version20161205185813 extends AbstractMigration
{
    /**
     * @param Schema $schema
     */
    public function up(Schema $schema)
    {
        // this up() migration is auto-generated, please modify it to your needs
        $this->abortIf($this->connection->getDatabasePlatform()->getName() != 'mysql', 'Migration can only be executed safely on \'mysql\'.');

        $this->addSql('CREATE TABLE flowers (id INT AUTO_INCREMENT NOT NULL, user_id INT DEFAULT NULL, flower_type_id INT DEFAULT NULL, flower_graphic_set_id INT DEFAULT NULL, last_breed_at DATETIME DEFAULT NULL, state ENUM(\'seed\', \'germ\', \'mature\') NOT NULL, created_at DATETIME DEFAULT NULL, updated_at DATETIME DEFAULT NULL, INDEX IDX_7DAF2300A76ED395 (user_id), INDEX IDX_7DAF2300818FFC14 (flower_type_id), INDEX IDX_7DAF23004BB6826F (flower_graphic_set_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB');
    }

    /**
     * @param Schema $schema
     */
    public function down(Schema $schema)
    {
        // this down() migration is auto-generated, please modify it to your needs
        $this->abortIf($this->connection->getDatabasePlatform()->getName() != 'mysql', 'Migration can only be executed safely on \'mysql\'.');

        $this->addSql('ALTER TABLE flowers DROP FOREIGN KEY FK_7DAF23004BB6826F');
        $this->addSql('ALTER TABLE flowers DROP FOREIGN KEY FK_7DAF2300818FFC14');
        $this->addSql('ALTER TABLE flowers DROP FOREIGN KEY FK_7DAF2300A76ED395');
        $this->addSql('DROP TABLE flowers');
    }
}

fkrauthan avatar Jan 10 '17 18:01 fkrauthan

After doctrine generated this migration file for your, have you edited it manually?

fre5h avatar Jan 10 '17 18:01 fre5h

The original file no. I just did some changes before posting it here (removed some tables that where part of this migration).

fkrauthan avatar Jan 10 '17 18:01 fkrauthan

The reason why you always get ENUMs on migration diff is that in your first migration missed the comment for ENUM column(s). It should look like this

status ENUM ('unsent', 'sending', 'sent', 'canceled', 'error') NOT NULL COMMENT (DC2Type:NotificationStatusType)

If Doctrine finds this comment, then it excludes this field on migration diff.

The question is why Doctrine didn't generate comment for your MariaDB. Maybe there is another syntax for it in MariaDB or something else. Need to investigate. By the way what database driver do you use? E.g.

parameters:
    database_driver: pdo_mysql

fre5h avatar Jan 10 '17 19:01 fre5h

I use pdo_mysql as my database_driver. And it looks like the SQL generated never added that COMMENT part to the statement. Therefor the database never executed it. MySQL and MariaDB are syntax equal if it comes to things like that. So it seems like somewhere in the code there is a compatibility check that does not work correctly?

fkrauthan avatar Jan 10 '17 19:01 fkrauthan

Is there a better way to just detect the type instead of having to use a comment from your bundles point of view?

fkrauthan avatar Jan 10 '17 19:01 fkrauthan

Doctrine always use comments for custom type (enums, json, array, etc.). So the only way is to find why comments are not generated in your case. What version of my bundle do you use?

fre5h avatar Jan 10 '17 19:01 fre5h

And also what version of Doctrine?

fre5h avatar Jan 10 '17 19:01 fre5h

Here are the versions out of my composer.lock file.

doctrine/doctrine-bundle: 1.6.4 doctrine/orm: 2.5.6

doctrine/doctrine-migrations-bundle: 1.2.1 doctrine/migrations: 1.5.0

fresh/doctrine-enum-bundle: 4.8.1

fkrauthan avatar Jan 10 '17 19:01 fkrauthan

OK, thanks https://github.com/fre5h/DoctrineEnumBundle/blob/master/DBAL/Types/AbstractEnumType.php#L72 This a function which adds correct ENUM syntax for specific platform. As you can see there is no adding of comment. Comments to database columns are added by Doctrine. So it is not a problem of my bundle, because its generated correct syntax for platform. Something wrong is with Doctrine in your case.

Can you for example install MySQL and create migration for it to check what happens.

fre5h avatar Jan 10 '17 19:01 fre5h

Is this a doctrine orm or a doctrine-bundle issue? I will open a issue in there bug tracker and reference this issue.

fkrauthan avatar Jan 10 '17 20:01 fkrauthan

It is a Doctrine DBAL job to create a proper SQL for platform. https://github.com/doctrine/dbal/tree/master/lib/Doctrine/DBAL/Platforms

fre5h avatar Jan 10 '17 20:01 fre5h

You can debug MySqlPlatform in the place where comments should be added. Maybe there you can find something new.

fre5h avatar Jan 10 '17 20:01 fre5h

@fkrauthan Hey, have you fixed it?

fre5h avatar Feb 11 '17 09:02 fre5h

@fre5h No it is still an issue. Started debugging with the help from the DBAL people but so far no luck. It seems like it is not detecting that type to be commented.

fkrauthan avatar Feb 20 '17 01:02 fkrauthan

This is definitely a migrations issue. I created a custom type and it was having the same problems, with the comments. I looked here to see if this would solve it before going through the effort of conversion.

smcjones avatar Apr 10 '17 22:04 smcjones

Hello guys! I have the same behavior here. Did you found a solution since then ?

adrienlamotte avatar Mar 20 '18 13:03 adrienlamotte

Would also love a solution to this. Once this is fixed and out of the way, migrations will be perfect.

spacetraveller avatar Apr 10 '18 16:04 spacetraveller

It this related to a collation check? Every diff all my CHAR fields are altered and I notice that the down function will reset the collation for those fields.

For example:

public function up(Schema $schema) : void
    $this->addSql('ALTER TABLE `my_table` CHANGE my_field my_fied CHAR(32) NOT NULL');
}

public function down(Schema $schema) : void
    $this->addSql('ALTER TABLE `my_table` CHANGE my_field my_fied CHAR(32) NOT NULL COLLATE utf8mb4_unicode_ci');
}

MySQL 5.7.19, default collation: utf8mb4_unicode_ci Doctrine migrations: 1.8.1

thuijzer avatar Oct 15 '18 09:10 thuijzer

Hi, I'm also having this issue. Any news about it?

nuil avatar Jan 14 '20 13:01 nuil

Same... any solutions yet?

codepushr avatar Jul 15 '20 19:07 codepushr

in the same boat. any ideas?

pculka avatar Jul 20 '20 11:07 pculka

Same problem here, probably the tag of this issue should be bug instead question.

Gonzalo1987 avatar Jul 27 '20 09:07 Gonzalo1987

anyone solved it ?

deansoffer avatar Nov 12 '20 13:11 deansoffer

@deansoffer didn't solve the root cause but in my case defining a default value stops the ongoing generation of migrations

not working:

@ORM\Column(type="string", length=255, columnDefinition="enum('invoice', 'delivery')")

working:

@ORM\Column(type="string", length=255, columnDefinition="enum('invoice', 'delivery')", options={"default":"invoice"})
doctrine:
    dbal:
        mapping_types:
            enum: string

"doctrine/migrations": 3.0.1

adriankirchner avatar Nov 12 '20 14:11 adriankirchner

@adriankirchner well such random behavior screams BUG. GIven how ENUMs are common types in DB, I wonder why this has not been addressed yet? I still have this bug with doctrine/doctrine-migrations-bundle 3.1.1

michnovka avatar May 30 '21 17:05 michnovka

Problem SOLVED.

doctrine:
    dbal:
        mapping_types:
            enum: string
        types:
            user_status_enum: App\Enum\UserStatusEnum
use Doctrine\DBAL\Types\Type;

class UserStatusEnum extends Type
{
   public function getName(): string
   {
       return 'user_status_enum';
   }

   public function requiresSQLCommentHint(AbstractPlatform $platform): bool
   {
       return true;
   }
}

kirya-dev avatar Jun 14 '21 10:06 kirya-dev

Thanks @kyria-dev, your solution is working for me

IronXtreme avatar Aug 06 '21 07:08 IronXtreme

Hi! I am running into same, although I do not use your bundle... I am working on an automated Enum field, with one EnumType, using the $enumType property of Doctrine's column annotation class. The problem is, that Doctrine compares the existing schema and the defined schema by entities. Therefore the comment is placed in the database, but it does not match since the ENUM values are not yet generated since the $enumType is not loaded then. Quite difficult to explain. But when I debug the EnumType class, it visits twice (once for the db-schema & once for the desired entity schema -> when the $enumType is set).

bertoost avatar Dec 20 '22 12:12 bertoost