【EC-CUBE 4】商品のソート(並び替え)オプションの実装方法

先日、商品一覧ページにある商品並べ替え(ソート)オプションのカスタマイズ方法について解説しました。

本記事では、以下のような新しく作成したページに、同様の商品並べ替え(ソート)オプションを追加する方法について解説します。

実装例

右上にソート順(並び替え)が選べるドロップダウンリストを設置。

選択した内容に応じて、商品の表示順が入れ替わる

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

開発前にデバッグモードの設定をお薦めします

デバッグモードを設定しておくと、エラーが起きたときに詳細情報が表示されるようになります。
エラー箇所を探しやすくなるので、開発前に設定しておくのをオススメします。
デバッグモードの設定方法については 以下記事 で解説しています。

カスタマイズ後は、デバッグモードの解除を忘れないように。

目次

特定のタグが付いた商品を表示するページに、ソートオプションを実装する

以前本サイトで紹介した、特定のタグを付けた商品のみを抽出し、一覧ページを作る方法 で作成したページに、デフォルトの商品一覧ページと同じようなソートオプションを実装してみます。実装前は以下のような表示になっています。

実装の手順

  1. フォームタイプ(FormType)の作成:ドロップダウンリストを生成するためのファイル
  2. リポジトリ(Repository)の作成:特定の商品を特定の順序で取得するファイル
  3. コントローラ(Controller)の作成:FormType、Repositoryを使って、Twigテンプレートにフォームと取得商品を渡すためのファイル
  4. Twigテンプレートの作成
STEP

フォームタイプ(FormType)の作成:ドロップダウンリストを生成するためのファイル

以下のSortType.phpファイルを作成し、「Customize/Form/Type」にアップします。

<?php

namespace Customize\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;

class SortType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('orderBy', ChoiceType::class, [
                'choices' => [
                    '新着順' => 'new',
                    '古参順' => 'old',
                ],
                'placeholder' => 'ソート順を選択してください',
            ]);
    }
}
STEP

リポジトリ(Repository)の作成:特定の商品を特定の順序で取得するファイル

以下のCustomProductRepository.phpファイルを作成し、「Customize/Repository」にアップします。

<?php

namespace Customize\Repository;

use Eccube\Repository\ProductRepository;

class CustomProductRepository extends ProductRepository
{
    public function findProductsByTagId($tagId, $sortOrder='DESC')
    {
        $qb = $this->createQueryBuilder('p');
        $qb->innerJoin('p.ProductTag', 'pt')
            ->innerJoin('pt.Tag', 't')
            ->andWhere('t.id = :Tag')
            ->setParameter('Tag', $tagId)
            ->orderBy('p.id', $sortOrder);

        return $qb->getQuery()->getResult();
    }
}
  • 既存のProductRepositoryを拡張しています。
  • findProductsByTagIdメソッドを定義しています。
    • 第一引数に指定したIDのタグをもつ商品を抽出し、第二引数で指定した順(指定しなかった場合はDESC = 降順)に並べ替えます。
STEP

コントローラ(Controller)の作成:FormType、Repositoryを使って、Twigテンプレートにフォームと取得商品を渡すためのファイル

以下のTagProductsController.phpファイルを作成し、「Customize/Controller」にアップします。

<?php

namespace Customize\Controller;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Eccube\Controller\AbstractController;
use Customize\Form\Type\SortType;
use Customize\Repository\CustomProductRepository;

class TagProductsController extends AbstractController
{
   /**
     * @var CustomProductRepository
     */
    protected $customProductRepository;

    /**
     * @param CustomProductRepository $customProductRepository
     */
     public function __construct(CustomProductRepository $customProductRepository) {
        $this->customProductRepository = $customProductRepository;
    }
    
    /**
     * @Route("/sample", name="sample")
     * @Template("sample.twig")
     */
    public function index(Request $request)
    { 
        $form = $this->createForm(SortType::class);      
        $form->handleRequest($request);

        $direction = 'DESC'; // デフォルトのソート方向(IDが新しい順)

        // フォームが送信された場合
        if ($form->isSubmitted() && $form->isValid()) {
            $orderBy = $form->get('orderBy')->getData(); // 選択されたソート順
            
            // ソートの方向を決定
            if ($orderBy === 'old') {
                $direction = 'ASC'; // 古参順(IDが古い順)
            }
        }
          
        // IDに基づいてソート
        $TagProducts = $this->customProductRepository->findProductsByTagId(4, $direction);
        
        return [
            'TagProducts' => $TagProducts,
            'form' => $form->createView(),
        ];
    }
}

フォームが送信された場合、されていない場合で処理を分岐させます。
また、ルーティングやタグIDなどは使用したい状況に合わせて修正します。

STEP

Twigテンプレートの作成

最後に、Twigテンプレートにフォームを埋め込んで完成です。

{% extends 'default_frame.twig' %}

{% block stylesheet %}
<style>
    .sortForm-container {
        display: flex;
        justify-content: flex-end;
        width: 100%;
        margin: 16px 0;
    }
</style>
{% endblock %}

{% block main %}
<div class="sortForm-container">
  {{ form_start(form, {'attr': {'id': 'sortForm'}}) }}
    {{ form_widget(form.orderBy, {'attr': {'onchange': 'this.form.submit()'}}) }}
  {{ form_end(form) }}
</div>
  <div class="ec-shelfRole">
      <ul class="ec-shelfGrid">
          {# TagProductsに格納されているデータを順に取り出し、TagProductに代入 #}
          {% for TagProduct in TagProducts %}
              <li class="ec-shelfGrid__item">
                {# 商品画像の表示 #}
                <p class="ec-shelfGrid__item-image">
                    <img src="{{ asset(TagProduct.main_list_image|no_image_product, 'save_image') }}" alt="{{ TagProduct.name }}" loading="lazy">
                </p>
                {# 商品名の表示 #}
                <p>{{ TagProduct.name }}</p>
                {# 価格の表示 #}
                <p class="price02-default">
                    {% if TagProduct.hasProductClass %}
                        {% if TagProduct.getPrice02Min == TagProduct.getPrice02Max %}
                            {{ TagProduct.getPrice02IncTaxMin|price }}
                        {% else %}
                            {{ TagProduct.getPrice02IncTaxMin|price }} ~ {{ TagProduct.getPrice02IncTaxMax|price }}
                        {% endif %}
                    {% else %}
                        {{ TagProduct.getPrice02IncTaxMin|price }}
                    {% endif %}
                </p>
              </li>
          {% endfor %}
      </ul>
  </div>
{% endblock %}

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