自作プラグイン7本を EC-CUBE 4.4 に対応させました。会員グループ管理プラグインと、そのアドオン6本です。
最初は構文チェックさえ通れば移行は終わったつもりでいました。甘かった。実際に 4.4 を立てて動かすと、インストールが完走しない、商品登録が500になる、プラグインの有効化が落ちる、という順に出てきます。どれも構文としては正しいので、静的な確認では絶対に見つかりません。
同じところで詰まる人がいると思うので、実際に踏んだものだけをまとめます。検索でここに来る人はエラーメッセージを手がかりに探すはずなので、先に早見表を置きます。
なお、4.4 本体はまだリリースされていません。開発ブランチを相手にした時点の記録なので、正式版で挙動が変わる可能性はあります。
エラーメッセージ早見表
| 症状・エラー | 原因 |
|---|---|
| EC-CUBE のインストールが完了しない | DiscountProcessor::addDiscountItem() の戻り値型が変わった |
Form data cannot be changed during "form.post_submit" | Symfony 7 が POST_SUBMIT でのデータ変更を禁止した |
There is no active transaction.(プラグイン有効化時) | DBAL 4 が MySQL の DDL 暗黙コミットを検知するようになった |
| 購入手続き画面で TypeError | 支払方法や配送方法の選択肢を配列以外で渡している |
| エンティティのアノテーションが効かない | Doctrine ORM 3 でアノテーションが廃止された |
Symfony\Component\Security\Core\Security が見つからない | Symfony 7 で削除された |
@Template や @IsGranted が効かない | SensioFrameworkExtraBundle の開発が終了した |
| 本体のテストクラスを継承できない | 4.4 で本体のテストクラスが final 化された |
assertSame で数値の比較が落ちる | decimal 列の getter が string を返すようになった |
以下、それぞれの詳細です。
依存がまるごと入れ替わっている
前提として、4.4 は 4.2 / 4.3 の延長ではありません。
| 依存 | 4.2 / 4.3 | 4.4 |
|---|---|---|
| PHP | 7.4 〜 8.3 | ^8.2 |
| Symfony | 6.4 | ^7.4 |
| doctrine/orm | 2.18 | ^3.0 |
| doctrine/dbal | 3.8 | ^4.4 |
同じコードで 4.2 / 4.3 と 4.4 の両方を面倒みるのは早々に諦めました。7本とも 4.4 専用のブランチに分けています。
インストールが完了しない
いちばん最初に踏んで、いちばん分かりにくかったのがこれです。症状は「EC-CUBE のインストーラーが完走しない」で、プラグインの画面まで到達すらしません。
原因は DiscountProcessor::addDiscountItem() の戻り値型です。
| 戻り値型 | |
|---|---|
| 4.2 / 4.3 | void |
| 4.4 | ?ProcessResult |
実装側が void のままだとシグネチャ不一致の致命的エラーになります。値引き明細を追加しないケースでは null を返せば、従来どおり何もしません。
戻り値型を変えるときは、途中で抜けているパスも全部見てください。自分は末尾の1箇所を取りこぼしました。
商品登録が500になる
Form data cannot be changed during "form.post_submit"
Symfony 7 は POST_SUBMIT でのデータ変更を禁止するようになりました。フォームイベントの中でフォームデータを差し替えていると、ここで例外になります。
該当箇所を見たら、どれもエンティティを直接操作したあとに念のためデータをセットし直しているだけで、その処理は元々必要ありませんでした。消して終わりです。
古いコードほど、効いていない行が残っています。Symfony 側が厳しくなったおかげで見つかった、という感じでした。
プラグインの有効化が落ちる
There is no active transaction.
これがいちばん厄介でした。順を追うとこうなっています。
- EC-CUBE 本体はプラグインの有効化をトランザクションで包む
- プラグイン側が外部キーを張り替えるために
ALTER TABLEを投げる - MySQL は DDL で暗黙コミットするので、同じ接続だとトランザクションがその場で終わる
- DBAL 4 はこれを検知するため、本体が最後に commit しようとしたところで落ちる
DBAL 3 のときは黙って通っていたので表面化していませんでした。有効化のたびに外部キーを張り直す処理を入れていたプラグインで、4.4 にして初めて出ています。
対処は、DDL を専用の接続で流すことです。本体のトランザクションとは別の接続なので、暗黙コミットが起きても影響しません。
PostgreSQL では DDL がトランザクション内で扱えるため、この問題は MySQL 固有です。両方で検証してください。
購入手続き画面で TypeError
4.4 の ShoppingController は、支払方法の選択肢を配列前提で扱うようになりました。ArrayCollection のまま渡していると TypeError で購入手続き画面が500になります。
これは症状の出方が意地悪でした。配送方法アドオン側のテストが「配送方法の選択肢が0件」で落ちるという形で表面化したためです。落ちているのは配送方法、原因は支払い方法が渡す選択肢の型。プラグインを1本ずつ見ていたら追えなかったと思います。
複数のプラグインを並行して上げていて、たまたま両方のテストを回していたから見つかりました。プラグインを何本も持っているなら、まとめて上げたほうが見つかりやすいかもしれません。
アノテーションが属性記法になった
Doctrine ORM 3 でアノテーションが廃止されました。エンティティやルーティングの記述を属性記法に変換する必要があります。
@ORM と @Route は Rector で機械的に変換できました。問題は EC-CUBE 独自のもので、こちらは手で置き換えています。
| 4.2 / 4.3 | 4.4 |
|---|---|
@EntityExtension | Eccube\Attribute 配下の属性 |
@ShoppingFlow | 同上 |
消えたクラスと開発終了したバンドル
Symfony 7 で削除されたもの、外部バンドルの開発終了に伴って移動したものです。移動先だけ知っていれば置換で終わります。
| 4.2 / 4.3 | 4.4 |
|---|---|
Symfony\Component\Security\Core\Security | Symfony\Bundle\SecurityBundle\Security |
@Template(SensioFrameworkExtraBundle) | Symfony\Bridge\Twig\Attribute\Template |
@IsGranted(同上) | Symfony\Component\Security\Http\Attribute\IsGranted |
SensioFrameworkExtraBundle は開発が終了しているので、依存ごと外すことになります。
テストが軒並み落ちる
差分がいちばん大きかったのは、プラグイン本体のコードではなくテストでした。
本体のテストクラスが final 化されました。 具象テストクラスを継承してヘルパーを借りていたテストが、全部動かなくなります。抽象基底クラスを継承する形に移して、具象クラスにしかないヘルパーは自前のトレイトに切り出しました。
このとき1つやらかしていて、借りていたヘルパーを同名の別物と取り違えていました。配送方法の登録フォームを作るヘルパーのつもりが、会員登録フォームのものだった。名前が同じで中身が違うので、移し替えるときは中身を確認してください。
そのほか、4.4 固有で引っかかったのが以下です。
| 引っかかった点 | 内容 |
|---|---|
| decimal 列の getter | string を返すようになった。assertSame での比較が落ちる |
| エンティティのメソッド | 戻り値型が宣言され、モックが型不一致で組めなくなった |
| カート投入のヘルパー | 第2引数は商品規格の ID。オブジェクトを渡すとルーティングで失敗する |
| 商品作成のヘルパー | 第3引数が 4.4 には無く、渡しても無視される |
| データプロバイダ | static にして属性記法へ |
数量が string で返ってくるのは何度見てもとまどいます。
プラグインコードを 44 系にする
4.4 版はプラグインコードとパッケージ名を変えました。会員グループ管理なら CustomerGroup42 から CustomerGroup44 です。
EC-CUBE から見ると別のプラグイン扱いになります。つまり 4.2 / 4.3 版からの入れ替えは、同じプラグインの更新ではありません。テーブル名を据え置いても、そのまま入れ替えられるかは別途の確認が要ります。
副産物として、バージョンで分岐していたコードを消せました。本体のバージョン定数を見て設定を切り替えていた箇所は、専用ブランチでは常に片方しか通りません。4.3 以降ずっとスキップされていたテストもまとめて削除しています。両立させようとしていたら残り続けたはずです。
検証した環境
CI で回している組み合わせです。
| 項目 | 内容 |
|---|---|
| EC-CUBE | 4.4(開発ブランチ) |
| PHP | 8.2 / 8.3 |
| データベース | MySQL 8.4、PostgreSQL 13 と 18 |
MySQL 5.7 は 4.4 の検証対象から外れています。PostgreSQL は下限の13と上限の18の両方を見ています。DDL の扱いが違うので、MySQL と PostgreSQL は両方回したほうがいいです。
まだ分かっていないこと
4.4 は未リリースなので、ここに書いたものが正式版でそのまま当てはまるとは限りません。開発ブランチが動けば挙動も変わります。
それと、ここに挙げたのは自分のプラグインが使っている範囲で踏んだものだけです。決済や外部連携など、自分が触っていない領域には別のハマりどころがあるはずです。
個別のプラグインでの対応内容は会員グループ管理プラグインと会員グループ価格管理アドオンの記事に書いています。