【EC-CUBE 4】注文内容に新しい項目を追加し、注文画面をカスタマイズしてみた

注文ごとに独自の情報を持たせたい、というのはよくある要望です。EC-CUBEの注文情報は dtb_order テーブルに保存されますが、ここへ自分で決めた項目をひとつ足し、注文画面のフォームから保存できるようにするまでを通しで解説します。例として「領収書が必要/不要」のチェックボックスを設置します。

注文画面に独自の入力項目を追加するには?

やることは3つです。①Orderエンティティを拡張して dtb_order に項目を追加②OrderTypeを拡張して注文画面のフォームに項目を追加③Twigテンプレートに表示用のコードを追記

Controllerのカスタマイズは不要です。注文画面のフォームは、すでに既存のShoppingControllerからテンプレートへ渡されているためです。

つまずきやすいのは②。フォームの項目を無条件に追加してしまうと、注文完了の直前で入力値が消えます。理由は本文で解説します。

【動作環境】EC-CUBEのバージョン:4.2.1 / サーバー:Xserver

開発前にデバッグモードの設定をおすすめします。エラーが起きたときに詳細情報が表示されるようになり、原因の箇所を探しやすくなります。カスタマイズ後は解除を忘れずに。

設定と解除の手順は、こちらの記事にまとめています。

デバッグモードの設定/解除方法

目次

このカスタマイズでやること

作業は次の3つに分かれます。どのファイルを触るのかを先に押さえておくと、途中で迷いません。

  1. 1dtb_order テーブルに新規プロパティを追加(拡張)する
  2. 2入力フォームを拡張(OrderTypeExtensionを作成)する
  3. 3Twigテンプレートにフォームと表示用のコードを追記する
手順 置き場所 役割
1 app/Customize/Entity/OrderTrait.php 注文情報に receipt という保存先を用意する
2 app/Customize/Form/Extension/OrderTypeExtension.php 注文画面のフォームにチェックボックスを足す
3 app/template/default/Shopping/index.twig
app/template/default/Shopping/confirm.twig
入力欄と、入力結果を画面に出す

必要に応じて、注文受付メールや受注管理画面にも表示用のコードを追記します(本記事では割愛します)。

dtb_orderテーブルに新規プロパティを追加(拡張)する

まずは注文情報を保存しておくテーブル dtb_order に、独自のプロパティ receipt を追加します。EC-CUBEでは既存のエンティティをTraitで拡張することで、コアのファイルを書き換えずに項目を増やせます。

テーブルの拡張そのものについては、別記事で基本から解説しています。ここでは実際に作成したエンティティと操作だけを記します。

既存テーブルに新しいフィールド(カラム)を追加するカスタマイズ

Orderエンティティを拡張する(OrderTraitの作成)

以下のTraitファイルを作成し、app/Customize/Entity 下に保存します。

<?php

namespace Customize\Entity;

use Doctrine\ORM\Mapping as ORM;
use Eccube\Annotation\EntityExtension;

/**
 * @EntityExtension("Eccube\Entity\Order")
 */
trait OrderTrait
{
    /**
     * @var boolean
     *
     * @ORM\Column(name="receipt", type="boolean", nullable=false, options={"default": false})
     */
    private $receipt = false;

    /**
     * Set receipt.
     *
     * @param boolean $receipt
     *
     * @return Order
     */
    public function setReceipt($receipt = false)
    {
        $this->receipt = $receipt;

        return $this;
    }

    /**
     * Get receipt.
     *
     * @return boolean
     */
    public function getReceipt()
    {
        return $this->receipt;
    }
}
項目 内容
プロパティ名 receipt
boolean(真偽値)
初期値 false

初期値を options={"default": false} で指定しているのがポイントです。すでに注文データが入っているテーブルであっても、既存の行に入れる値が決まるため、そのまま項目を足せます。

サーバーにSSH接続してテーブル拡張

Traitファイルをアップしたら、SSH接続して以下のコマンドを順に実行し、データベースを拡張します。Traitを置いただけではEC-CUBE側がプロパティを認識しないため、この3つはセットです。

  1. STEP1
    Proxyを生成する
    bin/console eccube:generate:proxies

    Traitに書いた内容を、EC-CUBEがエンティティの一部として扱えるようにするための生成処理です。

  2. STEP2
    キャッシュを削除する
    bin/console cache:clear --no-warmup

    古い定義が残っていると、生成したProxyが読まれません。

  3. STEP3
    データベースへ反映する
    bin/console doctrine:schema:update --dump-sql --force

    実行されるSQLを表示したうえで、データベースへ反映します。問題なく終われば、dtb_order テーブルに receipt というプロパティができているはずです。

XserverでのSSH接続の手順は、OSごとに記事を用意しています。

Windows PCからSSH接続する方法(Tera Termを利用)
Mac PCからSSH接続する方法

入力フォームを拡張(OrderTypeExtensionを作成)する

続いて、追加したプロパティ receipt に値をセットするためのフォームを、注文画面(/shopping)に設置します。

