【EC-Cube】EC-Cubeのデフォルトフローにプラグインで作ったページを割り込ませる【前編】

EC-Cubeの改修があり、EC-Cubeのプラグインの仕様書と既存のソースを読む日々を送っています。
EC-Cubeのアップデート等を想定してプラグイン開発で機能追加しようと思っていたのですが、チュートリアルの情報だけでは解決できない問題にぶつかりました。

EC-CUBE プラグインチュートリアル | EC-CUBE 開発ドキュメント

さて、
今回は購入フローに1ステップ(1ページ)加える方法について記載します。

イントロダクション

この記事で得られる事

  • EC-Cube3で、自作ページを割り込ませる方法についてわかる

環境

種類 バージョン
EC-Cube 3.0.15

実現したい事の説明

本来の購入フローは次のようになっています。

f:id:nakahashi_h:20180322023904p:plain

購入確認画面のお届け先の住所については、アカウント登録時に入力した住所を自動的に入れているようです。
任意の住所に変えたい場合は、確認画面の変更ボタンを押してお届け先住所を登録します。

実現したいことは、お届け先住所の入力を必ず新規入力させることです。
そのためには、デフォルト機能であるお届け先住所変更を、注文内容確認画面の前に差し込む方法で検討します。

f:id:nakahashi_h:20180322023917p:plain

余談

今回は、EC-Cubeを拡張すると言う方法をとりましたが、フロントだけでも対応はできるかもしれません。
もし、実装するなら確認画面でJSとcookieを駆使して、必ず変更ボタンを押させる処理を作ります。
この方法で対応できる余地があるのであれば、EC-Cubeのプラグイン開発までしなくても良いかもしれません。

どうやって割り込みをさせるのか?

結論から言うと、
カートから注文内容画面に移行する時、レスポンスに介入して、プラグインで用意したページにリダイレクトさせます。
次から説明します。

レスポンスに介入

EC-Cubeでは、既存の処理に割り込ませるにあたり、イベントのフックが各種用意されています。 http://downloads.ec-cube.net/manual/v3/plugin.pdf#page=5

フックの種類は大きく分けて2つあります。

EC-CUBE3では、

  • Symfony2のeventを利用したフックポイント
  • コントローラ内部処理やテンプレート、メール送信など、独自に拡張したフックポイント

の2種類のフックポイントを定義しています

Symfony2のeventを利用したフックポイント

前者は、httpkernelのライフサイクルに合わせたイベントです。
要は、「サーバーにリクエストして、サーバーで処理して、結果をレスポンスして。」といった、大枠のタイミングに対して割り込ませるためのものです。

今回は、 このフックポイントを使用します。
タイミングは、次の図の、3. Resoponsの時にリダイレクトを発火させることになります。

f:id:nakahashi_h:20180322024508p:plain

http://downloads.ec-cube.net/manual/v3/plugin.pdf#page=6

コントローラ内部処理やテンプレート、メール送信など、独自に拡張したフックポイント

後者は、EC-Cubeが用意しているファイルに仕込んでいるイベントの発火ポイントに対して割り込ませるものです。
EC-Cubeのファイル内で下記のようにフックポイントを用意していますので、そのフックポイントに処理を差し込みます。

// form作成
$builder = $app['eccube.service.shopping']->getShippingFormBuilder($Order);

$event = new EventArgs(
    array(
        'builder' => $builder,
        'Order' => $Order,
    ),
    $request
);
$app['eccube.event.dispatcher']->dispatch(EccubeEvents::FRONT_SHOPPING_INDEX_INITIALIZE, $event);

今回は、既存のコントローラやテンプレートに介入する必要が無いので使わない想定です。

プラグインで用意したページにリダイレクト

event.ymlにhookのイベント設定

実際のページの挙動を見ていると、カート確認画面から、購入内容確認画面に遷移しているように見えますが、 実際は、cart_buystepというURLを経由しています。
対象のコントローラであるsrc/Eccube/Controller/CartController.phpです。

ただ、挙動を確認する限り、コントローラ内の処理を実行した後に、フックのイベントが動いています。
本来の処理自体は処理されていますので、特にこのポイントに仕掛ける事で本来の処理を損ねることは無いと思われます。(ソースと挙動を見る限りは。)

フックを仕掛けるためには、event.ymlに登録が必要です。
次のようにフックと、紐づく関数名を設定します。

/app/Plugin/<プラグイン名>/event.yml

eccube.event.route.cart_buystep.response:
    - [onRouteCartBuystepResponse, NORMAL]
NORMALとは何か?

関数名の後に、NORMALという値が設定されています。
これは、処理の優先順を決められるようです。

http://downloads.ec-cube.net/manual/v3/plugin.pdf#page=32

今回は、特にバッティングが起きていなさそうなので調整は行いません。
もし、プラグイン同士がバッティングするようであれば調整するのも良いかもしれません。

リダイレクト処理

フックに対応するイベントは、<プラグイン名>Event.phpにevent.ymlに設定した関数名で設定します。
今回は、onRouteCartBuystepResponseなので次のように設定します。

/app/Plugin/<プラグイン名>/<プラグイン名>Event.php

/**
 * @param FilterResponseEvent $event
 */
public function onRouteCartBuystepResponse(FilterResponseEvent $event)
{
    $response = $this->app->redirect(
        $this->app->url('<対象のルート名>')
    );
    $event->setResponse($response);
}

上記で指定した、対象のルート名、およびリダイレクト先のURLについてはServiceProviderで登録します。

/app/Plugin/<プラグイン名>/ServiceProvider/<プラグイン名>ServiceProvider.php

$app->match(
    '<リダイレクト先のURL>',
    '<処理の関数>'
)
->bind('<対象のルート名>');

上記の処理の関数については、Controllerと関数を用意して紐づけるのがわかりやすいかと思います。
後は、コントローラで、描画するテンプレートを指定してあげればページを差し込む事ができます。



以上です。
これで、作ったページを任意の場所に割り込ませるという事ができるようになったかと存じます。
次回は、割り込んで処理したあと、本来のフローに戻す方法について説明する予定です。