Using Doctrine Migrations as a standalone tool
My current project has reached the point where a good migrations system is required. As I’m targeting two different database engines (MySQL and MS SQL Server) and we’re already using DBAL, it made sense to use Migrations from the Doctrine project.
To do this, I updated my composer.json with the following require statements:
"doctrine/migrations": "1.0.*@dev", "symfony/console": "~2.5"
in order to install Migrations and also Symfony console component so that I can run it from the command line.
The CLI script
Migrations doesn’t come with it’s own CLI script, so you have to create your own. Fortunately, we can tweak the supplied phar-cli-stub.php. I placed it in bin/migrations.php:
/** * Command line script to run Migrations * Inspired by phar-cli-stup.php */ use Symfony\Component\Console; use Doctrine\DBAL\Migrations\MigrationsVersion; use Doctrine\DBAL\Migrations\Tools\Console\Command as MigrationsCommand; require (__DIR__ . '/../vendor/autoload.php'); // Set current directory to application root so we can find config files chdir(__DIR__ . '/..'); // Instantiate console application $cli = new Console\Application('Doctrine Migrations', MigrationsVersion::VERSION()); $cli->setCatchExceptions(true); $helperSet = new Console\Helper\HelperSet(); $helperSet->set(new Console\Helper\DialogHelper(), 'dialog'); $cli->setHelperSet($helperSet); // Add Migrations commands $commands = array(); $commands[] = new MigrationsCommand\ExecuteCommand(); $commands[] = new MigrationsCommand\GenerateCommand(); $commands[] = new MigrationsCommand\LatestCommand(); $commands[] = new MigrationsCommand\MigrateCommand(); $commands[] = new MigrationsCommand\StatusCommand(); $commands[] = new MigrationsCommand\VersionCommand(); // remove the "migrations:" prefix on each command name foreach ($commands as $command) { $command->setName(str_replace('migrations:', '', $command->getName())); } $cli->addCommands($commands); // Run! $cli->run();
Note that, by default, the console commands are all prefixed with ‘migrations:’. This makes sense as usually they are integrated with the rest of the Doctrine ORM command line application and so it avoids any clashes. In this case, this script is only dealing with migrations and I don’t want to type more than I have to, so I remove the prefixes!
Configuration
Migrations requires two separate configuration files to work: migrations.yml and migrations-db.php. These need to be in the current directory, so I used chdir() to ensure that it is in a known location – the application root in this case.
migrations.yml is the config file that tells Migrations the names of things:
migrations.yml:
name: DBAL Migrations migrations_namespace: Migrations table_name: migration_versions migrations_directory: migrations
In my case, I want to use my migrations files to be in a directory called migrations and use the namespace Migrations. The database table name that Migrations uses to keep track of its internal status is called migration_versions. I’m not too imaginative when it comes to naming things!
migrations-db.php must return an array that is used to configure Doctrine\DBAL\DriverManager::getConnection()
migrations-db.php:
<?php return array( 'dbname' => 'albums', 'user' => 'rob', 'password' => '123456', 'host' => 'localhost', 'driver' => 'pdo_mysql', );
The documentation will help you find out what can go in here.
We’re now ready to go!
On the command line, php bin/migrations.php status should work:
$ php bin/migrations.php Doctrine Migrations version 2.0.0-DEV Usage: [options] command [arguments] Options: --help -h Display this help message. --quiet -q Do not output any message. --verbose -v|vv|vvv Increase the verbosity of messages --version -V Display this application version. --ansi Force ANSI output. --no-ansi Disable ANSI output. --no-interaction -n Do not ask any interactive question. Available commands: execute Execute a single migration version up or down manually. generate Generate a blank migration class. help Displays help for a command latest Outputs the latest version number list Lists commands migrate Execute a migration to a specified version or the latest available version. status View the status of a set of migrations. version Manually add and delete migration versions from the version table.
Creating a migration
run php bin/migrations.php generate and a new migration class will be created in the migrations directory. It has two methods: up() and down(). Both have an instance of Doctrine\DBAL\Schema\Schema passed and an you can do whatever you like in the function to manipulate your database to its next state. Again, the documentation is helpful!
For instance:
<?php namespace Migrations; use Doctrine\DBAL\Migrations\AbstractMigration; use Doctrine\DBAL\Schema\Schema; class Version20141027161210 extends AbstractMigration { public function up(Schema $schema) { $myTable = $schema->createTable('artists'); $myTable->addColumn('id', 'integer', ['unsigned' => true, 'autoincrement'=>true]); $myTable->addColumn('name', 'string', ['length' => 60]); $myTable->setPrimaryKey(['id']); } public function down(Schema $schema) { $schema->dropTable('artists'); } }
Running the migration
Simply run php bin/migrations.php migrate and Migrations will the up() method for all migration classes that haven’t be run yet. In this case it will create a table called artists and update the migration_versions table with the version number of ‘20141027161210’.
To back out of a migration, simple run php bin/migrations.php migration {version number} and Migrations will run the appropriate down() (or up()) methods to get to that version number.
Finally you can run php bin/migrations.php status to find out the current state.
On the whole, it turns out that it’s quite easy to use Migrations as a stand-alone tool outside of Doctrine ORM or Symfony!
Hi Rob,
Have you considered using Phinx (https://phinx.org) for your migrations? It supports both MySQL and SQL Server.
Cheers,
Rob