好きなだけかりんとうを食べる人生

フロントエンドとかデザインとかバックエンドとか浅く広く。社会人3年目のうぇぶでぃれくたーです。

【EC-CUBE3.x】ログイン後のリダイレクト周りを制御する

最近よくEC-CUBEを触るようになったのでメモ代わりに。
ほんとはRiotとRailsとSwift触りたいけど、これはこれで楽しい。

ケース

  • ログイン前にカートに商品を追加する
  • 追加した状態でログインする
  • ログイン後のリダイレクト先をカートに変更したい
  • (通常のログイン後のリダイレクト先はトップのままでいい)

実装手順

  • カートからログインページに遷移する際、クエリ文字列に rd=‘cart’ を指定する
  • クエリ文字列に rd=‘cart’ が含まれている場合、twig側で input[type=‘hidden’] を追加し、ログインと同時にPOSTする
  • ログイン成功後に DefaultAuthenticationSuccessHandler による処理を挟むようにする
  • DefaultAuthenticationSuccessHandleronAuthenticationSuccess メソッド内に条件分岐によるリダイレクト処理を挟む

流れとしてはこんな感じ。

ソースコード

カートからログインページに遷移する際、クエリ文字列に rd=‘cart’ を指定する

src/Eccube/Controller/ShoppingController.php

public function index(Application $app, Request $request) {
    // 略
    if (is_null($Customer)) {
        $params = array('rd' => 'cart');
        $url = $app['url_generator']->generate('shopping_login', $params); // クエリ文字列用の配列を渡せばOK
        return $app->redirect($url);

クエリ文字列に rd=‘cart’ が含まれている場合、twig側で input[type=‘hidden’] を追加し、ログインと同時にPOSTする

app/template/default/Shopping/login.twig

{% if rd == 'cart' %}
    <input type="hidden" name="rd" value="cart">
{% endif  %}

src/Eccube/Controller/ShoppingController.php

public function login(Application $app, Request $request) {
    // 略
    if ($request->query->get('rd') == 'cart') {
        $rd = 'cart';
    }

    return $app->render('Shopping/login.twig', array(
        'error' => $app['security.last_error']($request),
        'form' => $form->createView(),
        'rd' => $rd // twig内で参照できるように渡す
    ));
}

ログイン成功後に DefaultAuthenticationSuccessHandler による処理を挟むようにする + DefaultAuthenticationSuccessHandleronAuthenticationSuccess メソッド内に条件分岐によるリダイレクト処理を挟む

src/Eccube/Application.php

$this['security.authentication.success_handler.customer'] = $this->share(function ()  {
    $handler = new \Eccube\Security\DefaultAuthenticationSuccessHandler(
        $this,
        $this['security.http_utils'],
        $this['security.firewalls']['customer']['form']
    );
    $handler->setProviderKey('customer');

    return $handler;
});

↑を追記する

src/Eccube/Security/DefaultAuthenticationSuccessHandler.php

<?php

namespace Eccube\Security;

use Eccube\Application;
use Symfony\Component\Security\Http\Authentication\DefaultAuthenticationSuccessHandler as BaseDefaultAuthenticationSuccessHandler;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Http\HttpUtils;

class DefaultAuthenticationSuccessHandler extends BaseDefaultAuthenticationSuccessHandler
{
    /**
     * @var Application
     */
    private $app;

    public function __construct(Application $app, HttpUtils $httpUtils, array $options = array())
    {
        parent::__construct($httpUtils, $options);
        $this->app = $app;
    }

    public function onAuthenticationSuccess( Request $request, TokenInterface $token)
    {
        // rdがcartの場合、カートからのログインなのでカートにリダイレクトさせる
        if ($request->request->get('rd') == 'cart') {
          return $this->httpUtils->createRedirectResponse($request, '/cart');
        }
        return parent::onAuthenticationSuccess($request, $token);
    }
}

↑を新しく作る

参考

EC-CUBE3カスタマイズ - ユーザーがログイン成功/失敗したときにプログラムを実行する方法

おわりに

ちゃんとsymfonyとかsilexのドキュメント読むと色々よしなに対応してくれてるんだなーと実感した。

単純にログイン後のリダイレクト先を一律変更するだけなら、
/src/Eccube/Application.phpinitSecurity() 内で宣言している
$app[‘security.firewalls’] 辺りをいじればいけると思う。 (試してないので保証はしない)

手探り感ぱないのは否めないし、もっと良い書き方とかありそう。