BeginnerEngineerBlog
中の人
中の人

【Doctrine】ECCUBE4系でDoctrineでCASE文を使ってデータを任意の順番にソートする

公開: 2022-01-16 21:10
更新: 2023-04-06 14:52
1544
ECCUBE4.1 doctrine CASE symfony4.x
ECCUBE4系のdoctrineでCASE文を使用する紹介になります。

こんにちは!

中の人です!

ECCUBE4系はphpフレームワークのsymfony4系が使用されています。

で、symfony4系でデータベースと連携する際、doctrineというORMが利用されています。

ORMとは、データベースの連携をし易くしてくれる仕組みのことです。

ということでタイトル通りdoctrineでCASE文を使ってデータを任意の順番に並び替える方法を紹介します!


前提条件


今回は商品一覧画面の商品の並びを操作したいと思います。
(あらかじめCustomizeディレクトリに商品一覧を取得する関数を用意しています。Repositoryのカスタマイズのやり方は【ECCUBE4】Repositoryをカスタマイズするを参考にしてください。)

商品のデータは以下の通りです。


あらかじめデータを一つ追加しておきました。

現在の商品一覧画面は以下の通りです。

では、この商品の並びを、idの順番で
  • 価格が低い順
  • 1(彩のジェラートCUBE)
  • 3(ビギナーキューブアイス)
  • 2(チェリーアイスサンド)
  • 価格が高い順
  • 3(ビギナーキューブアイス)
  • 1(彩のジェラートCUBE)
  • 2(チェリーアイスサンド)
となるようにしてみます!


やり方


「// 👇書き換え」の部分を元の処理と変更している部分です。

📁 app/Customize/Repository/Extension/ProductRepositoryExtension.php

<?php

namespace Customize\Repository\Extension;

use Eccube\Repository\ProductRepository;
use Eccube\Repository\QueryKey;
use Eccube\Util\StringUtil;

