EC-CUBE4.2 同一商品の複数の規格をカートに一括投入するカスタマイズ

EC-CUBE4のお話。
タイトルだけではわからないかもしれないですが、例えば衣料品の同一商品について、サイズ違い・色違いをまとめてカートに投入するといったカスタマイズです。
EC-CUBE2では無料のプラグインがありますが、EC-CUBE4には見当たらなかったのでカスタマイズしてくれと言うご要望でした。

僕自身、EC-CUBE4というかsymfonyは殆ど触ったことがなかったので、そのへんの調査からになりました。
一番参考になったのは、以下のサイトです。
1)
https://symfonycasts.com/screencast/collections/add-new-collection-prototype

2) https://symfony.com/doc/current/reference/forms/types/collection.html

同時に複数の商品をカートに入れるためには、AddCartTypeを複数配置することになります。
symfonyのドキュメントによると、ひとつのフォームで複数のentityを扱えるようにするには、CollectionTypeを使えということでした。
EC-CUBE4でカートに商品を投入するフォームタイプは、
src/Eccube/Form/Type/AddCartType.php
です。
これをCollectionTypeを使って、複数扱えるようにします。

src/Eccube/Controller/ProductController.php
をカスタマイズする必要があるので
app/Customize/Controller/
下にコントローラーファイルを作成します。
function detail()をオリジナルからコピーして、フォームビルダー部分を

$builder = $this->formFactory->createBuilder( );
$builder
    ->add(
        'data',
        CollectionType::class,
        [
            'entry_type' => AddCartType::class,
            'entry_options' => [
                'product' => $Product,
                'id_add_product_id' => false,
                'attr' => ['class' => 'oneclass'],
            ],
            'allow_add' => true,
            'allow_delete' => true,
            'label' => '',
        ]
    );

のようにします。
また、twigテンプレート
src/Eccube/Resource/template/default/Product/detail.twig
を、
app/template/default/Product
にコピーしておきます。

この状態で、
/products/detail/xxxx
にアクセスして、変数formをダンプすると、

children->data->vars->prototype

の中に、AddCartTypeの要素がずらずら〜と入っているはずです。

detail.twigのadd_cartのフォームの中に、上記1)のURLにあるように、

<div class="product-class-item" data-prototype="{{ form_widget(form.data.vars.prototype)|e('html_attr') }}"></div->

を追加すると、data-prototypeの部分に、数量と規格の選択部分のhtmlが吐き出されています。
この部分には、

これまた1)を参考に、追加削除ボタンを処理するJavaScriptを作成します。
(僕の書いたコード、相当カッコ悪いと感じているのでここには載せません)
そうすると、

<div id="form_data_X" class="oneclass">〜</div>

で囲われた、一つの商品規格選択フォーム要素が追加されます。
フォームの要素のnameは、form[data][0][quantity]のようになっていると思います。
これで、複数の規格をカートに投入すると、配列として送信されます。
なお、カート追加のactionはproducts/addmulti_cartにしました。
商品一覧(/products/list)のほうで/products/add_cartは使うかもしれないので、アクションを分けておいたほうが楽かなと思いましたので。

ProductController.phpのfunction addCartもコピーして、function addmultiCart()としてカートへ追加する処理を記述します。
フォームビルダーのところはfunction detailと同じです。

エラーがなければ、$form->getData() にはカートに入れる商品毎の配列が入っています。
ここは、

foreach ( $addCartData['data'] as $oneItem ) {
    $this->cartService->addProduct($oneItem['product_class_id'], $oneItem['quantity']);
}

とループを回して、ひとつずつカートに追加するようにしました。

もうちょっと、シュッとしたやりかたがあるようが歩きもしますが、とりあえず動いたのでOKとしました。

なお、symfonyがなのか、CollectionTypeがなのかわかりませんが、メモリーをかなり使うようです。
僕が試したubuntu22.04(PHP8.1)のデフォルト値のmemory_limitではメモリー不足になってしまいました。
memory_limitを512Mにしたらエラーは起きなくなりました。

カテゴリー: Webコンテンツ パーマリンク