ハマログ

株式会社イーツー・インフォの社員ブログ

EC-CUBE (Symfony)のCLIで送ったメールのURLがlocalhostになる

概要

EC-CUBE(4系以上)において、バッチ処理などからメールを送信したい場面があります。そんなとき、Webサイトが https://ec-cube.test なのに、メールに記載されるURLが http://localhost になってしまうことがあります。

TL;DR

  • CLIから実行すると、URLが localhost になってしまう
  • services.yaml に設定を記載するとよい
  • RequestStackを使うなど、別の方法も有効かも

localhost になってしまう例

バッチ処理で使われるようなコマンドを想定して、次の簡単なサンプルコードを実装してみます。

<?php

namespace Customize\Command;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;

class TestMailCommand extends Command
{
    protected static $defaultName = 'test:mail';
    public function __construct(private UrlGeneratorInterface $urlGenerator)
    {
        parent::__construct();
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = new SymfonyStyle($input, $output);

        $url = $this->urlGenerator->generate('cart', [], UrlGeneratorInterface::ABSOLUTE_URL);
        $io->success($url);

        return 0;
  }
}

これを bin/console test:mailコマンドで実行すると、 ホストが localhost のURLが表示されてしまいます。

ここでは例のため UrlGeneratorInterface で取得した絶対URLをコンソールに表示しているだけですが、Twigテンプレートなどでメールを送信する場合でも同様です。

HTTPのリクエストから実行されていないので、フレームワークが使っているドメインなどを認識できないためこうなります。

① services.yamlに絶対URLを指定

TL;DRに書いたように、このlocalhost問題は設定ファイルに絶対URLを記載することで解決できます。app/Customize/Resource/config/services.yaml に次の項目を追加します

framework:
    router:
        default_uri: https://ec-cube.test

そして、上と同じように test:mail を実行するとこのようになります。

localhostではなく、設定したURLが表示されるようになりました。ちなみにこれはなんてことはなく、ただのSymfonyのドキュメントに書いてある方法です。

https://symfony.com/doc/6.4/routing.html#generating-urls-in-commands

② RequestContextを指定する例

Symfonyの設定ではなく、URLを生成するときのコードで対応することもできます。URLを生成するときにHTTPのリクエストコンテキストがないためlocalhostになってしまうので、RequestContextを設定することで対応する方法です。

上とほとんど同じですが、このようなコードになります。

<?php

namespace Customize\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Routing\RequestContext;

class TestMailCommand extends Command
{
    protected static $defaultName = 'test:mail';
    public function __construct(
        private UrlGeneratorInterface $urlGenerator,
        private RequestContext $requestContext,
    )
    {
        parent::__construct();
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = new SymfonyStyle($input, $output);

        $this->requestContext->setHost('hoge.localhost');
        $this->requestContext->setHttpPort(8080);
        $url = $this->urlGenerator->generate('cart', [], UrlGeneratorInterface::ABSOLUTE_URL);
        $io->success($url);

        return 0;
    }
}

こうすることで、表示されるURLがhttp://hoge.localhost:8080/cart になります。この方法ではservices.yamlを編集する必要はありません。

弊社で開発・販売している「かご落ち通知メールプラグイン」というEC-CUBEプラグインがあります。カートに入ったまま放置されている商品についてメールでお知らせする機能で、メール送信はcronなどでバッチ処理を起動する想定となっています。このプラグインのメール送信部分は、RequestContextを使うなどservices.yamlによらない方法で実装しました。管理画面でプラグインの初期設定をしてもらうタイミングで、他の項目とあわせてトップページURLを保存する仕様になっています。

最後に

EC-CUBEやSymfonyに限りませんが、URLの生成は意外と罠が多いです。最後に紹介したRequestStackを使った方法では、EC-CUBEをサブディレクトリで運用しているときや、UrlGeneratorではなくAssetのURLを生成するときなどでは、意図しないURLになってしまうことがあります。結局はちゃんと確認するしかありません。

余談ですが、この記事で使った ec-cube.testhoge.localhost のはテスト・開発用途で予約済みトップレベルドメインなので、安心して使えるドメインです。こういった例で適当な .com のドメインや Gmail のメールアドレスを使うと、実在してしまうことがあるので注意が必要です。

CLI操作EC-CUBEEC-CUBEプラグインlocalhost問題PHP開発RequestContextservices.yamlsymfonyUrlGeneratorURL生成コマンドラインテスト環境ドメイン設定バッチ処理バッチ処理対策フレームワークプラグイン開発メール送信絶対URL設定開発Tips

  koni   2024年11月28日


関連記事

GCPでLaravelのログ監視を行う方法

GCPでアプリケーションのログに特定の文字列が出てきたら検知して通知する方法を調…

cornerstone がよさげでぽちる

Mac で TortoiseSVN のような svn GUI client はな…

WordPress 3.7

WordPress の新バージョンの 3.7 ですが、今回もっとも大きな注目点は…


← 前の投稿

次の投稿 →