注文のためのフォームにはOrderTypeが用意されており、すでに注文画面でフォームが埋め込まれています。そこで、OrderTypeを拡張したOrderTypeExtensionを作成し、app/Customize/Form/Extension 下に保存します。

<?php

namespace Customize\Form\Extension;

use Eccube\Form\Type\Shopping\OrderType;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;

class OrderTypeExtension extends AbstractTypeExtension
{
  public static function getExtendedTypes(): iterable
  {
    return [OrderType::class];
  }

  public function buildForm(FormBuilderInterface $builder, array $options)
  {
    if (!$options['skip_add_form']) {
      $builder
      ->add('receipt', CheckboxType::class, [
        'label' => '領収証が必要な方はチェックを入れてください。',
        'required' => false,
        'mapped' => true,
      ]);
    }
  }
}

この if (!$options['skip_add_form']) を外さないでください。外すと、注文完了の直前でチェックの内容が消えます。

EC-CUBEは確認画面から注文処理へ進むときに、フォームをもう一度組み立て直します。このときは skip_add_form を有効にしてフォーム項目の定義を意図的に飛ばし、すでにOrderへ入っている値をそのまま引き回す作りになっています。拡張側が無条件に項目を足してしまうと、この場面でも項目が復活し、送信されていない状態の値で上書きされてしまう、というわけです。

FormTypeの拡張と、チェックボックスなどのフォーム部品については、それぞれ別記事で詳しく解説しています。後者ではCheckboxTypeではなくChoiceTypeを使った実装方法を紹介しています。

FormExtensionを使ったFormTypeのカスタマイズ
ドロップダウンリスト / ラジオボタン / チェックボックスの実装方法

Twigテンプレートをカスタマイズする

作成したフォームを表示させるには、本来ならControllerからTwigテンプレートへフォームを渡す処理が必要です。ただし今回は、すでに既存のShoppingControllerからOrderTypeのフォームが渡されているため、Controllerのカスタマイズは不要です。

注文画面に対応するTwigテンプレート Shopping/index.twig を開き、チェックボックスを表示させたい箇所に以下を追記します。

{{ form_widget(form.receipt) }}

続いて、注文確認画面 Shopping/confirm.twig で、チェックに応じた内容を表示させます。適当な場所に以下を追記してください。

{{ Order.receipt ? '領収書:必要' : '領収書:不要' }}

入力画面と確認画面で、参照するものが違います。入力画面はフォームなので form.receipt、確認画面はフォームではなく注文そのものを表示しているので Order.receipt です。確認画面にはフォームが渡っていないため、ここで form_widget を書いても表示されません。

見た目は、好みに応じてレイアウトやスタイルを調整してください。

EC-CUBEでのCSSの当て方と反映方法は、こちらにまとめています。

CSSの簡単設定と反映方法

実装結果

注文画面(/shopping)に、チェックボックスが設置されました。今回はお支払い方法の下に置いています。

オリジナルのチェックボックスを実装したEC-CUBEの注文画面。お支払い方法の下に「領収証が必要な方はチェックを入れてください。」が表示されている

実装後の注文画面(/shopping)

フォームはお支払い方法の下に設置

注文確認画面(/shopping/confirm)の表示は、チェックの有無で切り替わります。

注文画面でチェックしなかった場合の注文確認画面。「領収書:不要」と表示されている

チェックしなかった場合

「領収書:不要」と表示される

注文画面でチェックした場合の注文確認画面。「領収書:必要」と表示されている

チェックした場合

「領収書:必要」と表示される

あわせて、dtb_order テーブルの receipt プロパティの値も、チェックの有無に応じて変化します。

うまくいかないときの確認ポイント

症状 確認するところ
注文は通るが、チェックが保存されていない OrderTypeExtensionの skip_add_form の分岐が抜けていないか。無条件に項目を足すと、注文処理へ進む場面で値が上書きされます
receipt が見つからない、というエラーになる Proxyの生成・キャッシュの削除・データベースへの反映を、順に実行したか。Traitを置いただけでは認識されません
確認画面に何も表示されない 確認画面で form.receipt を書いていないか。確認画面は Order.receipt です

まとめ

  • 注文情報への項目追加は、app/Customize/Entity に置くTraitで行う。コアのファイルは触らない
  • 反映にはProxyの生成・キャッシュの削除・データベースへの反映の3コマンドが必要
  • フォームの追加はOrderTypeExtensionskip_add_form が有効なときは項目を足さないのが必須条件
  • 注文画面のフォームはShoppingControllerから渡されているので、Controllerのカスタマイズは不要
  • 表示は、入力画面が form.receipt、確認画面が Order.receipt


EC-CUBE 4カスタマイズのまとめ記事のアイキャッチ

あわせて読みたい
EC-CUBE 4 カスタマイズのまとめ
EC-CUBE 4について、筆者自身が学習・実践してきたカスタマイズ方法をまとめています。はじめて触る方向けに、手を動かす順番も並べました。

EC-CUBEのカスタマイズに関する記事

この記事に出てきた用語

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次