PHPackages                             shipmonk/doctrine-two-phase-migrations - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. shipmonk/doctrine-two-phase-migrations

ActiveLibrary[Database &amp; ORM](/categories/database)

shipmonk/doctrine-two-phase-migrations
======================================

Two phase migrations for Doctrine ORM: before and after deploying new codebase version

0.7.1(2mo ago)2549.3k↑51.3%[2 issues](https://github.com/shipmonk-rnd/doctrine-two-phase-migrations/issues)MITPHPPHP ^8.2CI passing

Since Feb 17Pushed 1mo ago2 watchersCompare

[ Source](https://github.com/shipmonk-rnd/doctrine-two-phase-migrations)[ Packagist](https://packagist.org/packages/shipmonk/doctrine-two-phase-migrations)[ RSS](/packages/shipmonk-doctrine-two-phase-migrations/feed)WikiDiscussions master Synced today

READMEChangelog (10)Dependencies (36)Versions (21)Used By (0)

Two-phase migrations for Doctrine
---------------------------------

[](#two-phase-migrations-for-doctrine)

This lightweight library allows you to perform safer Doctrine migrations during deployment in cluster-based environments like kubernetes where rolling-update takes place. Each migration has two *up* phases, no *down* phase.

- **before**
    - to be called before any traffic hits the new application version
    - typically contains ADD COLUMN etc.
- **after**
    - to be called after the deployment is done and no traffic is hitting the old application version
    - typically contains DROP COLUMN etc.

You can see [Czech talk about this library on YouTube](https://youtu.be/7OVO8itXUt0?t=3380).

### Installation:

[](#installation)

```
composer require shipmonk/doctrine-two-phase-migrations
```

### Configuration in Symfony application:

[](#configuration-in-symfony-application)

Register the bundle in `config/bundles.php`:

```
return [
    // ...
    ShipMonk\Doctrine\Migration\Bridge\Symfony\TwoPhaseMigrationsBundle::class => ['all' => true],
];
```

Then configure it in `config/packages/two_phase_migrations.yaml`:

```
two_phase_migrations:
    migrations_dir: '%kernel.project_dir%/migrations'

    # optional parameters:
    # migration_table_name: 'doctrine_migration'
    # migration_class_namespace: 'YourCompany\Migrations'
    # migration_class_prefix: 'Migration'
    # excluded_tables: ['my_tmp_table']
    # template_file_path: '%kernel.project_dir%/migrations/my-template.txt'
    # template_indent: "\t\t"
    # lock_timeout_seconds: 300 # how long migration:run waits for a lock held by a parallel run before failing
```

The bundle requires `symfony/http-kernel` ^6.4+. All commands and services are registered automatically, and `Doctrine\ORM\EntityManagerInterface` is autowired. If you register a custom `MigrationExecutor`, `MigrationAnalyzer`, or `MigrationVersionProvider` service, it will be picked up automatically.

All commands accept an optional `Psr\Log\LoggerInterface`. When a logger is available (e.g. via MonologBundle), structured log messages with context are emitted. When no logger is injected, commands fall back to `Symfony\Component\Console\Logger\ConsoleLogger` and write directly to the console output.

Manual service registration (without the bundle)If your `Doctrine\ORM\EntityManagerInterface` is autowired, just register few services in your DIC and tag the commands:

```
_instanceof:
    Symfony\Component\Console\Command\Command:
        tags:
            - console.command

services:
    ShipMonk\Doctrine\Migration\Command\MigrationInitCommand:
    ShipMonk\Doctrine\Migration\Command\MigrationRunCommand:
    ShipMonk\Doctrine\Migration\Command\MigrationSkipCommand:
    ShipMonk\Doctrine\Migration\Command\MigrationCheckCommand:
    ShipMonk\Doctrine\Migration\Command\MigrationGenerateCommand:
    ShipMonk\Doctrine\Migration\MigrationService:
    ShipMonk\Doctrine\Migration\MigrationConfig:
        $migrationsDir: "%kernel.project_dir%/migrations"

    # more optional parameters:
        $migrationClassNamespace: 'YourCompany\Migrations'
        $migrationTableName: 'doctrine_migration'
        $migrationClassPrefix: 'Migration' # will be appended with date('YmDHis') by default
        $excludedTables: ['my_tmp_table'] # migration table ($migrationTableName) is always added to excluded tables automatically
        $templateFilePath: "%kernel.project_dir%/migrations/my-template.txt" # customizable according to your coding style
        $templateIndent: "\t\t" # defaults to spaces
        $lockTimeoutSeconds: 300 # how long migration:run waits for a lock held by a parallel run before failing
```

### Commands:

[](#commands)

#### Initialization:

[](#initialization)

After installation, you need to create `migration` table in your database. It is safe to run it even when the table was already initialized. When upgrading from `1.x`, running it once also upgrades the existing table to the new schema (it makes `finished_at` nullable, see [Concurrency &amp; execution safety](#concurrency--execution-safety)). Only that single column is altered, so it is safe to run against a populated table.

```
$ bin/console migration:init

# example output:
[info] Initializing migration table doctrine_migration
[info] Migration table doctrine_migration created successfully
```

#### Generating new migration:

[](#generating-new-migration)

You can generate migration from database &lt;=&gt; entity diff automatically. This puts all the queries generated by Doctrine to before stage, which will NOT be correct for any destructive actions. Be sure to verify the migration and move the queries to proper stage or adjust them. When no diff is detected, empty migration class is generated.

```
$ bin/console migration:generate

# example output:
[info] Starting migration generation
[info] 1 schema changes detected
[info] Migration version 20230217063818 generated successfully
```

The generated file then looks like this:

```
