app/Customize/Repository/ProductRepository.php line 156

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of EC-CUBE
  4.  *
  5.  * Copyright(c) EC-CUBE CO.,LTD. All Rights Reserved.
  6.  *
  7.  * http://www.ec-cube.co.jp/
  8.  *
  9.  * For the full copyright and license information, please view the LICENSE
  10.  * file that was distributed with this source code.
  11.  */
  12. namespace Customize\Repository;
  13. use Customize\Controller\Trait\ConstanceTrait;
  14. use Doctrine\Common\Collections\ArrayCollection;
  15. use Doctrine\Persistence\ManagerRegistry as RegistryInterface;
  16. use Eccube\Common\EccubeConfig;
  17. use Eccube\Doctrine\Query\Queries;
  18. use Eccube\Entity\Category;
  19. use Eccube\Entity\Product;
  20. use Eccube\Entity\ProductStock;
  21. use Eccube\Util\StringUtil;
  22. use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
  23. use Customize\Common\Constants;
  24. use Eccube\Repository\QueryKey;
  25. use Carbon\Carbon;
  26. use Doctrine\ORM\EntityManagerInterface;
  27. use Eccube\Entity\Order;
  28. use Eccube\Entity\OrderItem;
  29. use Customize\Entity\OrderDetailAdditionalInfo;
  30. /**
  31.  * ProductRepository
  32.  *
  33.  * This class was generated by the Doctrine ORM. Add your own custom
  34.  * repository methods below.
  35.  */
  36. class ProductRepository extends ServiceEntityRepository
  37. {
  38.     use ConstanceTrait;
  39.     /**
  40.      * @var Queries
  41.      */
  42.     protected $queries;
  43.     /**
  44.      * @var EccubeConfig
  45.      */
  46.     protected $eccubeConfig;
  47.     public const COLUMNS = [
  48.         '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',
  49.     ];
  50.     /**
  51.      * ProductRepository constructor.
  52.      *
  53.      * @param RegistryInterface $registry
  54.      * @param Queries $queries
  55.      * @param EccubeConfig $eccubeConfig
  56.      */
  57.     public function __construct(
  58.         RegistryInterface $registry,
  59.         Queries $queries,
  60.         EccubeConfig $eccubeConfig,
  61.         private EntityManagerInterface $entityManager,
  62.     ) {
  63.         parent::__construct($registryProduct::class);
  64.         $this->queries $queries;
  65.         $this->eccubeConfig $eccubeConfig;
  66.         $this->setUpValue();
  67.     }
  68.     /**
  69.      * Find the Product with sorted ClassCategories.
  70.      *
  71.      * @param integer $productId
  72.      *
  73.      * @return Product
  74.      */
  75.     public function findWithSortedClassCategories($productId)
  76.     {
  77.         $qb $this->createQueryBuilder('p');
  78.         $qb->addSelect(['pc''cc1''cc2''pi''pt'])
  79.             ->innerJoin('p.ProductClasses''pc')
  80.             ->leftJoin('pc.ClassCategory1''cc1')
  81.             ->leftJoin('pc.ClassCategory2''cc2')
  82.             ->leftJoin('p.ProductImage''pi')
  83.             ->leftJoin('p.ProductTag''pt')
  84.             ->where('p.id = :id')
  85.             ->andWhere('pc.visible = :visible')
  86.             ->setParameter('id'$productId)
  87.             ->setParameter('visible'true)
  88.             ->orderBy('cc1.sort_no''DESC')
  89.             ->addOrderBy('cc2.sort_no''DESC');
  90.         $product $qb
  91.             ->getQuery()
  92.             ->getSingleResult();
  93.         return $product;
  94.     }
  95.     /**
  96.      * Find the Products with sorted ClassCategories.
  97.      *
  98.      * @param array $ids Product in ids
  99.      * @param string $indexBy The index for the from.
  100.      *
  101.      * @return ArrayCollection|array
  102.      */
  103.     public function findProductsWithSortedClassCategories(array $ids$indexBy null)
  104.     {
  105.         if (count($ids) < 1) {
  106.             return [];
  107.         }
  108.         $qb $this->createQueryBuilder('p'$indexBy);
  109.         $qb->addSelect(['pc''cc1''cc2''pi''pt''tr''ps'])
  110.             ->innerJoin('p.ProductClasses''pc')
  111.             // XXX Joined 'TaxRule' and 'ProductStock' to prevent lazy loading
  112.             ->leftJoin('pc.TaxRule''tr')
  113.             ->innerJoin('pc.ProductStock''ps')
  114.             ->leftJoin('pc.ClassCategory1''cc1')
  115.             ->leftJoin('pc.ClassCategory2''cc2')
  116.             ->leftJoin('p.ProductImage''pi')
  117.             ->leftJoin('p.ProductTag''pt')
  118.             ->where($qb->expr()->in('p.id'$ids))
  119.             ->andWhere('pc.visible = :visible')
  120.             ->setParameter('visible'true)
  121.             ->orderBy('cc1.sort_no''DESC')
  122.             ->addOrderBy('cc2.sort_no''DESC');
  123.         $products $qb
  124.             ->getQuery()
  125.             ->useResultCache(true$this->eccubeConfig['eccube_result_cache_lifetime_short'])
  126.             ->getResult();
  127.         return $products;
  128.     }
  129.     /**
  130.      * get query builder.
  131.      *
  132.      * @param array{
  133.      *         category_id?:Category,
  134.      *         name?:string,
  135.      *         pageno?:string,
  136.      *         disp_number?:ProductListMax,
  137.      *         orderby?:ProductListOrderBy
  138.      *     } $searchData
  139.      *
  140.      * @return \Doctrine\ORM\QueryBuilder
  141.      */
  142.     public function getQueryBuilderBySearchData($searchData$entityManager$categories$date null)
  143.     {
  144.         $qb $this->createQueryBuilder('p')
  145.             ->andWhere('p.Status = 1');
  146.         // Remove id of product china and english
  147.         $connection $entityManager->getConnection();
  148.         $productForeignSQL "
  149.                 SELECT plg_expand_product_columns_value.product_id
  150.                 FROM plg_expand_product_columns_value
  151.                 WHERE column_id=:column_id and value in (:china,:english)";
  152.         $productForeignIds $connection->prepare($productForeignSQL);
  153.         $productForeignIdsResultSet $productForeignIds->executeQuery(
  154.             [
  155.                 'column_id' => Constants::LOCALE_RECORD_ID,
  156.                 'china' => Constants::LOCALE_CHINA,
  157.                 'english' => Constants::LOCALE_ENGLISH
  158.             ]
  159.         );
  160.         $producForeigntNeedIgnore $productForeignIdsResultSet->fetchAllAssociative();
  161.         $qb->andWhere($qb->expr()->notIn('p.id'':product_foreign'))
  162.             ->setParameter('product_foreign'$producForeigntNeedIgnore);
  163.         $categoryJoin false;
  164.         if (!empty($searchData['category_id']) && $searchData['category_id']) {
  165.             $Categories $searchData['category_id']->getSelfAndDescendants();
  166.             if ($Categories) {
  167.                 $qb
  168.                     ->innerJoin('p.ProductCategories''pct')
  169.                     ->innerJoin('pct.Category''c')
  170.                     ->andWhere($qb->expr()->in('pct.Category'':Categories'))
  171.                     ->setParameter('Categories'$Categories);
  172.                 $categoryJoin true;
  173.             }
  174.         }
  175.         // categories
  176.         if (!empty($categories) && $categories) {
  177.             $count 0;
  178.             foreach ($categories as $category) {
  179.                 $str '';
  180.                 $arr = [];
  181.                 foreach ($category as $cat) {
  182.                     if (is_numeric($cat)) {
  183.                         $arr[] =    $cat;
  184.                     }
  185.                 }
  186.                 // Group category to select "and"
  187.                 if (!empty($arr)) {
  188.                     $count++;
  189.                     $qb->innerJoin('p.ProductCategories''pct' $count);
  190.                     $str .= 'pct' $count '.Category IN (' implode(','$arr) . ')';
  191.                     $qb->andWhere($str);
  192.                 }
  193.             }
  194.         }
  195.         // name
  196.         if (isset($searchData['name']) && StringUtil::isNotBlank($searchData['name'])) {
  197.             $keywords preg_split('/[\s ]+/u'str_replace(['%''_'], ['\\%''\\_'], $searchData['name']), -1PREG_SPLIT_NO_EMPTY);
  198.             foreach ($keywords as $index => $keyword) {
  199.                 $key sprintf('keyword%s'$index);
  200.                 $qb
  201.                     ->andWhere(sprintf(
  202.                         'NORMALIZE(p.name) LIKE NORMALIZE(:%s) OR
  203.                         NORMALIZE(p.search_word) LIKE NORMALIZE(:%s) OR
  204.                         EXISTS (SELECT wpc%d FROM \Eccube\Entity\ProductClass wpc%d WHERE p = wpc%d.Product AND NORMALIZE(wpc%d.code) LIKE NORMALIZE(:%s))',
  205.                         $key,
  206.                         $key,
  207.                         $index,
  208.                         $index,
  209.                         $index,
  210.                         $index,
  211.                         $key
  212.                     ))
  213.                     ->setParameter($key'%' $keyword '%');
  214.             }
  215.         }
  216.         // Order By
  217.         // 価格低い順
  218.         $config $this->eccubeConfig;
  219.         if (!empty($searchData['orderby']) && $searchData['orderby']->getId() == $config['eccube_product_order_price_lower']) {
  220.             // @see http://doctrine-orm.readthedocs.org/en/latest/reference/dql-doctrine-query-language.html
  221.             $qb->addSelect('MIN(pc.price02) as HIDDEN price02_min');
  222.             $qb->innerJoin('p.ProductClasses''pc');
  223.             $qb->andWhere('pc.visible = true');
  224.             $qb->groupBy('p.id');
  225.             $qb->orderBy('price02_min''ASC');
  226.             $qb->addOrderBy('p.id''DESC');
  227.             // 価格高い順
  228.         } elseif (!empty($searchData['orderby']) && $searchData['orderby']->getId() == $config['eccube_product_order_price_higher']) {
  229.             $qb->addSelect('MAX(pc.price02) as HIDDEN price02_max');
  230.             $qb->innerJoin('p.ProductClasses''pc');
  231.             $qb->andWhere('pc.visible = true');
  232.             $qb->groupBy('p.id');
  233.             $qb->orderBy('price02_max''DESC');
  234.             $qb->addOrderBy('p.id''DESC');
  235.             // 新着順
  236.         } elseif (!empty($searchData['orderby']) && $searchData['orderby']->getId() == $config['eccube_product_order_newer']) {
  237.             // 在庫切れ商品非表示の設定が有効時対応
  238.             // @see https://github.com/EC-CUBE/ec-cube/issues/1998
  239.             if ($this->getEntityManager()->getFilters()->isEnabled('option_nostock_hidden') == true) {
  240.                 $qb->innerJoin('p.ProductClasses''pc');
  241.                 $qb->andWhere('pc.visible = true');
  242.             }
  243.             $qb->orderBy('p.create_date''DESC');
  244.             $qb->addOrderBy('p.id''DESC');
  245.         } else {
  246.             if ($categoryJoin === false) {
  247.                 $qb
  248.                     ->leftJoin('p.ProductCategories''pct')
  249.                     ->leftJoin('pct.Category''c');
  250.             }
  251.             $qb
  252.                 ->addOrderBy('p.id''DESC');
  253.         }
  254.         $dateObject \DateTime::createFromFormat('Y-m-d'$date);
  255.         $isValidDate $dateObject && $dateObject->format('Y-m-d') === $date;
  256.         // Search use day
  257.         if ($isValidDate) {
  258.             if ($_SERVER['SERVER_NAME'] == $this->eccubeConfig['salon_domain']) {
  259.                 // Search use days for salon
  260.                 return $this->searchDaysForSalon($date$qb);
  261.             }
  262.             $beforeUseDay $this->DEFAULT_BEFORE_USE_DAYS;
  263.             $afterUseDay $this->DEFAULT_AFTER_USE_DAYS;
  264.             $conn $entityManager->getConnection();
  265.             // Join 3 tables to get id products need ignore for filter feature
  266.             $sql "
  267.                 SELECT dtb_order_item.product_id
  268.                 FROM plg_order_detail_additional_info
  269.                 JOIN dtb_order_item ON dtb_order_item.id = plg_order_detail_additional_info.order_detail_id
  270.                 JOIN dtb_order ON dtb_order.id = dtb_order_item.order_id
  271.                 LEFT JOIN plg_product_use_days ON plg_product_use_days.product_id = dtb_order_item.product_id
  272.                 WHERE
  273.                     wear_date BETWEEN IF(
  274.                         plg_order_detail_additional_info.before_use_days,
  275.                         DATE_SUB(
  276.                             :use_date,
  277.                             INTERVAL IF(wear_date >= :use_date, plg_order_detail_additional_info.before_use_days, plg_order_detail_additional_info.after_use_days) DAY
  278.                         ),
  279.                         DATE_SUB(:use_date, INTERVAL :before_use_day DAY)
  280.                     )
  281.                     AND
  282.                     IF(
  283.                         plg_order_detail_additional_info.after_use_days,
  284.                         DATE_ADD(
  285.                             :use_date,
  286.                             INTERVAL IF(wear_date > :use_date, plg_order_detail_additional_info.before_use_days, plg_order_detail_additional_info.after_use_days) DAY
  287.                         ),
  288.                         DATE_ADD(:use_date, INTERVAL :after_use_day DAY)
  289.                     )";
  290.             $stmt $conn->prepare($sql);
  291.             $resultSet $stmt->executeQuery(
  292.                 [
  293.                     'use_date' => $date,
  294.                     'before_use_day' => $beforeUseDay,
  295.                     'after_use_day' => $afterUseDay,
  296.                 ]
  297.             );
  298.             $productNeedIgnore $resultSet->fetchAllAssociative();
  299.             if ($productNeedIgnore) {
  300.                 $qb->andWhere(
  301.                     $qb->expr()->notIn('p.id'':products_need_ignore')
  302.                 )
  303.                     ->setParameter('products_need_ignore'$productNeedIgnore);
  304.             }
  305.         }
  306.         return $this->queries->customize(QueryKey::PRODUCT_SEARCH$qb$searchData);
  307.     }
  308.     /**
  309.      * Filter ignore product has order in salon
  310.      *
  311.      * @param $date
  312.      * @param $qb
  313.      * @return void
  314.      */
  315.     private function searchDaysForSalon($date$qb)
  316.     {
  317.         $dateFormat Carbon::parse($date);
  318.         $fittingDateAddAfterUseDays $dateFormat->copy()->addDays(Constants::FITTING_AFTER_USE_DAYS)->toDateString();
  319.         $fittingDateAddBeforeUseDays $dateFormat->copy()->subDays(Constants::FITTING_BEFORE_USE_DAYS)->toDateString();
  320.         $normalDateAddAfterUseDays $dateFormat->copy()->addDays($this->DEFAULT_AFTER_USE_DAYS)->toDateString();
  321.         $normalDateAddBeforeUseDays $dateFormat->copy()->subDays($this->DEFAULT_BEFORE_USE_DAYS)->toDateString();
  322.         $usedProducts $this->entityManager
  323.             ->createQueryBuilder()
  324.             ->select('odi')
  325.             ->from(OrderDetailAdditionalInfo::class, 'odai')
  326.             ->innerJoin(Order::class, 'od''WITH''odai.order_id = od.id')
  327.             ->innerJoin(OrderItem::class, 'odi''WITH''odai.order_detail_id = odi.id')
  328.             ->andWhere('(
  329.             (odai.wear_date BETWEEN :wear_date_fitting_before AND :wear_date_fitting_after AND odai.order_type = :fitting_type)
  330.             OR
  331.             (odai.wear_date BETWEEN :wear_date_normal_before AND :wear_date_normal_after AND odai.order_type <> :fitting_type)
  332.         )')
  333.             ->setParameter('wear_date_fitting_after'$fittingDateAddAfterUseDays)
  334.             ->setParameter('wear_date_fitting_before'$fittingDateAddBeforeUseDays)
  335.             ->setParameter('wear_date_normal_after'$normalDateAddAfterUseDays)
  336.             ->setParameter('wear_date_normal_before'$normalDateAddBeforeUseDays)
  337.             ->setParameter('fitting_type''fitting')
  338.             ->getQuery()
  339.             ->getResult();
  340.         $productNeedIgnoreInSalon = [];
  341.         foreach ($usedProducts as $usedProduct) {
  342.             array_push($productNeedIgnoreInSalon, ['product_id' => $usedProduct->getId()]);
  343.         }
  344.         if ($productNeedIgnoreInSalon) {
  345.             $qb->andWhere(
  346.                 $qb->expr()->notIn('p.id'':products_need_ignore')
  347.             )
  348.                 ->setParameter('products_need_ignore'$productNeedIgnoreInSalon);
  349.         }
  350.         return $qb;
  351.     }
  352.     /**
  353.      * get query builder.
  354.      *
  355.      * @param array{
  356.      *         id?:string|int|null,
  357.      *         category_id?:Category,
  358.      *         status?:ProductStatus[],
  359.      *         link_status?:ProductStatus[],
  360.      *         stock_status?:int,
  361.      *         stock?:ProductStock::IN_STOCK|ProductStock::OUT_OF_STOCK,
  362.      *         tag_id?:Tag,
  363.      *         create_datetime_start?:\DateTime,
  364.      *         create_datetime_end?:\DateTime,
  365.      *         create_date_start?:\DateTime,
  366.      *         create_date_end?:\DateTime,
  367.      *         update_datetime_start?:\DateTime,
  368.      *         update_datetime_end?:\DateTime,
  369.      *         update_date_start?:\DateTime,
  370.      *         update_date_end?:\DateTime,
  371.      *         sortkey?:string,
  372.      *         sorttype?:string
  373.      *     } $searchData
  374.      *
  375.      * @return \Doctrine\ORM\QueryBuilder
  376.      */
  377.     public function getQueryBuilderBySearchDataForAdmin($searchData)
  378.     {
  379.         $qb $this->createQueryBuilder('p')
  380.             ->addSelect('pc''pi''tr''ps')
  381.             ->innerJoin('p.ProductClasses''pc')
  382.             ->leftJoin('p.ProductImage''pi')
  383.             ->leftJoin('pc.TaxRule''tr')
  384.             ->leftJoin('pc.ProductStock''ps')
  385.             ->andWhere('pc.visible = :visible')
  386.             ->setParameter('visible'true);
  387.         // id
  388.         if (isset($searchData['id']) && StringUtil::isNotBlank($searchData['id'])) {
  389.             $id preg_match('/^\d{0,10}$/'$searchData['id']) ? $searchData['id'] : null;
  390.             if ($id && $id '2147483647' && $this->isPostgreSQL()) {
  391.                 $id null;
  392.             }
  393.             $qb
  394.                 ->andWhere('p.id = :id OR p.name LIKE :likeid OR pc.code LIKE :likeid')
  395.                 ->setParameter('id'$id)
  396.                 ->setParameter('likeid''%' str_replace(['%''_'], ['\\%''\\_'], $searchData['id']) . '%');
  397.         }
  398.         // category
  399.         if (!empty($searchData['category_id']) && $searchData['category_id']) {
  400.             $Categories $searchData['category_id']->getSelfAndDescendants();
  401.             if ($Categories) {
  402.                 $qb
  403.                     ->innerJoin('p.ProductCategories''pct')
  404.                     ->innerJoin('pct.Category''c')
  405.                     ->andWhere($qb->expr()->in('pct.Category'':Categories'))
  406.                     ->setParameter('Categories'$Categories);
  407.             }
  408.         }
  409.         // status
  410.         if (!empty($searchData['status']) && $searchData['status']) {
  411.             $qb
  412.                 ->andWhere($qb->expr()->in('p.Status'':Status'))
  413.                 ->setParameter('Status'$searchData['status']);
  414.         }
  415.         // link_status
  416.         if (isset($searchData['link_status']) && !empty($searchData['link_status'])) {
  417.             $qb
  418.                 ->andWhere($qb->expr()->in('p.Status'':Status'))
  419.                 ->setParameter('Status'$searchData['link_status']);
  420.         }
  421.         // stock status
  422.         if (isset($searchData['stock_status'])) {
  423.             $qb
  424.                 ->andWhere('pc.stock_unlimited = :StockUnlimited AND pc.stock = 0')
  425.                 ->setParameter('StockUnlimited'$searchData['stock_status']);
  426.         }
  427.         // stock status
  428.         if (isset($searchData['stock']) && !empty($searchData['stock'])) {
  429.             switch ($searchData['stock']) {
  430.                 case [ProductStock::IN_STOCK]:
  431.                     $qb->andWhere('pc.stock_unlimited = true OR pc.stock > 0');
  432.                     break;
  433.                 case [ProductStock::OUT_OF_STOCK]:
  434.                     $qb->andWhere('pc.stock_unlimited = false AND pc.stock <= 0');
  435.                     break;
  436.                 default:
  437.                     // 共に選択された場合は全権該当するので検索条件に含めない
  438.             }
  439.         }
  440.         // tag
  441.         if (!empty($searchData['tag_id']) && $searchData['tag_id']) {
  442.             $qb
  443.                 ->innerJoin('p.ProductTag''pt')
  444.                 ->andWhere('pt.Tag = :tag_id')
  445.                 ->setParameter('tag_id'$searchData['tag_id']);
  446.         }
  447.         // crate_date
  448.         if (!empty($searchData['create_datetime_start']) && $searchData['create_datetime_start']) {
  449.             $date $searchData['create_datetime_start'];
  450.             $qb
  451.                 ->andWhere('p.create_date >= :create_date_start')
  452.                 ->setParameter('create_date_start'$date);
  453.         } elseif (!empty($searchData['create_date_start']) && $searchData['create_date_start']) {
  454.             $date $searchData['create_date_start'];
  455.             $qb
  456.                 ->andWhere('p.create_date >= :create_date_start')
  457.                 ->setParameter('create_date_start'$date);
  458.         }
  459.         if (!empty($searchData['create_datetime_end']) && $searchData['create_datetime_end']) {
  460.             $date $searchData['create_datetime_end'];
  461.             $qb
  462.                 ->andWhere('p.create_date < :create_date_end')
  463.                 ->setParameter('create_date_end'$date);
  464.         } elseif (!empty($searchData['create_date_end']) && $searchData['create_date_end']) {
  465.             $date = clone $searchData['create_date_end'];
  466.             $date $date
  467.                 ->modify('+1 days');
  468.             $qb
  469.                 ->andWhere('p.create_date < :create_date_end')
  470.                 ->setParameter('create_date_end'$date);
  471.         }
  472.         // update_date
  473.         if (!empty($searchData['update_datetime_start']) && $searchData['update_datetime_start']) {
  474.             $date $searchData['update_datetime_start'];
  475.             $qb
  476.                 ->andWhere('p.update_date >= :update_date_start')
  477.                 ->setParameter('update_date_start'$date);
  478.         } elseif (!empty($searchData['update_date_start']) && $searchData['update_date_start']) {
  479.             $date $searchData['update_date_start'];
  480.             $qb
  481.                 ->andWhere('p.update_date >= :update_date_start')
  482.                 ->setParameter('update_date_start'$date);
  483.         }
  484.         if (!empty($searchData['update_datetime_end']) && $searchData['update_datetime_end']) {
  485.             $date $searchData['update_datetime_end'];
  486.             $qb
  487.                 ->andWhere('p.update_date < :update_date_end')
  488.                 ->setParameter('update_date_end'$date);
  489.         } elseif (!empty($searchData['update_date_end']) && $searchData['update_date_end']) {
  490.             $date = clone $searchData['update_date_end'];
  491.             $date $date
  492.                 ->modify('+1 days');
  493.             $qb
  494.                 ->andWhere('p.update_date < :update_date_end')
  495.                 ->setParameter('update_date_end'$date);
  496.         }
  497.         // Order By
  498.         if (isset($searchData['sortkey']) && !empty($searchData['sortkey'])) {
  499.             $sortOrder = (isset($searchData['sorttype']) && $searchData['sorttype'] == 'a') ? 'ASC' 'DESC';
  500.             $qb->orderBy(self::COLUMNS[$searchData['sortkey']], $sortOrder);
  501.             $qb->addOrderBy('p.update_date''DESC');
  502.             $qb->addOrderBy('p.id''DESC');
  503.         } else {
  504.             $qb->orderBy('p.update_date''DESC');
  505.             $qb->addOrderBy('p.id''DESC');
  506.         }
  507.         return $this->queries->customize(QueryKey::PRODUCT_SEARCH_ADMIN$qb$searchData);
  508.     }
  509.     public function getProductByIds(array $ids)
  510.     {
  511.         $products =  $this->createQueryBuilder('p')
  512.             ->addSelect(['p''pi''pc'])
  513.             ->andWhere('p.id in (:ids)')
  514.             ->leftJoin('p.ProductImage''pi')
  515.             ->innerJoin('p.ProductClasses''pc')
  516.             ->setParameter('ids'$ids)
  517.             ->getQuery()
  518.             ->execute();
  519.         // Create array null with count($ids) { [0 => null, 1=> null] }
  520.         $sortedResults array_fill(0count($ids), null);
  521.         // Rearrange the display array in the correctpassed in ids
  522.         foreach ($products as $result) {
  523.             // Find index id in $ids
  524.             $index array_search($result->getId(), $ids);
  525.             if ($index !== false) {
  526.                 $sortedResults[$index] = $result;
  527.             }
  528.         }
  529.         return $sortedResults;
  530.     }
  531. }