商品のおすすめ順並び替えは
こちらのプラグインを使っています:
https://github.com/EC-CUBE/ProductRank-pluginマスターデータ管理から、mtb_product_list_order_by に 「3, おすすめ順」を登録し、
商品おすすめ順を上記プラグインで設定しました。
フロントの商品一覧のソート機能は提供されていないみたいなので、
とりあえず、
ProductRepository#getQueryBuilderBySearchData
を直接以下のように変更して試してみました。
変更前:
// Order By
// 価格順
if (!empty($searchData['orderby']) && $searchData['orderby']->getId() == '1') {
//@see http://doctrine-orm.readthedocs.org/en/latest/reference/dql-doctrine-query-language.html
$qb->addSelect('MIN(pc.price02) as HIDDEN price02_min');
$qb->innerJoin('p.ProductClasses', 'pc');
$qb->groupBy('p');
$qb->orderBy('price02_min', 'ASC');
// 新着順
} else if (!empty($searchData['orderby']) && $searchData['orderby']->getId() == '2') {
$qb->orderBy('p.create_date', 'DESC');
} else {
if ($categoryJoin === false) {
$qb
->leftJoin('p.ProductCategories', 'pct')
->leftJoin('pct.Category', 'c');
}
$qb
->addOrderBy('p.id', 'DESC');
}
return $qb;
変更後(おすすめ順追加):
// Order By
// 価格順
if (!empty($searchData['orderby']) && $searchData['orderby']->getId() == '1') {
//@see http://doctrine-orm.readthedocs.org/en/latest/reference/dql-doctrine-query-language.html
$qb->addSelect('MIN(pc.price02) as HIDDEN price02_min');
$qb->innerJoin('p.ProductClasses', 'pc');
$qb->groupBy('p');
$qb->orderBy('price02_min', 'ASC');
// 新着順
} else if (!empty($searchData['orderby']) && $searchData['orderby']->getId() == '2') {
$qb->orderBy('p.create_date', 'DESC');
// おすすめ順
} else if (!empty($searchData['orderby']) && $searchData['orderby']->getId() == '3') {
$qb->orderBy('pct.rank', 'DESC');
} else {
if ($categoryJoin === false) {
$qb
->leftJoin('p.ProductCategories', 'pct')
->leftJoin('pct.Category', 'c');
}
$qb
->addOrderBy('p.id', 'DESC');
}
return $qb;
そうすると、子孫カテゴリーを持たないカテゴリーのおすすめ順の場合は、
うまくページャーが機能するのですが、
子孫カテゴリーを持つカテゴリーのおすすめ順の場合は
同じ商品が複数回表示されてしまいます。
xdebugで処理を追っていった所、
Doctrine\ORM\Tools\Pagination\Paginator.phpの151行目の
$ids = array_map('current', $subQuery->getScalarResult());
ここで、実際に表示する商品のid一覧を取得していることがわかりました。
取得のためのSQLは以下のような感じです:
SELECT DISTINCT d0_.product_id AS product_id0,
d1_.rank AS rank1
FROM dtb_product d0_
INNER JOIN dtb_product_category d1_ ON d0_.product_id = d1_.product_id
INNER JOIN dtb_category d2_ ON d1_.category_id = d2_.category_id
AND (d2_.del_flg = 0)
WHERE (d0_.status = 1
AND d1_.category_id IN (1, 20, 19, 18, 17, 16, 15, 14))
AND (d0_.del_flg = 0)
ORDER BY d1_.rank DESC
LIMIT 15 OFFSET 15
;
上の SQLの select の d1_.rank AS rank1 があるために、重複が除去できていない状態だと思いました。なので
SELECT DISTINCT d0_.product_id AS product_id0,
d1_.rank AS rank1
を
SELECT DISTINCT d0_.product_id AS product_id0
というふうに、 d1_.rank AS rank1 を追加しないようにしたいのですが、
これはできそうでしょうか。
あるいは、もっと他の方法はありませんでしょうか。
どなたかお知恵をお貸しいただければ幸いです。 m(_ _)m