概要
SymfonyアプリでDBマイグレーションをやってくれる DoctrineMigrationsBundle の3系が2020年06月にリリースされました。
2系から3系へのメジャーバージョンアップ対応を記します
環境
- PHP
7.2
- Symfony
4.4
- DoctrineMigrationsBundle
2.1.2
-->3.0.1
- MySQL
5.6
本題
変更点等は UPGRADE.md に記されています
doctrine/doctrine-migrations-bundle
パッケージは
doctrine/migrations
パッケージを require しているので、こちらの UPGRADE.md も読んでおくといいかもです
要点としては以下です
-
『マイグレーションテーブルの更新』
- テーブル名: これまで
migration_versions
がデフォルトでしたが、doctrine_migration_versions
がデフォルトになります(設定で変更可能) - カラム
-
version
: これまで20200601000000
のようにYmdHis
フォーマットでしたが、3系からはFQCN
(Fully Qualified Class Name)になります -
execution_time
: 新規に追加されます。マイグレーションにかかった時間を格納するようです。既存のexecuted_at
(マイグレーションを適用した日時)とは別カラムになります
-
- テーブル名: これまで
- 『Code BC Breaks』
- いくつかのクラスが final classになっていたり、削除されていたりします
『Code Bc Breaks』 については、各自のアプリケーションでの実装次第となりそうなので、
final classになったものについては継承する形式をやめて construct で内包する形に変更するなどの対応になるかと思います。
この記事では、
共通してつまづきそうな『マイグレーションテーブルの更新』について記します。
『マイグレーションテーブルの更新』に合わせて、 doctrine_migrtions
の設定方法が変わりました
変更点は主に以下の2つです
- マイグレーションファイルのディレクトリ・namespaceの設定方法の変更
- マイグレーションテーブルの設定方法の変更
マイグレーションファイルのディレクトリ・namespaceの設定方法の変更
マイグレーションファイルを保存してあるディレクトリに合わせて以下の設定を加えます
After は、デフォルトの値になるので、各自アプリケーションでのディレクトリ・namespaceに合わせて設定する必要があります
デフォルトと異なる場合、合わせて指定してあげないと「マイグレーションファイルが存在しない」と認識されエラーになります
Before ※ 元々、設定がない場合もあります
doctrine_migrations:
dir_name: '%kernel.project_dir%/src/Migrations'
namespace: DoctrineMigrations
After
doctrine_migrations:
migrations_paths:
DoctrineMigrations: '%kernel.project_dir%/src/Migrations'
# 👆 ここが {namespace}: {dir_name} となるように設定します
例えば、以下のようなファイル構成と namespace であれば、デフォルトのままで問題ないですが、
どちらかでもカスタムしていれば合わせて設定してください
% tree ./path_to_app/src
..
├── Migrations # 👈 {dir_name} として設定
│ ├── Version20200601000000.php
│ ├── Version20200602000000.php
..
namespace DoctrineMigrations; # 👈 {namespace} として設定
final class Version20200601000000 extends AbstractMigration
{
..
マイグレーションテーブルの設定方法の変更
次にマイグレーションテーブルの設定方法も変更になりました。
デフォルトのテーブル名が migration_versions
から doctrine_migration_versions
に変わったので、
既存のマイグレーションテーブルをそのまま使うのであれば、指定してあげる必要があります。
Before ※ 元々、設定がない場合もあります
doctrine_migrations:
table_name: 'migration_versions'
column_name: 'version'
column_length: 14
executed_at_column_name: 'executed_at'
After
doctrine_migrations:
storage:
table_storage:
table_name: 'migration_versions' # 注意①
version_column_name: 'version' # 元々、versionsカラムであれば指定しなくても大丈夫です
version_column_length: 191 # 注意②
executed_at_column_name: 'executed_at' # 元々、executed_atカラムであれば指定しなくても大丈夫です
注意① table_name
3系からデフォルトのマイグレーションテーブルのテーブル名は doctrine_migration_versions
に変更されます。
おそらく(?)みなさんのマイグレーションテーブルのテーブル名は指定して作成していなければ migration_versions
のはずなので、
3系からは設定で指定してあげる必要があります。
そうとは知らず、省略していると、 doctrine_migration_versions
テーブルが新規作成され、1からマイグレーションが実行されてしまうので注意してください
注意② version_column_length
3系から version
カラムに入る値は 20200601000000
のように YmdHis
フォーマットではなく FQCN になります。
2系のカラム長のデフォルト値 14
のままでは、 FQCN が入り切らない可能性があるため、3系では増えました。
UPGRADE.md に記載のあるように 1024
を設定しまうと、 MySQL 5.6 ではエラーになってしまうので注意してください
理由は、MySQL 5.6の単一カラムのインデックスキーは 767byte
までしか指定できないからです。
なので 191
(191文字 * 4byte = 764byte < 767byte) ※ 4byte文字を考慮
execution_time
カラムが追加されたこともあり、マイグレーションテーブルの2系と3系でどう変わるのか?は実際のデータを見てもらうのが早いので、以下に示します
2系
mysql> select * from migration_versions;
+----------------+---------------------+
| version | executed_at |
+----------------+---------------------+
| 20200601000000 | 2020-06-01 00:01:00 |
| 20200602000000 | 2020-06-02 00:01:00 |
..
3系
mysql> select * from migration_versions;
+------------------------------------------+---------------------+----------------+
| version | executed_at | execution_time |
+------------------------------------------+---------------------+----------------+
| DoctrineMigrations\Version20200601000000 | 2020-06-01 00:01:00 | 11 |
| DoctrineMigrations\Version20200602000000 | 2020-06-02 00:01:00 | 12 |
..
doctrine:migrations:migrate
または doctrine:migrations:execute
実行時に、
3系のマイグレーションテーブルへ更新されます
execution_time
カラムが追加されるだけではなく、
適用済みのマイグレーションの version
の値についても、 FQCN への更新がされます!
1からマイグレーションが再実行されるわけではないのでご安心を。
以上で、『マイグレーションテーブルの更新』まわりでのメジャーバージョンアップ対応は完了になります。
ほとんどのケースで、これで対応完了になるのではないかと思っております
マイグレーションファイルでサービスコンテナを利用している場合
ここからは、少しレアケースで、なんらかの理由でマイグレーションファイルでサービスコンテナを利用している場合、
追加で対応してあげる必要があります
これまでは、以下のように ContainerAwareInterface
を implements して use ContainerAwareTrait
を宣言すれば、
自動でサービスコンテナがセットされていました。
が、3系からは自動でセットされません
class Version20200601000000 extends AbstractMigration implements ContainerAwareInterface
{
use ContainerAwareTrait;
対応方法はこちらの Migration Dependencies
に記載されています
マイグレーション実行時にマイグレーションインスタンスの生成を
MigrationFactory
経由で生成しているところを、これを装飾した MigrationFactoryDecorator
経由に変更する(エイリアスをはる)ことで、
デコレータの装飾部分で ContainerAwareInterface
のインスタンスであれば、サービスコンテナをセットするといった感じです。
doctrine_migrations:
services:
'Doctrine\Migrations\Version\MigrationFactory': 'App\Migrations\Factory\MigrationFactoryDecorator'
# 👆 MigrationFactory として MigrationFactoryDecorator を使用するように変更