在symfony中用DoctrineMigrationsBundle处理数据库迁移的详细指南

116 阅读2分钟

DoctrineMigrationsBundle帮助我们将实体的变化反映到数据库中,这样我们就不需要手动操作了。它将你的实体与你的数据库进行比较,因此在运行diff 命令后,你的实体中的任何更新都会出现在你的迁移文件中。它的工作方式如下:

  • 如果数据库中有一个表,但是你在应用程序中删除了它的实体类,那么迁移也会在数据库中删除这个表。

  • 如果你在你的应用程序中创建了一个新的实体,但是它的表在数据库中还不存在,迁移也会创建相关的表。

  • 如果你对你的应用程序中的一个实体做了任何改动,迁移也会更新数据库中的相关表。

这里的关键点是,在你运行diff 命令来创建迁移文件之前,要确保这些变化还没有在数据库中出现,否则diff 命令将无法看到这些变化,最终你将得到一个空的迁移文件。

注意:如果你是第一次运行迁移过程,迁移命令将在数据库中创建migration_versions 表。之后,它将在其中插入迁移版本。

我们的例子

我在数据库中有一个app_user 表,但是在我的应用程序中删除了AppUser 实体,所以迁移时也应该删除数据库中的app_user 表。然后我在我的应用程序中添加了一个新的实体,叫做Customer ,但是这个表在数据库中还不存在,所以迁移也应该在数据库中创建customer 表。

编译器

运行composer require doctrine/doctrine-migrations-bundle "^1.3" ,安装DoctrineMigrationsBundle,并在AppKernel.php文件中添加new Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle(),

配置

#config.yml
doctrine_migrations:
    dir_name: "%kernel.root_dir%/DoctrineMigrations"
    namespace: CustomerBundle
    table_name: migration_versions
    name: Application Migrations
    organize_migrations: false

数据库

目前我们在数据库中只有app_user 表。

mysql> SHOW TABLES;
+------------------+
| Tables_in_common |
+------------------+
| api_user         |
+------------------+
1 row in set (0.00 sec)

客户实体

创建以下实体。我删除了注释、设置器和获取器方法,以保持代码的简短,但显然你必须拥有它们。

namespace CustomerBundle\Entity;

class Customer
{
    private $id;
    private $name;
    private $dob;
}

创建迁移文件

$ php bin/console doctrine:migrations:diff
Generated new migration class to "/var/www/html/symfony/common/app/DoctrineMigrations/Version20171208210144.php" from schema differences.
$ cat app/DoctrineMigrations/Version20171208210144.php

namespace CustomerBundle;

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

/**
 * Auto-generated Migration: Please modify to your needs!
 */
class Version20171208210144 extends AbstractMigration
{
    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 customer (id INT AUTO_INCREMENT NOT NULL, name VARCHAR(50) NOT NULL, dob DATETIME NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB');
        $this->addSql('DROP TABLE api_user');
    }

    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('CREATE TABLE api_user (id INT AUTO_INCREMENT NOT NULL, api_key VARCHAR(36) NOT NULL COLLATE utf8_unicode_ci, roles LONGTEXT NOT NULL COLLATE utf8_unicode_ci COMMENT \'(DC2Type:array)\', UNIQUE INDEX unq_api_key (api_key), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB');
        $this->addSql('DROP TABLE customer');
    }
}

执行迁移

$ php bin/console doctrine:migrations:migrate --no-interaction
                                                              
                    Application Migrations                    
                                                              

Migrating up to 20171208210144 from 0

  ++ migrating 20171208210144

     -> CREATE TABLE customer (id INT AUTO_INCREMENT NOT NULL, name VARCHAR(50) NOT NULL, dob DATETIME NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB
     -> DROP TABLE api_user

  ++ migrated (0.41s)

  ------------------------

  ++ finished in 0.41s
  ++ 1 migrations executed
  ++ 2 sql queries

数据库

mysql> SHOW TABLES;
+--------------------+
| Tables_in_common   |
+--------------------+
| customer           |
| migration_versions |
+--------------------+
2 rows in set (0.01 sec)

mysql> SELECT * FROM migration_versions;
+----------------+
| version        |
+----------------+
| 20171208210144 |
+----------------+
1 row in set (0.00 sec)

mysql> SELECT * FROM customer;
Empty set (0.01 sec)