app/Customize/Repository/Extension/ProductRepositoryExtension.php line 35

Open in your IDE?
  1. <?php
  2. namespace Customize\Repository\Extension;
  3. use Eccube\Repository\ProductRepository;
  4. use Eccube\Repository\QueryKey;
  5. use Eccube\Entity\Product;
  6. use Plugin\Maker42\Entity\Maker;
  7. use Eccube\Util\StringUtil;
  8. use Eccube\Entity\Master\ProductStatus;
  9. use Eccube\Common\EccubeConfig;
  10. use Eccube\Doctrine\Query\Queries;
  11. use Doctrine\Persistence\ManagerRegistry;
  12. use Symfony\Contracts\Cache\CacheInterface;
  13. use Symfony\Contracts\Cache\ItemInterface;
  14. class ProductRepositoryExtension extends ProductRepository
  15. {
  16.     /**
  17.      * @var CacheInterface
  18.      */
  19.     private CacheInterface $cache;
  20.     /**
  21.      * カテゴリ別商品数のキャッシュ有効期間(秒)
  22.      */
  23.     private const CATEGORY_COUNT_CACHE_LIFETIME 3600;
  24.     public function __construct(
  25.         ManagerRegistry $registry,
  26.         Queries $queries,
  27.         EccubeConfig $eccubeConfig,
  28.         CacheInterface $cache
  29.     ) {
  30.         parent::__construct($registry$queries$eccubeConfig);
  31.         $this->cache $cache;
  32.     }
  33.     /**
  34.      * get query builder.
  35.      *
  36.      * @param  array $searchData
  37.      *
  38.      * @return \Doctrine\ORM\QueryBuilder
  39.      */
  40.     public function customizeGetQueryBuilderBySearchData($searchData)
  41.     {
  42.         $qb $this->createQueryBuilder('p')
  43.             ->andwhere('p.Status = :Disp')
  44.             ->setParameter('Disp'ProductStatus::DISPLAY_SHOW);
  45.         // category
  46.         $categoryJoin false;
  47.         if (!empty($searchData['category_id']) && $searchData['category_id']) {
  48.             $Categories $searchData['category_id']->getSelfAndDescendants();
  49.             if ($Categories) {
  50.                 $qb
  51.                     ->innerJoin('p.ProductCategories''pct')
  52.                     ->innerJoin('pct.Category''c')
  53.                     ->andWhere($qb->expr()->in('pct.Category'':Categories'))
  54.                     ->setParameter('Categories'$Categories);
  55.                 $categoryJoin true;
  56.             }
  57.         }
  58.         //maker
  59.         $qb
  60.             ->leftJoin('p.Maker''m');
  61.         if (!empty($searchData['maker_id']) && $searchData['maker_id']) {
  62.             $qb
  63.                 ->andWhere('m = :id')
  64.                 ->setParameter('id'$searchData['maker_id']);
  65.         }
  66.         //stock又は新商品のみ
  67.         if (empty($searchData['nostock']) || (!empty($searchData['new']) && $searchData['new'])) {
  68.             $qb
  69.                 ->leftJoin('p.ProductClasses''pcl');
  70.         }
  71.         //stock
  72.         if (empty($searchData['nostock'])) {
  73.             $qb
  74.                 ->andWhere('pcl.stock > 0');
  75.         }
  76.         //新商品のみ(2週間以内の発売日)
  77.         if (!empty($searchData['new'])) {
  78.             $today date("Y-m-d");
  79.             //eccubeで登録される時間が日本時間の6時間前になる為、2週間+6時間前をの日付を取得
  80.             $two_week_ago date("Y-m-d"strtotime("{$today} -2 week -6 hour"));
  81.             $qb
  82.                 ->andWhere(" '{$two_week_ago}' <= pcl.release_date and pcl.release_date < '{$today}' ");
  83.         }
  84.         //タグ検索 TOPページスライダー
  85.         if (!empty($searchData['tag_slider']) && $searchData['tag_slider']) {
  86.             $qb
  87.                 ->innerJoin('p.ProductTag''pt')
  88.                 ->innerJoin('pt.Tag''tag')
  89.                 ->andWhere("tag.name = '{$searchData['tag_slider']}'");
  90.         }
  91.         // name
  92.         if (isset($searchData['name']) && StringUtil::isNotBlank($searchData['name'])) {
  93.             //スペース、全角スペースで分割
  94.             $keywords preg_split('/[\s ]+/u'str_replace(['%''_'], ['\\%''\\_'], $searchData['name']), -1PREG_SPLIT_NO_EMPTY);
  95.             foreach ($keywords as $index => $keyword) {
  96.                 $key sprintf('keyword%s'$index);
  97.                 $qb
  98.                     ->andWhere(sprintf(
  99.                         'NORMALIZE(m.name) LIKE NORMALIZE(:%s) OR
  100.                         REPLACE(REPLACE(NORMALIZE(p.name), \'゙\', \'\'), \'゚\', \'\') LIKE REPLACE(REPLACE(NORMALIZE(:%s), \'゙\', \'\'), \'゚\', \'\') OR
  101.                         NORMALIZE(p.search_word) LIKE NORMALIZE(:%s) OR
  102.                         NORMALIZE(p.description_detail) LIKE NORMALIZE(:%s) OR
  103.                         NORMALIZE(p.free_area) LIKE NORMALIZE(:%s) OR
  104.                         EXISTS (SELECT wpc%d FROM \Eccube\Entity\ProductClass wpc%d WHERE p = wpc%d.Product AND NORMALIZE(wpc%d.code) LIKE NORMALIZE(:%s))',
  105.                         $key,
  106.                         $key,
  107.                         $key,
  108.                         $key,
  109.                         $key,
  110.                         $index,
  111.                         $index,
  112.                         $index,
  113.                         $index,
  114.                         $key
  115.                     ))
  116.                     ->setParameter($key'%' $keyword '%');
  117.             }
  118.         }
  119.         // Order By
  120.         // 価格低い順
  121.         $config $this->eccubeConfig;
  122.         if (!empty($searchData['orderby']) && $searchData['orderby']->getId() == $config['eccube_product_order_price_lower']) {
  123.             // @see http://doctrine-orm.readthedocs.org/en/latest/reference/dql-doctrine-query-language.html
  124.             $qb->addSelect('MIN(pc.price02) as HIDDEN price02_min');
  125.             $qb->innerJoin('p.ProductClasses''pc');
  126.             $qb->andWhere('pc.visible = true');
  127.             $qb->groupBy('p.id');
  128.             $qb->orderBy('price02_min''ASC');
  129.             $qb->addOrderBy('p.id''ASC');
  130.             // 価格高い順
  131.         } elseif (!empty($searchData['orderby']) && $searchData['orderby']->getId() == $config['eccube_product_order_price_higher']) {
  132.             $qb->addSelect('MAX(pc.price02) as HIDDEN price02_max');
  133.             $qb->innerJoin('p.ProductClasses''pc');
  134.             $qb->andWhere('pc.visible = true');
  135.             $qb->groupBy('p.id');
  136.             $qb->orderBy('price02_max''DESC');
  137.             $qb->addOrderBy('p.id''ASC');
  138.             // 新着順
  139.         } elseif (!empty($searchData['orderby']) && $searchData['orderby']->getId() == $config['eccube_product_order_newer']) {
  140.             // 在庫切れ商品非表示の設定が有効時対応
  141.             // @see https://github.com/EC-CUBE/ec-cube/issues/1998
  142.             if ($this->getEntityManager()->getFilters()->isEnabled('option_nostock_hidden') == true) {
  143.                 $qb->innerJoin('p.ProductClasses''pc');
  144.                 $qb->andWhere('pc.visible = true');
  145.             }
  146.             $qb->orderBy('p.create_date''DESC');
  147.             $qb->addOrderBy('p.id''ASC');
  148.         } elseif (!empty($searchData['orderby']) && $searchData['orderby']->getId() == $config['eccube_product_order_best_seller']) {
  149.             //売れ筋順
  150.         } elseif (!empty($searchData['orderby']) && $searchData['orderby']->getId() == $config['eccube_product_order_japanese_asc']) {
  151.             // 五十音順(昇順)
  152.             if ($this->getEntityManager()->getFilters()->isEnabled('option_nostock_hidden') == true) {
  153.                 $qb->innerJoin('p.ProductClasses''pc');
  154.                 $qb->andWhere('pc.visible = true');
  155.             }
  156.             $qb->addOrderBy('p.kana''ASC');
  157.         } elseif (!empty($searchData['orderby']) && $searchData['orderby']->getId() == $config['eccube_product_order_japanese_desc']) {
  158.             // 五十音順(降順)
  159.             if ($this->getEntityManager()->getFilters()->isEnabled('option_nostock_hidden') == true) {
  160.                 $qb->innerJoin('p.ProductClasses''pc');
  161.                 $qb->andWhere('pc.visible = true');
  162.             }
  163.             $qb->addOrderBy('p.kana''DESC');
  164.         } elseif (!empty($searchData['orderby']) && $searchData['orderby']->getId() == $config['eccube_product_order_maker_part_number_asc']) {
  165.             // 品番順(昇順)
  166.             if ($this->getEntityManager()->getFilters()->isEnabled('option_nostock_hidden') == true) {
  167.                 $qb->innerJoin('p.ProductClasses''pc');
  168.                 $qb->andWhere('pc.visible = true');
  169.             }
  170.             $qb->addOrderBy('p.makerPartNumber''ASC');
  171.         } elseif (!empty($searchData['orderby']) && $searchData['orderby']->getId() == $config['eccube_product_order_maker_part_number_desc']) {
  172.             // 品番順(降順)
  173.             if ($this->getEntityManager()->getFilters()->isEnabled('option_nostock_hidden') == true) {
  174.                 $qb->innerJoin('p.ProductClasses''pc');
  175.                 $qb->andWhere('pc.visible = true');
  176.             }
  177.             $qb->addOrderBy('p.makerPartNumber''DESC');
  178.         } else {
  179.             if ($categoryJoin === false) {
  180.                 $qb
  181.                     ->leftJoin('p.ProductCategories''pct')
  182.                     ->leftJoin('pct.Category''c');
  183.             }
  184.             $qb
  185.                 ->addOrderBy('p.id''ASC');
  186.         }
  187.         return $this->queries->customize(QueryKey::PRODUCT_SEARCH$qb$searchData);
  188.     }
  189.     public function findProductsWithCategoriesCount()
  190.     {
  191.         return $this->cache->get('categories_product_count', function (ItemInterface $item) {
  192.             $item->expiresAfter(self::CATEGORY_COUNT_CACHE_LIFETIME);
  193.             $qb $this->createQueryBuilder('p');
  194.             $result $qb
  195.                 ->select('c.id,COUNT(p.id) as cnt')
  196.                 ->where('p.Status = :Disp')
  197.                 ->setParameter('Disp'ProductStatus::DISPLAY_SHOW)
  198.                 ->innerJoin('p.ProductCategories''pct')
  199.                 ->innerJoin('pct.Category''c')
  200.                 ->groupBy('c.id')
  201.                 ->getQuery()
  202.                 ->getResult();
  203.             $counts = [];
  204.             foreach ($result as $r) {
  205.                 $counts[$r['id']] = $r['cnt'];
  206.             }
  207.             return $counts;
  208.         });
  209.     }
  210.     /**
  211.      * カテゴリ別の商品数を取得(在庫切れ商品を除外)
  212.      *
  213.      * @return array カテゴリID => 商品数 の連想配列
  214.      */
  215.     public function findProductsWithCategoriesCountInStock()
  216.     {
  217.         return $this->cache->get('categories_product_count_in_stock', function (ItemInterface $item) {
  218.             $item->expiresAfter(self::CATEGORY_COUNT_CACHE_LIFETIME);
  219.             $qb $this->createQueryBuilder('p');
  220.             $result $qb
  221.                 ->select('c.id, COUNT(DISTINCT p.id) as cnt')
  222.                 ->where('p.Status = :Disp')
  223.                 ->setParameter('Disp'ProductStatus::DISPLAY_SHOW)
  224.                 ->innerJoin('p.ProductCategories''pct')
  225.                 ->innerJoin('pct.Category''c')
  226.                 ->innerJoin('p.ProductClasses''pc')
  227.                 ->andWhere('pc.stock > 0')
  228.                 ->groupBy('c.id')
  229.                 ->getQuery()
  230.                 ->getResult();
  231.             $counts = [];
  232.             foreach ($result as $r) {
  233.                 $counts[$r['id']] = $r['cnt'];
  234.             }
  235.             return $counts;
  236.         });
  237.     }
  238.     public function findProductsWithMakersCount($maker_id)
  239.     {
  240.         $qb $this->createQueryBuilder('p');
  241.         // maker
  242.         if ($maker_id) {
  243.             return $qb
  244.                 ->where('p.Status = :Disp')
  245.                 ->setParameter('Disp'ProductStatus::DISPLAY_SHOW#公開になっているもの
  246.                 ->leftJoin('p.Maker''m')
  247.                 ->select('COUNT(m.id)')
  248.                 ->andWhere('m.id =' $maker_id)
  249.                 ->getQuery() #作成したクエリを取得
  250.                 ->getSingleScalarResult(); #実行 getSingleScalarResultはcountした時、数値が取得できます。
  251.         }
  252.     }
  253.     public function findProductsStockCount($id)
  254.     {
  255.         $qb $this->createQueryBuilder('p');
  256.         if ($id) {
  257.             return $qb
  258.                 ->where('p.Status = :Disp')
  259.                 ->setParameter('Disp'ProductStatus::DISPLAY_SHOW#公開になっているもの
  260.                 ->leftJoin('p.ProductClasses''pc')
  261.                 ->select('pc.stock')
  262.                 ->andWhere('p.id =' $id)
  263.                 ->getQuery() #作成したクエリを取得
  264.                 ->getSingleScalarResult(); #実行 getSingleScalarResultはcountした時、数値が取得できます。
  265.         }
  266.     }
  267.     /**
  268.      * Find the Products with sorted ClassCategories.
  269.      *
  270.      * @param array $ids Product in ids
  271.      * @param string $indexBy The index for the from.
  272.      *
  273.      * @return ArrayCollection|array
  274.      */
  275.     public function findProductsWithSortedClassCategories(array $ids$indexBy null)
  276.     {
  277.         if (count($ids) < 1) {
  278.             return [];
  279.         }
  280.         $qb $this->createQueryBuilder('p'$indexBy);
  281.         $qb->addSelect(['pc''cc1''cc2''pi''pt''tr''ps'])
  282.             ->innerJoin('p.ProductClasses''pc')
  283.             // XXX Joined 'TaxRule' and 'ProductStock' to prevent lazy loading
  284.             ->leftJoin('pc.TaxRule''tr')
  285.             ->leftJoin('pc.ProductStock''ps')
  286.             ->leftJoin('pc.ClassCategory1''cc1')
  287.             ->leftJoin('pc.ClassCategory2''cc2')
  288.             ->leftJoin('p.ProductImage''pi')
  289.             ->leftJoin('p.ProductTag''pt')
  290.             ->where($qb->expr()->in('p.id'$ids))
  291.             ->andWhere('pc.visible = :visible')
  292.             ->setParameter('visible'true)
  293.             ->orderBy('cc1.sort_no''DESC')
  294.             ->addOrderBy('cc2.sort_no''DESC');
  295.         $products $qb
  296.             ->getQuery()
  297.             ->useResultCache(true$this->eccubeConfig['eccube_result_cache_lifetime_short'])
  298.             ->getResult();
  299.         return $products;
  300.     }
  301. }