EC-CUBE 4.2から4.3へのバージョンアップで動かなくなるカスタマイズは、親クラスやインターフェイスが型を宣言したメソッドと、4.3で削除された書き方を使っている箇所だけです。4.3の本体も型を書かない従来の書き方を残しているので、すべてのメソッドに型を付ける必要はありません。
4.2.3から4.3.1-p1へ実際に上げたときに動かなくなった6箇所を、エラー文と直し方で紹介します。ほかのカスタマイズは、手を入れずに動きました。
直す必要がある箇所の見分け方
4.3ではSymfonyが5.4から6.4に、Twigが2から3に上がります。ただしSymfony 6.4も、フォームのbuildForm()やコマンドのexecute()のように利用者が上書きするメソッドの多くには、まだ型を宣言していません。
直す箇所は、PhpStormなどIDEの正規表現検索で、app/Customize・app/Plugin・app/templateを対象に探せます。
| 検索する正規表現 | 見つかるもの |
|---|---|
implements\s.*(RouterInterface|UrlGeneratorInterface|UrlMatcherInterface) |
ルーターを差し替えるクラス |
DependencyInjection\\ContainerInterface |
サービスコンテナを受け取るクラス |
\{%-?\s*for\s[^%]*\sif\s |
Twig 3で廃止されたfor…if |
Response::create\( |
Symfony 6で削除された静的メソッド |
ContainerInterfaceは、使い方によって直し方が違います。プラグインのPluginManagerなら型を書き換え、コンストラクタで受け取っているだけなら設定を1行足します。
型の宣言が合わずに止まる箇所
次の3つはbin/console自体が起動しなくなり、キャッシュの削除もできなくなるので、最初に直します。
ルーターを差し替えるクラス(RouterInterface)
URLの生成を変えるためにrouterサービスを差し替えているクラスは、Symfony 6.4でインターフェイスに付いた型と合わずに止まります。
PHP Fatal error: Declaration of Customize\Routing\CustomRouter::match($pathinfo) must be compatible with Symfony\Component\Routing\Matcher\UrlMatcherInterface::match(string $pathinfo): array in /path/to/eccube/app/Customize/Routing/CustomRouter.php on line 78
PHPは食い違ったメソッドを1つずつしか報告しないので、まとめて次の宣言に合わせます。
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\RouteCollection;
public function generate(string $name, array $parameters = [], int $referenceType = self::ABSOLUTE_PATH): string
public function setContext(RequestContext $context): void
public function getContext(): RequestContext
public function getRouteCollection(): RouteCollection
public function match(string $pathinfo): array
プラグインのPluginManager
4.3では、PluginManagerが継承するAbstractPluginManagerの引数が、SymfonyのコンテナからPSRのコンテナに変わりました。
PHP Fatal error: Declaration of Plugin\SamplePlugin42\PluginManager::update(array $meta, Symfony\Component\DependencyInjection\ContainerInterface $container) must be compatible with Eccube\Plugin\AbstractPluginManager::update(array $meta, Psr\Container\ContainerInterface $container)
useをPsr\Container\ContainerInterfaceに変えます。PSRのコンテナにはgetParameter()が無いので、パラメーターはEccubeConfigから読みます。
use Eccube\Common\EccubeConfig;
use Psr\Container\ContainerInterface;
// 変更前: $container->getParameter('eccube_theme_front_dir')
$templateDir = $container->get(EccubeConfig::class)->get('eccube_theme_front_dir');
公式のメルマガ管理プラグインと商品レビュー管理プラグインの4.3.0版も同じ書き換えをしていて、プラグインコードとテーブル名は4.2版と同じです。自分で直すのは、4.3対応版が出ていないプラグインだけです。
4.2で生成したプロキシ
Traitでエンティティを拡張していると、4.2の本体を元に生成したapp/proxy/entityのプロキシが残り、型が合わずに止まります。
PHP Fatal error: Declaration of Eccube\Entity\Customer::getRoles() must be compatible with Symfony\Component\Security\Core\User\UserInterface::getRoles(): array in /path/to/eccube/app/proxy/entity/src/Eccube/Entity/Customer.php on line 317
EC-CUBEは起動時にプロキシを読み込むので、このままではeccube:generate:proxiesも実行できません。古いプロキシを別の場所へ移し、キャッシュを消してから生成し直します。
mv app/proxy/entity/src /path/to/backup/proxy-4.2-src
rm -rf var/cache/prod
bin/console cache:clear --no-warmup
bin/console eccube:generate:proxies
プロキシはGitで管理しないことが多く、本番環境へ反映したときに初めて出ることがあります。反映手順に、この移動を最初から入れておきます。
4.3で使えなくなった書き方
ContainerInterfaceの自動注入(Cannot autowire service)
Symfony 6では、ContainerInterfaceを型にした引数へ、サービスコンテナを自動で渡す設定が無くなりました。
Cannot autowire service "Customize\Command\SampleCommand": argument "$container" of method "__construct()" references interface "Symfony\Component\DependencyInjection\ContainerInterface" but no such service exists. You should maybe alias this interface to the existing "service_container" service.
エラー文のとおり、app/Customize/Resource/config/services.yamlにエイリアスを1行足すと、4.2と同じ動きに戻ります。使うサービスだけを引数で受け取る形に書き直せば、このエイリアスは要りません。
services:
Symfony\Component\DependencyInjection\ContainerInterface: '@service_container'
Twig 3で廃止されたfor…if
Twig 3では、forタグにifで条件を付ける書き方が廃止され、該当するテンプレートを使うページが500エラーになります。
Unexpected token "name" of value "if" ("end of statement block" expected).
条件はfilterフィルターに移します。
{# 変更前(Twig 2まで) #}
{% for item in items if item.count > 0 %}
{# 変更後(Twig 3) #}
{% for item in items|filter(item => item.count > 0) %}
Response::create()
Symfony 6では、Response::create()のような静的メソッドが削除されました。RedirectResponseとJsonResponseのcreate()も同じです。例外処理の中で使っていると、エラー画面を作る処理が失敗して500になります。
Attempted to call an undefined method named "create" of class "Symfony\Component\HttpFoundation\Response".
Uncaught Exception: Unable to add global "Layout" as the runtime or the extensions have already been initialized.
ログの最後に残る2行目はTwigの不具合に見えますが、原因は直前の1行目です。newで作る形に直します。
// 変更前
$event->setResponse(Response::create($content, $statusCode));
// 変更後
$event->setResponse(new Response($content, $statusCode));
直したあとに確認する順番
まずbin/console cache:clearが成功するかを確かめます。ルーター、PluginManager、プロキシ、ContainerInterfaceの4つは、ここでエラーになります。
Twigのfor…ifとResponse::create()は、その処理が実行されるまでエラーになりません。書き換えたテンプレートを使うページを開き、GETだけを受け付けるURLにPOSTを送って、405のエラー画面が表示されるかも確かめます。
EC-CUBEに関するお問い合わせ
[重要]現在公式にセキュリティサポートが切れていないPHPは8.1以上、MySQLは8.0以上で、対応しているEC-CUBEバージョンは4.2以上です。古いEC-CUBEを使っている方は適切なタイミングでバージョンアップをご検討ください。