class ProductRepositoryExtension extends ProductRepository
{
    /**
     * get query builder.
     *
     * @param  array $searchData
     *
     * @return \Doctrine\ORM\QueryBuilder
     */
    public function getQueryBuilderBySearchData($searchData)
    {
        $qb = $this->createQueryBuilder('p')
            ->andWhere('p.Status = 1');

        // category
        $categoryJoin = false;
        if (!empty($searchData['category_id']) && $searchData['category_id']) {
            $Categories = $searchData['category_id']->getSelfAndDescendants();
            if ($Categories) {
                $qb
                    ->innerJoin('p.ProductCategories', 'pct')
                    ->innerJoin('pct.Category', 'c')
                    ->andWhere($qb->expr()->in('pct.Category', ':Categories'))
                    ->setParameter('Categories', $Categories);
                $categoryJoin = true;
            }
        }

        // name
        if (isset($searchData['name']) && StringUtil::isNotBlank($searchData['name'])) {
            $keywords = preg_split('/[\s ]+/u', str_replace(['%', '_'], ['\\%', '\\_'], $searchData['name']), -1, PREG_SPLIT_NO_EMPTY);

            foreach ($keywords as $index => $keyword) {
                $key = sprintf('keyword%s', $index);
                $qb
                    ->andWhere(sprintf('NORMALIZE(p.name) LIKE NORMALIZE(:%s) OR
                        NORMALIZE(p.search_word) LIKE NORMALIZE(:%s) OR
                        EXISTS (SELECT wpc%d FROM \Eccube\Entity\ProductClass wpc%d WHERE p = wpc%d.Product AND NORMALIZE(wpc%d.code) LIKE NORMALIZE(:%s))',
                        $key, $key, $index, $index, $index, $index, $key))
                    ->setParameter($key, '%'.$keyword.'%');
            }
        }

        // Order By
        // 価格低い順
        $config = $this->eccubeConfig;
        if (!empty($searchData['orderby']) && $searchData['orderby']->getId() == $config['eccube_product_order_price_lower']) {
            //@see http://doctrine-orm.readthedocs.org/en/latest/reference/dql-doctrine-query-language.html
            // 👇書き換え
            $qb->addSelect('(CASE WHEN p.id = :one THEN 1 WHEN p.id = :three THEN 2 WHEN p.id = :two THEN 3 ELSE 9999 END) AS HIDDEN CUSTOME_ORDER')
                ->setParameter('one', 1)
                ->setParameter('three', 3)
                ->setParameter('two', 2);
            $qb->innerJoin('p.ProductClasses', 'pc');
            $qb->andWhere('pc.visible = true');
            $qb->groupBy('p.id');
            // 👇書き換え
            $qb->orderBy('CUSTOME_ORDER', 'ASC');
            $qb->addOrderBy('p.id', 'DESC');
            // 価格高い順
        } elseif (!empty($searchData['orderby']) && $searchData['orderby']->getId() == $config['eccube_product_order_price_higher']) {
            // 👇書き換え
            $qb->addSelect('(CASE WHEN p.id = :three THEN 1 WHEN p.id = :one THEN 2 WHEN p.id = :two THEN 3 ELSE 9999 END) AS HIDDEN CUSTOME_ORDER')
                ->setParameter('one', 1)
                ->setParameter('three', 3)
                ->setParameter('two', 2);
            $qb->innerJoin('p.ProductClasses', 'pc');
            $qb->andWhere('pc.visible = true');
            $qb->groupBy('p.id');
            // 👇書き換え
            $qb->orderBy('CUSTOME_ORDER, p.id');
            $qb->addOrderBy('p.id', 'DESC');
            // 新着順
        } elseif (!empty($searchData['orderby']) && $searchData['orderby']->getId() == $config['eccube_product_order_newer']) {
            // 在庫切れ商品非表示の設定が有効時対応
            // @see https://github.com/EC-CUBE/ec-cube/issues/1998
            if ($this->getEntityManager()->getFilters()->isEnabled('option_nostock_hidden') == true) {
                $qb->innerJoin('p.ProductClasses', 'pc');
                $qb->andWhere('pc.visible = true');
            }
            $qb->orderBy('p.create_date', 'DESC');
            $qb->addOrderBy('p.id', 'DESC');
        } else {
            if ($categoryJoin === false) {
                $qb
                    ->leftJoin('p.ProductCategories', 'pct')
                    ->leftJoin('pct.Category', 'c');
            }
            $qb
                ->addOrderBy('p.id', 'DESC');
        }

        return $this->queries->customize(QueryKey::PRODUCT_SEARCH, $qb, $searchData);
    }
}



// ~~省略
$qb->addSelect('(CASE WHEN p.id = :three THEN 1 WHEN p.id = :one THEN 2 WHEN p.id = :two THEN 3 ELSE 9999 END) AS HIDDEN CUSTOME_ORDER')
                ->setParameter('one', 1)
                ->setParameter('three', 3)
                ->setParameter('two', 2);
// ~~ 省略
$qb->orderBy('CUSTOME_ORDER', 'ASC');

こんな感じでCASE文を使うことができます!

また、orderByですが、価格高い順で指定しているように

$qb->orderBy('CUSTOME_ORDER, p.id');

こんな感じで指定することもできます。

では実際の画面を見てみましょう。

まずは価格が低い順


次に価格が高い順


ちゃんと動いてますね!

これでデータの順番を任意の順番にすることができます!

ということで紹介を終わります!


終わりに


doctrineて難しいですよね。というかsymfonyが難しい。。
最初doctrineを見た時はわけわからん状態でした。まぁ今でもよくわかってませんが。

doctrineでCASE文を使う方法は結構ネットに上がってたのですが、setParameterで値をセットする方法があまりなかった様に感じて、できるんかなーと思ってやってみたらできたので紹介してみました。

ちなみに私がCASE文を使った箇所はformTypeのoptionのquery_builderで実装しました。

ということでこんな実装したい方は参考にしてみてください!

ではまた!
0
0
0
0
通信エラーが発生しました。
【広告】
似たような記事