src/Eccube/Repository/ProductRepository.php line 104

Open in your IDE?
  1. <?php
  2. namespace Eccube\Repository;
  3. use Doctrine\Common\Collections\ArrayCollection;
  4. use Doctrine\Persistence\ManagerRegistry as RegistryInterface;
  5. use Eccube\Common\EccubeConfig;
  6. use Eccube\Doctrine\Query\Queries;
  7. use Eccube\Entity\Category;
  8. use Eccube\Entity\Master\ProductListMax;
  9. use Eccube\Entity\Master\ProductListOrderBy;
  10. use Eccube\Entity\Master\ProductStatus;
  11. use Eccube\Entity\Product;
  12. use Eccube\Entity\ProductStock;
  13. use Eccube\Entity\Tag;
  14. use Eccube\Util\StringUtil;
  15. use Plugin\Recommend42\Entity\RecommendProduct;
  16. /**
  17.  * ProductRepository
  18.  *
  19.  * This class was generated by the Doctrine ORM. Add your own custom
  20.  * repository methods below.
  21.  */
  22. class ProductRepository extends AbstractRepository
  23. {
  24.   /**
  25.    * @var Queries
  26.    */
  27.   protected $queries;
  28.   /**
  29.    * @var EccubeConfig
  30.    */
  31.   protected $eccubeConfig;
  32.   public const COLUMNS = [
  33.     'product_id' => 'p.id''name' => 'p.name''product_code' => 'pc.code''stock' => 'pc.stock''status' => 'p.Status''create_date' => 'p.create_date''update_date' => 'p.update_date',
  34.   ];
  35.   /**
  36.    * ProductRepository constructor.
  37.    *
  38.    * @param RegistryInterface $registry
  39.    * @param Queries $queries
  40.    * @param EccubeConfig $eccubeConfig
  41.    */
  42.   public function __construct(
  43.     RegistryInterface $registry,
  44.     Queries           $queries,
  45.     EccubeConfig      $eccubeConfig
  46.   )
  47.   {
  48.     parent::__construct($registryProduct::class);
  49.     $this->queries $queries;
  50.     $this->eccubeConfig $eccubeConfig;
  51.   }
  52.   /**
  53.    * 子カテゴリー一覧をハッシュで取得
  54.    * @param integer $p_id
  55.    * @return hash
  56.    */
  57.   public function getHashStatus()
  58.   {
  59.     $conn $this->getEntityManager()->getConnection();
  60.     $sql "SELECT id,product_status_id FROM dtb_product";
  61.     $stmt $conn->prepare($sql);
  62.     $resultSet $stmt->executeQuery();
  63.     $rows $resultSet->fetchAllAssociative();
  64.     $hash = array();
  65.     foreach ($rows as $row) {
  66.       $hash[$row["id"]] = $row["product_status_id"];
  67.     }
  68.     return $hash;
  69.   }
  70.   /**
  71.    * Find the Product with sorted ClassCategories.
  72.    *
  73.    * @param integer $productId
  74.    *
  75.    * @return Product
  76.    */
  77.   public function findWithSortedClassCategories($productId)
  78.   {
  79.     $qb $this->createQueryBuilder('p');
  80.     $qb->addSelect(['pc''cc1''cc2''pi''pt'])
  81.       ->innerJoin('p.ProductClasses''pc')
  82.       ->leftJoin('pc.ClassCategory1''cc1')
  83.       ->leftJoin('pc.ClassCategory2''cc2')
  84.       ->leftJoin('p.ProductImage''pi')
  85.       ->leftJoin('p.ProductTag''pt')
  86.       ->where('p.id = :id')
  87.       ->andWhere('pc.visible = :visible')
  88.       ->setParameter('id'$productId)
  89.       ->setParameter('visible'true)
  90.       ->orderBy('cc1.sort_no''DESC')
  91.       ->addOrderBy('cc2.sort_no''DESC');
  92.     $product $qb
  93.       ->getQuery()
  94.       ->getSingleResult();
  95.     return $product;
  96.   }
  97.   /**
  98.    * Find the Products with sorted ClassCategories.
  99.    *
  100.    * @param array $ids Product in ids
  101.    * @param string $indexBy The index for the from.
  102.    *
  103.    * @return ArrayCollection|array
  104.    */
  105.   public function findProductsWithSortedClassCategories(array $ids$indexBy null)
  106.   {
  107.     if (count($ids) < 1) {
  108.       return [];
  109.     }
  110.     $qb $this->createQueryBuilder('p'$indexBy);
  111.     $qb->addSelect(['pc''cc1''cc2''pi''pt''tr''ps'])
  112.       ->innerJoin('p.ProductClasses''pc')
  113.       // XXX Joined 'TaxRule' and 'ProductStock' to prevent lazy loading
  114.       ->leftJoin('pc.TaxRule''tr')
  115.       ->innerJoin('pc.ProductStock''ps')
  116.       ->leftJoin('pc.ClassCategory1''cc1')
  117.       ->leftJoin('pc.ClassCategory2''cc2')
  118.       ->leftJoin('p.ProductImage''pi')
  119.       ->leftJoin('p.ProductTag''pt')
  120.       ->where($qb->expr()->in('p.id'$ids))
  121.       ->andWhere('pc.visible = :visible')
  122.       ->setParameter('visible'true)
  123.       ->orderBy('cc1.sort_no''DESC')
  124.       ->addOrderBy('cc2.sort_no''DESC');
  125.     $products $qb
  126.       ->getQuery()
  127.       ->useResultCache(true$this->eccubeConfig['eccube_result_cache_lifetime_short'])
  128.       ->getResult();
  129.     return $products;
  130.   }
  131.   /**
  132.    * get query builder.
  133.    *
  134.    * @param array{
  135.    *         category_id?:Category,
  136.    *         name?:string,
  137.    *         pageno?:string,
  138.    *         disp_number?:ProductListMax,
  139.    *         orderby?:ProductListOrderBy
  140.    *     } $searchData
  141.    *
  142.    * @return \Doctrine\ORM\QueryBuilder
  143.    */
  144.   public function getQueryBuilderBySearchData($searchData)
  145.   {
  146.     $qb $this->createQueryBuilder('p')
  147.       ->andWhere('((p.Status = 1) OR (p.Status = 6) OR (p.Status = 8))')
  148.       ->andWhere('p.del_flg = 0');
  149.     // category
  150.     $categoryJoin false;
  151.     if (!empty($searchData['category_id']) && $searchData['category_id']) {
  152.       $Categories $searchData['category_id']->getSelfAndDescendants();
  153.       if ($Categories) {
  154.         $qb
  155.           ->innerJoin('p.ProductCategories''pct')
  156.           ->innerJoin('pct.Category''c')
  157.           ->andWhere($qb->expr()->in('pct.Category'':Categories'))
  158.           ->setParameter('Categories'$Categories);
  159.         $categoryJoin true;
  160.       }
  161.     }
  162.     // 複数のカテゴリーに対応
  163.     if (!empty($searchData['c_id']) and is_array($searchData['c_id']) and count($searchData['c_id']) > 0) {
  164.       dump($searchData);exit;
  165.     }
  166.     // name
  167.     if (isset($searchData['name']) && StringUtil::isNotBlank($searchData['name'])) {
  168.       $keywords preg_split('/[\s ]+/u'str_replace(['%''_'], ['\\%''\\_'], $searchData['name']), -1PREG_SPLIT_NO_EMPTY);
  169.       foreach ($keywords as $index => $keyword) {
  170.         $key sprintf('keyword%s'$index);
  171.         $qb
  172.           ->andWhere(sprintf('NORMALIZE(p.name) LIKE NORMALIZE(:%s) OR
  173.                         NORMALIZE(p.search_word) LIKE NORMALIZE(:%s) OR
  174.                         EXISTS (SELECT wpc%d FROM \Eccube\Entity\ProductClass wpc%d WHERE p = wpc%d.Product AND NORMALIZE(wpc%d.code) LIKE NORMALIZE(:%s))',
  175.             $key$key$index$index$index$index$key))
  176.           ->setParameter($key'%' $keyword '%');
  177.       }
  178.     }
  179.     // ============================================================
  180.     // 限定商品の除外処理
  181.     // ============================================================
  182.     // 1. カテゴリーベースの限定商品除外(カテゴリーID: 218)
  183.     // 限定カテゴリーの子カテゴリーに属する商品は除外
  184.     // ただし、限定カテゴリーを直接指定した場合は表示
  185.     $genteiCategoryId 218;
  186.     $isGenteiCategory false;
  187.     if (!empty($searchData['category_id'])) {
  188.       // 指定カテゴリーが限定カテゴリー(218)またはその子孫かチェック
  189.       $category $searchData['category_id'];
  190.       if ($category->getId() == $genteiCategoryId) {
  191.         $isGenteiCategory true;
  192.       } else {
  193.         // 親をたどって限定カテゴリーかチェック
  194.         $parent $category->getParent();
  195.         while ($parent) {
  196.           if ($parent->getId() == $genteiCategoryId) {
  197.             $isGenteiCategory true;
  198.             break;
  199.           }
  200.           $parent $parent->getParent();
  201.         }
  202.       }
  203.     }
  204.     if (!$isGenteiCategory) {
  205.       // 限定カテゴリー以外の場合、限定商品を除外
  206.       $genteiProductIds $this->getGenteiProductIds($genteiCategoryId);
  207.       if (!empty($genteiProductIds)) {
  208.         $qb->andWhere($qb->expr()->notIn('p.id'':genteiProductIds'))
  209.            ->setParameter('genteiProductIds'$genteiProductIds);
  210.       }
  211.     }
  212.     // 2. 拡張項目ベースの限定公開除外(column_id: 66)
  213.     // ProductPlusの限定公開URLに値がある商品は除外
  214.     $genteiUrlProductIds $this->getGenteiUrlProductIds();
  215.     if (!empty($genteiUrlProductIds)) {
  216.       $qb->andWhere($qb->expr()->notIn('p.id'':genteiUrlProductIds'))
  217.          ->setParameter('genteiUrlProductIds'$genteiUrlProductIds);
  218.     }
  219.     // Order By
  220.     // 価格低い順
  221.     $config $this->eccubeConfig;
  222.     if (!empty($searchData['orderby']) && $searchData['orderby']->getId() == $config['eccube_product_order_price_lower']) {
  223.       // @see http://doctrine-orm.readthedocs.org/en/latest/reference/dql-doctrine-query-language.html
  224.       $qb->addSelect('MIN(pc.price02) as HIDDEN price02_min');
  225.       $qb->innerJoin('p.ProductClasses''pc');
  226.       $qb->andWhere('pc.visible = true');
  227.       $qb->groupBy('p.id');
  228.       $qb->orderBy('price02_min''ASC');
  229.       $qb->addOrderBy('p.id''DESC');
  230.       // 価格高い順
  231.     } elseif (!empty($searchData['orderby']) && $searchData['orderby']->getId() == $config['eccube_product_order_price_higher']) {
  232.       $qb->addSelect('MAX(pc.price02) as HIDDEN price02_max');
  233.       $qb->innerJoin('p.ProductClasses''pc');
  234.       $qb->andWhere('pc.visible = true');
  235.       $qb->groupBy('p.id');
  236.       $qb->orderBy('price02_max''DESC');
  237.       $qb->addOrderBy('p.id''DESC');
  238.       // 新着順
  239.     } elseif (!empty($searchData['orderby']) && $searchData['orderby']->getId() == $config['eccube_product_order_newer']) {
  240.       // 在庫切れ商品非表示の設定が有効時対応
  241.       // @see https://github.com/EC-CUBE/ec-cube/issues/1998
  242.       if ($this->getEntityManager()->getFilters()->isEnabled('option_nostock_hidden') == true) {
  243.         $qb->innerJoin('p.ProductClasses''pc');
  244.         $qb->andWhere('pc.visible = true');
  245.       }
  246.       $qb->orderBy('p.create_date''DESC');
  247.       $qb->addOrderBy('p.id''DESC');
  248.     } else {
  249.       if ($categoryJoin === false) {
  250.         $qb
  251.           ->leftJoin('p.ProductCategories''pct')
  252.           ->leftJoin('pct.Category''c');
  253.       }
  254.       $qb
  255.         ->addOrderBy('p.id''DESC');
  256.     }
  257.     //dump($qb->getQuery()->getSQL());exit;
  258.     //$all = $qb->getQuery()->getArrayResult();
  259.     //dump($all);exit;
  260.     return $this->queries->customize(QueryKey::PRODUCT_SEARCH$qb$searchData);
  261.   }
  262.   /**
  263.    * get query builder.
  264.    *
  265.    * @param array{
  266.    *         id?:string|int|null,
  267.    *         category_id?:Category,
  268.    *         status?:ProductStatus[],
  269.    *         link_status?:ProductStatus[],
  270.    *         stock_status?:int,
  271.    *         stock?:ProductStock::IN_STOCK|ProductStock::OUT_OF_STOCK,
  272.    *         tag_id?:Tag,
  273.    *         create_datetime_start?:\DateTime,
  274.    *         create_datetime_end?:\DateTime,
  275.    *         create_date_start?:\DateTime,
  276.    *         create_date_end?:\DateTime,
  277.    *         update_datetime_start?:\DateTime,
  278.    *         update_datetime_end?:\DateTime,
  279.    *         update_date_start?:\DateTime,
  280.    *         update_date_end?:\DateTime,
  281.    *         sortkey?:string,
  282.    *         sorttype?:string
  283.    *     } $searchData
  284.    *
  285.    * @return \Doctrine\ORM\QueryBuilder
  286.    */
  287.   public function getQueryBuilderBySearchDataForAdmin($searchData)
  288.   {
  289.     $qb $this->createQueryBuilder('p')
  290.       ->addSelect('pc''pi''tr''ps')
  291.       ->innerJoin('p.ProductClasses''pc')
  292.       ->leftJoin('p.ProductImage''pi')
  293.       ->leftJoin('pc.TaxRule''tr')
  294.       ->leftJoin('pc.ProductStock''ps')
  295.       ->andWhere('pc.visible = :visible')
  296.       ->setParameter('visible'true)
  297.       ->andWhere('p.del_flg = 0');
  298.     // id(商品ID・商品名・商品コード・検索ワード・鑑定番号)
  299.     if (isset($searchData['id']) && StringUtil::isNotBlank($searchData['id'])) {
  300.       $id preg_match('/^\d{0,10}$/'$searchData['id']) ? $searchData['id'] : null;
  301.       if ($id && $id '2147483647' && $this->isPostgreSQL()) {
  302.         $id null;
  303.       }
  304.       $qb
  305.         ->andWhere('p.id = :id OR p.name LIKE :likeid OR pc.code LIKE :likeid OR p.search_word LIKE :likeid OR EXISTS (SELECT ppd.id FROM Plugin\ProductPlus42\Entity\ProductData ppd INNER JOIN Plugin\ProductPlus42\Entity\ProductDataDetail ppdd WITH ppdd.ProductData = ppd WHERE ppd.Product = p AND ppd.ProductItem = 2 AND ppdd.value LIKE :likeid)')
  306.         ->setParameter('id'$id)
  307.         ->setParameter('likeid''%' str_replace(['%''_'], ['\\%''\\_'], $searchData['id']) . '%');
  308.     }
  309.     // 在庫・お預かり・地金型コイン
  310.     // 1. 在庫    = コインパレスの在庫
  311.     // 2. お預かり = お客さまから預かっているコイン
  312.     // 3. 地金型コイン = カテゴリー地金型を含むコイン
  313.     if (!empty($searchData["custody_flg"]) and count($searchData["custody_flg"]) == 1) {
  314.       $custody_flg $searchData["custody_flg"][0];
  315.       if ($custody_flg == 1) {
  316.         $ids $this->getStorageCpIds();
  317.         $qb->andWhere($qb->expr()->in('p.id'$ids));
  318.       } elseif ($custody_flg == 2) {
  319.         $ids $this->getStorageCustIds();
  320.         $qb->andWhere($qb->expr()->in('p.id'$ids));
  321.       }elseif($custody_flg == 3){
  322.         $Categories = array();
  323.         $categoryRepository $this->getEntityManager()->getRepository(Category::class);
  324.         $Categories[] = $categoryRepository->find("5");
  325.         $qb->innerJoin('p.ProductCategories''pct2')
  326.           ->innerJoin('pct2.Category''c2')
  327.           ->andWhere($qb->expr()->in('pct2.Category'':Categories2'))
  328.           ->setParameter('Categories2'$Categories);
  329.       }
  330.     }
  331.     // category
  332.     if (!empty($searchData['category_id']) && $searchData['category_id']) {
  333.       $Categories $searchData['category_id']->getSelfAndDescendants();
  334.       if ($Categories) {
  335.         $qb
  336.           ->innerJoin('p.ProductCategories''pct')
  337.           ->innerJoin('pct.Category''c')
  338.           ->andWhere($qb->expr()->in('pct.Category'':Categories'))
  339.           ->setParameter('Categories'$Categories);
  340.       }
  341.     }
  342.     // status
  343.     if (!empty($searchData['status']) && $searchData['status']) {
  344.       $qb
  345.         ->andWhere($qb->expr()->in('p.Status'':Status'))
  346.         ->setParameter('Status'$searchData['status']);
  347.     }
  348.     // link_status
  349.     if (isset($searchData['link_status']) && !empty($searchData['link_status'])) {
  350.       $qb
  351.         ->andWhere($qb->expr()->in('p.Status'':Status'))
  352.         ->setParameter('Status'$searchData['link_status']);
  353.     }
  354.     // stock status
  355.     if (isset($searchData['stock_status'])) {
  356.       $qb
  357.         ->andWhere('pc.stock_unlimited = :StockUnlimited AND pc.stock = 0')
  358.         ->setParameter('StockUnlimited'$searchData['stock_status']);
  359.     }
  360.     // stock status
  361.     if (isset($searchData['stock']) && !empty($searchData['stock'])) {
  362.       switch ($searchData['stock']) {
  363.         case [ProductStock::IN_STOCK]:
  364.           $qb->andWhere('pc.stock_unlimited = true OR pc.stock > 0');
  365.           break;
  366.         case [ProductStock::OUT_OF_STOCK]:
  367.           $qb->andWhere('pc.stock_unlimited = false AND pc.stock <= 0');
  368.           break;
  369.         default:
  370.           // 共に選択された場合は全権該当するので検索条件に含めない
  371.       }
  372.     }
  373.     // tag
  374.     if (!empty($searchData['tag_id']) && $searchData['tag_id']) {
  375.       $qb
  376.         ->innerJoin('p.ProductTag''pt')
  377.         ->andWhere('pt.Tag = :tag_id')
  378.         ->setParameter('tag_id'$searchData['tag_id']);
  379.     }
  380.     // crate_date
  381.     if (!empty($searchData['create_datetime_start']) && $searchData['create_datetime_start']) {
  382.       $date $searchData['create_datetime_start'];
  383.       $qb
  384.         ->andWhere('p.create_date >= :create_date_start')
  385.         ->setParameter('create_date_start'$date);
  386.     } elseif (!empty($searchData['create_date_start']) && $searchData['create_date_start']) {
  387.       $date $searchData['create_date_start'];
  388.       $qb
  389.         ->andWhere('p.create_date >= :create_date_start')
  390.         ->setParameter('create_date_start'$date);
  391.     }
  392.     if (!empty($searchData['create_datetime_end']) && $searchData['create_datetime_end']) {
  393.       $date $searchData['create_datetime_end'];
  394.       $qb
  395.         ->andWhere('p.create_date < :create_date_end')
  396.         ->setParameter('create_date_end'$date);
  397.     } elseif (!empty($searchData['create_date_end']) && $searchData['create_date_end']) {
  398.       $date = clone $searchData['create_date_end'];
  399.       $date $date
  400.         ->modify('+1 days');
  401.       $qb
  402.         ->andWhere('p.create_date < :create_date_end')
  403.         ->setParameter('create_date_end'$date);
  404.     }
  405.     // update_date
  406.     if (!empty($searchData['update_datetime_start']) && $searchData['update_datetime_start']) {
  407.       $date $searchData['update_datetime_start'];
  408.       $qb
  409.         ->andWhere('p.update_date >= :update_date_start')
  410.         ->setParameter('update_date_start'$date);
  411.     } elseif (!empty($searchData['update_date_start']) && $searchData['update_date_start']) {
  412.       $date $searchData['update_date_start'];
  413.       $qb
  414.         ->andWhere('p.update_date >= :update_date_start')
  415.         ->setParameter('update_date_start'$date);
  416.     }
  417.     if (!empty($searchData['update_datetime_end']) && $searchData['update_datetime_end']) {
  418.       $date $searchData['update_datetime_end'];
  419.       $qb
  420.         ->andWhere('p.update_date < :update_date_end')
  421.         ->setParameter('update_date_end'$date);
  422.     } elseif (!empty($searchData['update_date_end']) && $searchData['update_date_end']) {
  423.       $date = clone $searchData['update_date_end'];
  424.       $date $date
  425.         ->modify('+1 days');
  426.       $qb
  427.         ->andWhere('p.update_date < :update_date_end')
  428.         ->setParameter('update_date_end'$date);
  429.     }
  430.     // Order By
  431.     if (isset($searchData['sortkey']) && !empty($searchData['sortkey'])) {
  432.       $sortOrder = (isset($searchData['sorttype']) && $searchData['sorttype'] == 'a') ? 'ASC' 'DESC';
  433.       $qb->orderBy(self::COLUMNS[$searchData['sortkey']], $sortOrder);
  434.       $qb->addOrderBy('p.update_date''DESC');
  435.       $qb->addOrderBy('p.id''DESC');
  436.     } else {
  437.       $qb->orderBy('p.id''DESC');
  438.       //$qb->addOrderBy('p.update_date', 'DESC');
  439.     }
  440.     //dump($qb->getQuery()->getSQL());exit;
  441.     //$all = $qb->getQuery()->getArrayResult();
  442.     //dump($all);exit;
  443.     return $this->queries->customize(QueryKey::PRODUCT_SEARCH_ADMIN$qb$searchData);
  444.   }
  445.   /**
  446.    * 商品種別(クレジット可否)をハッシュで取得
  447.    * sale_type_id = 3 がクレジット不可商品
  448.    *
  449.    * @return array
  450.    */
  451.   public function getHashType()
  452.   {
  453.     $conn $this->getEntityManager()->getConnection();
  454.     $sql = <<<SQL
  455. SELECT
  456.     product_id,
  457.     sale_type_id
  458. FROM
  459.     dtb_product_class
  460. WHERE
  461.     visible = 1
  462. SQL;
  463.     $stmt $conn->prepare($sql);
  464.     $resultSet $stmt->executeQuery();
  465.     $rows $resultSet->fetchAllAssociative();
  466.     $hash = array();
  467.     foreach ($rows as $row) {
  468.       $hash[$row['product_id']] = $row['sale_type_id'];
  469.     }
  470.     return $hash;
  471.   }
  472.   /**
  473.    * 地金型コインカテゴリーに属する商品をハッシュで取得
  474.    *
  475.    * @return array
  476.    */
  477.   public function getHashJigane()
  478.   {
  479.     $conn $this->getEntityManager()->getConnection();
  480.     $sql = <<<SQL
  481. SELECT
  482.     product_id,
  483.     category_id
  484. FROM
  485.     dtb_product_category
  486. WHERE
  487.     category_id = 5
  488. SQL;
  489.     $stmt $conn->prepare($sql);
  490.     $resultSet $stmt->executeQuery();
  491.     $rows $resultSet->fetchAllAssociative();
  492.     $hash = array();
  493.     foreach ($rows as $row) {
  494.       $hash[$row['product_id']] = $row['category_id'];
  495.     }
  496.     return $hash;
  497.   }
  498.   /**
  499.    * コインパレスが販売中のコインID一覧を取得
  500.    * @return array
  501.    * @throws \Doctrine\DBAL\Exception
  502.    */
  503.   public function getStorageCpIds()
  504.   {
  505.     $sql = <<<SQL
  506. SELECT
  507.   A.id
  508. FROM
  509.   dtb_product AS A
  510.   INNER JOIN plg_productplus_dtb_product_data AS B ON A.id = B.product_id
  511.   INNER JOIN plg_productplus_dtb_product_data_detail AS C ON B.id = C.product_data_id
  512. WHERE
  513.   B.product_item_id = 6
  514.   AND (C.value = 1424 or C.value = 1427 or C.value = '')
  515. SQL;
  516.     return $this->getIdsFromSQL($sql);
  517.   }
  518.   /**
  519.    * お客さまからの預りコインID一覧を取得
  520.    * @return array
  521.    * @throws \Doctrine\DBAL\Exception
  522.    */
  523.   public function getStorageCustIds()
  524.   {
  525.     $sql = <<<SQL
  526. SELECT
  527.   A.id
  528. FROM
  529.   dtb_product AS A
  530.   INNER JOIN plg_productplus_dtb_product_data AS B ON A.id = B.product_id
  531.   INNER JOIN plg_productplus_dtb_product_data_detail AS C ON B.id = C.product_data_id
  532. WHERE
  533.   B.product_item_id = 6
  534.   AND (C.value != 1424 AND C.value != 1427 AND C.value != '')
  535. SQL;
  536.     return $this->getIdsFromSQL($sql);
  537.   }
  538.   /**
  539.    * SQL文からID一覧を取得
  540.    * @param $sql
  541.    * @return array
  542.    * @throws \Doctrine\DBAL\Exception
  543.    */
  544.   public function getIdsFromSQL($sql){
  545.     $conn $this->getEntityManager()->getConnection();
  546.     $stmt $conn->prepare($sql);
  547.     $resultSet $stmt->executeQuery();
  548.     $rows $resultSet->fetchAllAssociative();
  549.     $ids = array();
  550.     foreach ($rows as $row) {
  551.       $ids[] = $row['id'];
  552.     }
  553.     return $ids;
  554.   }
  555.   /**
  556.    * 限定カテゴリーに属する商品IDを取得
  557.    * @param int $genteiCategoryId 限定親カテゴリーID(デフォルト: 218)
  558.    * @return array 商品IDの配列
  559.    */
  560.   public function getGenteiProductIds(int $genteiCategoryId 218): array
  561.   {
  562.     // 限定カテゴリー(218)とその子カテゴリーのIDを取得
  563.     $categoryIds $this->getGenteiCategoryIds($genteiCategoryId);
  564.     if (empty($categoryIds)) {
  565.       return [];
  566.     }
  567.     // 限定カテゴリーに属する商品IDを取得
  568.     $sql "SELECT DISTINCT product_id AS id FROM dtb_product_category WHERE category_id IN (" implode(','$categoryIds) . ")";
  569.     return $this->getIdsFromSQL($sql);
  570.   }
  571.   /**
  572.    * 限定カテゴリーとその子カテゴリーのIDを取得
  573.    * @param int $parentCategoryId 親カテゴリーID
  574.    * @return array カテゴリーIDの配列
  575.    */
  576.   public function getGenteiCategoryIds(int $parentCategoryId): array
  577.   {
  578.     $conn $this->getEntityManager()->getConnection();
  579.     // 親カテゴリーと全ての子孫カテゴリーを取得(再帰的に)
  580.     $sql = <<<SQL
  581. SELECT id FROM dtb_category
  582. WHERE id = :parent_id
  583.    OR parent_category_id = :parent_id
  584.    OR parent_category_id IN (SELECT id FROM dtb_category WHERE parent_category_id = :parent_id)
  585.    OR parent_category_id IN (SELECT id FROM dtb_category WHERE parent_category_id IN (SELECT id FROM dtb_category WHERE parent_category_id = :parent_id))
  586. SQL;
  587.     $stmt $conn->prepare($sql);
  588.     $resultSet $stmt->executeQuery(['parent_id' => $parentCategoryId]);
  589.     $rows $resultSet->fetchAllAssociative();
  590.     $ids = [];
  591.     foreach ($rows as $row) {
  592.       $ids[] = $row['id'];
  593.     }
  594.     return $ids;
  595.   }
  596.   /**
  597.    * 限定公開URL(column_id=66)に値がある商品IDを取得
  598.    * @return array 商品IDの配列
  599.    */
  600.   public function getGenteiUrlProductIds(): array
  601.   {
  602.     $sql = <<<SQL
  603. SELECT DISTINCT
  604.   ppd.product_id AS id
  605. FROM
  606.   plg_productplus_dtb_product_data AS ppd
  607.   INNER JOIN plg_productplus_dtb_product_data_detail AS ppdd ON ppd.id = ppdd.product_data_id
  608. WHERE
  609.   ppd.product_item_id = 66
  610.   AND ppdd.value IS NOT NULL
  611.   AND ppdd.value != ''
  612. SQL;
  613.     return $this->getIdsFromSQL($sql);
  614.   }
  615. }