Technical Documentation: doctrine/DoctrineMigrationsBundle
โน๏ธ Provenance: Multi-Tier Ingestion ยท CodeWiki Reference
Index (`docs/index.rst`)
DoctrineMigrationsBundle
Database migrations are a way to safely update your database schema both locally
and on production. Instead of running the doctrine:schema:update command or
applying the database changes manually with SQL statements, migrations allow to
replicate the changes in your database schema in a safe manner.
Migrations are available in Symfony applications via the DoctrineMigrationsBundle,
which uses the external Doctrine Database Migrations library. Read thedocumentation_ of that library if you need a general introduction about migrations.
Installation
Run this command in your terminal:
.. code-block:: terminal
$ composer require doctrine/doctrine-migrations-bundleIf you don't use Symfony Flex_, you must enable the bundle manually in the application:
.. code-block:: php
// config/bundles.php
return [
// ...
Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true],
];Configuration
If you use Symfony Flex, the doctrine_migrations.yaml config file is created
automatically. Otherwise, create the following file and configure it for your
application:
.. code-block:: yaml
# config/packages/doctrine_migrations.yaml
doctrine_migrations:
# Whether to enable fetching migrations from the service container.
enable_service_migrations: false
# List of namespace/path pairs to search for migrations, at least one required
migrations_paths:
'App\Migrations': '%kernel.project_dir%/src/Migrations'
'AnotherApp\Migrations': '/path/to/other/migrations'
'SomeBundle\Migrations': '@SomeBundle/Migrations'
# List of additional migration classes to be loaded, optional
migrations:
- 'App\Migrations\Version123'
- 'App\Migrations\Version123'
# Connection to use for the migrations
connection: default
# Entity manager to use for migrations. This overrides the "connection" setting.
em: default
storage:
# Default (SQL table) metadata storage configuration
table_storage:
table_name: 'doctrine_migration_versions'
version_column_name: 'version'
version_column_length: 192
executed_at_column_name: 'executed_at'
# Possible values: "BY_YEAR", "BY_YEAR_AND_MONTH", false
organize_migrations: false
# Path to your custom migrations template
custom_template: ~
# Run all migrations in a transaction.
all_or_nothing: false
# Adds an extra check in the generated migrations to ensure that is executed on the same database type.
check_database_platform: true
# Whether or not to wrap migrations in a single transaction.
transactional: true
# Whether or not to enable the profiler collector to calculate and visualize migration status. This adds some queries overhead.
# enable_profiler: false
services:
# Custom migration sorting service id
'Doctrine\Migrations\Version\Comparator': ~
# Custom migration classes factory
'Doctrine\Migrations\Version\MigrationFactory': ~
factories:
# Custom migration sorting service id via callables (MyCallableFactory must be a callable)
'Doctrine\Migrations\Version\Comparator': 'MyCallableFactory'- The
servicesnode allows you to provide custom services to the underlyingDependencyFactorypart ofdoctrine/migrations. - The node
factoriesis similar toservices, with the difference that it accepts only callables.
The provided callable must return the service to be passed to the DependencyFactory.
The callable will receive as first argument the DependencyFactory itself,
allowing you to fetch other dependencies from the factory while instantiating your custom dependencies.
Usage
All of the migrations functionality is contained in a few console commands:
.. code-block:: terminal
doctrine
doctrine:migrations:current [current] Outputs the current version.
doctrine:migrations:diff [diff] Generate a migration by comparing your current database to your mapping information.
doctrine:migrations:dump-schema [dump-schema] Dump the schema for your database to a migration.
doctrine:migrations:execute [execute] Execute a single migration version up or down manually.
doctrine:migrations:generate [generate] Generate a blank migration class.
doctrine:migrations:latest [latest] Outputs the latest version number
doctrine:migrations:migrate [migrate] Execute a migration to a specified version or the latest available version.
doctrine:migrations:rollup [rollup] Roll migrations up by deleting all tracked versions and inserting the one version that exists.
doctrine:migrations:status [status] View the status of a set of migrations.
doctrine:migrations:up-to-date [up-to-date] Tells you if your schema is up-to-date.
doctrine:migrations:version [version] Manually add and delete migration versions from the version table.
doctrine:migrations:sync-metadata-storage [sync-metadata-storage] Ensures that the metadata storage is at the latest version.
doctrine:migrations:list [list-migrations] Display a list of all available migrations and their status.Start by getting the status of migrations in your application by running
the status command:
.. code-block:: terminal
$ php bin/console doctrine:migrations:statusThis command will show you generic information about the migration status, such as how many migrations have been
already executed, which still need to run, and the database in use.
Now, you can start working with migrations by generating a new blank migration
class. Later, you'll learn how Doctrine can generate migrations automatically
for you.
.. code-block:: terminal
$ php bin/console doctrine:migrations:generateHave a look at the newly generated migration class and you will see something
like the following:
.. code-block:: php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20180605025653 extends AbstractMigration
{
public function getDescription() : string
{
return '';
}
public function up(Schema $schema) : void
{
// this up() migration is auto-generated, please modify it to your needs
}
public function down(Schema $schema) : void
{
// this down() migration is auto-generated, please modify it to your needs
}
}If you run the status command again it will now show that you have one new
migration to execute:
.. code-block:: terminal
$ php bin/console doctrine:migrations:statusNow you can add some migration code to the up() and down() methods and
finally migrate when you're ready:
.. code-block:: terminal
$ php bin/console doctrine:migrations:migrate 'DoctrineMigrations\Version20180605025653'For more information on how to write the migrations themselves (i.e. how to
fill in the up() and down() methods), see the official Doctrine Migrationsdocumentation_.
Running Migrations during Deployment
Of course, the end goal of writing migrations is to be able to use them to
reliably update your database structure when you deploy your application.
By running the migrations locally (or on a beta server), you can ensure that
the migrations work as you expect.
When you do finally deploy your application, you just need to remember to run
the ``doctrine:migrations:migrate`` command. Internally, Doctrine creates
a ``doctrine_migration_versions`` table inside your database and tracks which migrations
have been executed there. So, no matter how many migrations you've created
and executed locally, when you run the command during deployment, Doctrine
will know exactly which migrations it hasn't run yet by looking at the ``doctrine_migration_versions``
table of your production database. Regardless of what server you're on, you
can always safely run this command to execute only the migrations that haven't
been run yet on *that* particular database.
Skipping Migrations
~~~~~~~~~~~~~~~~~~~
You can skip single migrations by explicitly adding them to the ``doctrine_migration_versions`` table:
.. code-block:: terminal
$ php bin/console doctrine:migrations:version 'App\Migrations\Version123' --add
.. tip::
Pay attention to the single quotes (``'``) used in the command above, without them
or with the double quotes (``"``) the command will not work properly.
Doctrine will then assume that this migration has already been run and will ignore it.
Migration Dependencies
----------------------
Migrations can have dependencies on external services (such as geolocation, mailer or data processing services) to
enable more advanced behavior. To inject dependencies into your migrations, you must enable loading migrations from
the service container and register the migrations as services.
If you are using Symfony's default service configuration, migration services are registered automatically
once placed in the ``src`` directory:
.. configuration-block::
.. code-block:: yaml
# config/packages/doctrine_migrations.yaml
doctrine_migrations:
enable_service_migrations: true
migrations_paths:
'App\Migrations': '%kernel.project_dir%/src/Migrations'
If you are not using the default configuration, register your migration classes manually and make sure they are
discoverable by the autoloader. If autoconfiguration is disabled, tag them manually with
the ``doctrine_migrations.migration`` tag:
.. configuration-block::
.. code-block:: yaml
# config/services.yaml
services:
DoctrineMigrations\Version20180605025653:
tags: [ 'doctrine_migrations.migration' ]
arguments:
$myService: '@App\Services\MyService'
The connection and logger services are injected automatically through bindings. You may specify them explicitly
if needed:
.. configuration-block::
.. code-block:: yaml
# config/services.yaml
services:
DoctrineMigrations\Version20180605025653:
tags: [ 'doctrine_migrations.migration' ]
arguments:
- '@doctrine.migrations.connection'
- '@doctrine.migrations.logger'
- '@App\Services\MyService'
Then override the constructor in your migration class and add your dependencies:
.. code-block:: php
declare(strict_types=1);
namespace App\Migrations;
use App\Services\MyService;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20180605025653 extends AbstractMigration
{
private MyService $myService;
public function __construct(Connection $connection, LoggerInterface $logger, MyService $myService)
{
parent::__construct($connection, $logger);
$this->myService = $myService;
}
// ...
}
Generating Migrations Automatically
-----------------------------------
In reality, you should rarely need to write migrations manually, as the migrations
library can generate migration classes automatically by comparing your Doctrine
mapping information (i.e. what your database *should* look like) with your
actual current database structure.
For example, suppose you create a new ``User`` entity and add mapping information
for Doctrine's ORM:
.. configuration-block::
.. code-block:: php-attributes
// src/Entity/User.php
namespace App\Entity;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
#[Entity]
#[Table(name: 'user')]
class User
{
#[ORM\Id]
#[ORM\GeneratedValue(strategy: 'AUTO')]
#[ORM\Column(type: Types::INTEGER)]
private $id;
#[ORM\Column(type: Types::STRING, length: 255)]
private $name;
.. code-block:: yaml
# config/doctrine/User.orm.yaml
App\Entity\User:
type: entity
table: user
id:
id:
type: integer
generator:
strategy: AUTO
fields:
name:
type: string
length: 255
.. code-block:: xml
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<entity name="App\Entity\User" table="user">
<generator strategy="AUTO"/>
<field name="name" column="name" type="string" length="255" />
</entity>
</doctrine-mapping>
With this information, Doctrine is now ready to help you persist your new
``User`` object to and from the ``user`` table. Of course, this table
doesn't exist yet! Generate a new migration for this table automatically by
running the following command:
.. code-block:: terminal
$ php bin/console doctrine:migrations:diff
You should see a message that a new migration class was generated based on
the schema differences. If you open this file, you'll find that it has the
SQL code needed to create the ``user`` table. Next, run the migration
to add the table to your database:
.. code-block:: terminal
$ php bin/console doctrine:migrations:migrate
The moral of the story is this: after each change you make to your Doctrine
mapping information, run the ``doctrine:migrations:diff`` command to automatically
generate your migration classes.
If you do this from the very beginning of your project (i.e. so that even
the first tables were loaded via a migration class), you'll always be able
to create a fresh database and run your migrations in order to get your database
schema fully up to date. In fact, this is an easy and dependable workflow
for your project.
If you don't want to use this workflow and instead create your schema via
``doctrine:schema:create``, you can tell Doctrine to skip all existing migrations:
.. code-block:: terminal
$ php bin/console doctrine:migrations:version --add --all
Otherwise Doctrine will try to run all migrations, which probably will not work.
Manual Tables Not Managed by Doctrine
-------------------------------------
In addition to your generated database structure based on your doctrine entities you might need some custom tables.
By default such tables will be marked for removal by the ``doctrine:migrations:diff`` command.
Here's how you can configure ``doctrine/dbal`` to ignore some tables:
.. configuration-block::
.. code-block:: yaml
# config/packages/doctrine.yaml
doctrine:
dbal:
schema_filter: ~^(?!t_)~ # Ignore all tables prefixed by `t_`
.. code-block:: xml
<doctrine:dbal schema-filter="~^(?!t_)~" />
.. code-block:: php
// config/packages/doctrine.php
$container->loadFromExtension('doctrine', array(
'dbal' => [
'schema_filter' => '~^(?!t_)~', // Ignore all tables prefixed by `t_`
// ...
],
// ...
));
This ignores the tables, and any named objects such as sequences, on the DBAL level and they will be ignored by the ``diff`` command.
Note that if you have multiple connections configured then the ``schema_filter`` configuration
will need to be placed per-connection.
Troubleshooting out of sync metadata storage issue
--------------------------------------------------
``doctrine/migrations`` relies on a properly configured Database server version in the connection string to manage the table storing the
migrations, also known as the metadata storage.
If you encounter the error ``The metadata storage is not up to date, please run the sync-metadata-storage command to fix this issue.``
when running the command ``doctrine:migrations:migrate`` or the suggested command itself ``doctrine:migrations:sync-metadata-storage`` please
check the database connection string, and make sure that the proper server version is defined. If you are running a MariaDB database,
you should prefix the server version with ``mariadb-`` (ex: ``mariadb-10.2.12``). See the `configuring_database`_ section.
Example connection string for MariaDB:
.. code-block:: terminal
DATABASE_URL=mysql://root:@127.0.0.1:3306/testtest?serverVersion=mariadb-10.4.11
.. _documentation: https://www.doctrine-project.org/projects/doctrine-migrations/en/current/index.html
.. _configuring_database: https://symfony.com/doc/current/doctrine.html#configuring-the-database
.. _DoctrineMigrationsBundle: https://github.com/doctrine/DoctrineMigrationsBundle
.. _`Doctrine Database Migrations`: https://github.com/doctrine/migrations
.. _`Symfony Flex`: https://symfony.com/doc/current/setup/flex.html
---
--- METRICS ---
- Files Extracted: 1
- Estimated Token Budget: ~4490 tokens
- Canonical Reference: https://codewiki.google/github.com/doctrine/DoctrineMigrationsBundle