Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Include enum changes in doctrine migration #135

Open
flaushi opened this issue Sep 18, 2018 · 7 comments
Open

Include enum changes in doctrine migration #135

flaushi opened this issue Sep 18, 2018 · 7 comments

Comments

@flaushi
Copy link

flaushi commented Sep 18, 2018

Hi!

Suppose I add or remove an option from my enum.

When creating a doctrine migration, this change is not included in the migration. Do I have to do this manually?
Example:
before

final class EnumActionType extends AbstractEnumType {
    
    const LOGIN = 'login';
    const CREATE_USER = 'createUser';
    const CHANGE_PASSWORD = 'changePw';
   
    protected static $choices = [ 
        self::LOGIN =>'Nutzer angemeldet',
        self::CREATE_USER =>'Neuen Nutzer erzeugt',
        self::CHANGE_PASSWORD => 'Passwort geändert'];
}

after:

final class EnumActionType extends AbstractEnumType {
    
    const LOGIN = 'login';
    const CREATE_USER = 'createUser';
    const CHANGE_PASSWORD = 'changePw';
    const NEW_VAL = 'newVal';

    protected static $choices = [ 
        self::LOGIN =>'Nutzer angemeldet',
        self::CREATE_USER =>'Neuen Nutzer erzeugt',
        self::CHANGE_PASSWORD => 'Passwort geändert',
        self::NEW_VAL => 'Neuer Wert'];
}

The automatically created migration by doctrine:migrations:diff does not care about this change.
What would be necessary is to first drop each CHECK-constraint, and then recreate it with the new set of enum values:

for postgres:

$values = \implode(
            ', ',
            \array_map(
                function ($value) {
                    return "'{$value}'";
                },
                EnumActionType::getValues()
                )
            );
        $this->addSql('ALTER TABLE action_log_entry DROP CONSTRAINT action_log_entry_action_check');
        $this->addSql("ALTER TABLE action_log_entry ADD CONSTRAINT action_log_entry_action_check CHECK(action IN ($values))");

for MS SQL Server:

$stmt = $this->connection->prepare("SELECT OBJECT_NAME(object_id) AS ConstraintName FROM sys.objects WHERE type_desc='CHECK_CONSTRAINT' AND OBJECT_NAME(parent_object_id)='action_log_entry'");
        $stmt->execute();
        $values = \implode(
            ', ',
            \array_map(
                function ($value) {
                    return "'{$value}'";
                },
                EnumActionType::getValues()
                )
            );
        foreach($stmt->fetchAll() as $row) {
            $this->addSql("ALTER TABLE action_log_entry DROP CONSTRAINT {$row['ConstraintName']}");
            $this->addSql("ALTER TABLE action_log_entry ADD CONSTRAINT {$row['ConstraintName']} CHECK(action IN ($values))");
        }

However, I would additionally have to find all usages of the enum in my entities manually.

I think automating this would be great !?

@flaushi
Copy link
Author

flaushi commented Oct 18, 2018

Thanks a lot for this hint, however it only works for MySQL. In postgres and mssql, this check is realized in a different way: there is a named check or constraint (c.f. action_log_entry_action_check see above), and the migration would have to look up this name, drop the check and then create the new one.

@wbrframe
Copy link

wbrframe commented Jun 21, 2019

At the database level, all constraints are stored in the context of a table, not a specific field.
Get all constraints of type CHECK can be next SQL:

SELECT con.*
       FROM pg_catalog.pg_constraint con
            INNER JOIN pg_catalog.pg_class rel
                       ON rel.oid = con.conrelid
            INNER JOIN pg_catalog.pg_namespace nsp
                       ON nsp.oid = connamespace
       WHERE nsp.nspname = '<schema_name>' AND rel.relname = '<table_name>' AND con.contype = 'c';

In the results, you can see the real name of the constraint for your column.
This will allow us to write the correct migration.

ALTER TABLE <table_name> DROP CONSTRAINT <constraint_name>;
ALTER TABLE <table_name> ADD CONSTRAINT <constraint_name> CHECK(action IN ('newValue', 'value1', 'value2', 'value3'));

Also, don't forget to implement down method for new migration.
Alters must contain the previous type list.

 -- without newValue
ALTER TABLE <table_name> DROP CONSTRAINT <constraint_name>;
ALTER TABLE <table_name> ADD CONSTRAINT <constraint_name> CHECK(action IN ('value1', 'value2', 'value3'));

@fre5h
Copy link
Owner

fre5h commented Apr 29, 2021

To drop comments use this command doctrine:enum:drop-comment CustomType

@nkl90
Copy link

nkl90 commented Nov 16, 2021

@fre5h, thank you very much for your work! And this command:)

@tguenneguez
Copy link

On which version doctrine:enum:drop-comment is avalaible ?
Y don't find it.

Thanks
Thomas

@fre5h
Copy link
Owner

fre5h commented Jan 23, 2023

@tguenneguez It is available since bundle version 7.3.0 https://github.com/fre5h/DoctrineEnumBundle/releases/tag/v7.3.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants