src/Widget/CatalogWidget.php line 224

Open in your IDE?
  1. <?php
  2. namespace App\Widget;
  3. use Doctrine\ORM\QueryBuilder;
  4. use Doctrine\ORM\UnexpectedResultException;
  5. use MLDev\BaseBundle\Entity\Page;
  6. use MLDev\BaseBundle\Paginator\Pagination\PaginationInterface;
  7. use MLDev\BaseBundle\Paginator\Paginator;
  8. use MLDev\BaseBundle\Repository\PageRepository;
  9. use MLDev\BaseBundle\Widget\AbstractWidget;
  10. use MLDev\CatalogBundle\Entity\Product;
  11. use MLDev\CatalogBundle\Entity\ProductItem;
  12. use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
  13. use Symfony\Component\Form\Extension\Core\Type\TextType;
  14. use Symfony\Component\Form\FormBuilderInterface;
  15. class CatalogWidget extends AbstractWidget
  16. {
  17.     /**
  18.      * @var array
  19.      */
  20.     private array $availableSortingRules = [
  21.         'relevance_asc' => 'По популярности',
  22.         'name_asc' => 'По наименованию',
  23.         'price_asc' => 'По возрастанию цены',
  24.         'price_desc' => 'По убыванию цены',
  25.     ];
  26.     private array $optionNameList = [];
  27.     private array $optionLabelList = [];
  28.     public function execute(array $options): string
  29.     {
  30.         /**
  31.          * @var Page $page
  32.          */
  33.         $page $this->getContextValue('page');
  34.         $queryBuilder $this->getProductItemQueryByPages(
  35.             $this->getChildPagesId($page),
  36.             $this->getSortingRules()
  37.         );
  38.         if (($prices $this->getPricesFromQuery())) {
  39.             if ($prices['from_price_value'] && $prices['to_price_value']) {
  40.                 $queryBuilder->andWhere(
  41.                     $queryBuilder->expr()->between(
  42.                         'Price.value',
  43.                         $prices['from_price_value'],
  44.                         $prices['to_price_value']
  45.                     )
  46.                 );
  47.             }
  48.         }
  49.         foreach ($this->optionNameList as $fieldName) {
  50.             if (($filterValue $this->getRequest()->query->get($fieldName, [])) && !empty($filterValue)) {
  51.                 $queryBuilder->andWhere(
  52.                     $queryBuilder->expr()->in('ProductItem.' $fieldName$filterValue)
  53.                 );
  54.             }
  55.         }
  56.         return $this->render('widget/catalog/default.html.twig', [
  57.             'page' => $page,
  58.             'product_item_list' => $queryBuilder->getQuery()->getResult(),
  59.             'available_sorting_rules' => $this->availableSortingRules,
  60.             'statistics_on_prices' => $this->getStatisticsOnPrices($page),
  61.             'statistics_on_options' => $this->getStatisticsOnOptions($page),
  62.         ]);
  63.     }
  64.     public function getName(): string
  65.     {
  66.         return 'Список товаров';
  67.     }
  68.     public function configure(FormBuilderInterface $builder, array $options): FormBuilderInterface
  69.     {
  70.         $builder
  71.             ->add('title'TextType::class, [
  72.                 'label' => 'Заголовок',
  73.                 'required' => false,
  74.             ])
  75.             ->add('is_show_children_category'CheckboxType::class, [
  76.                 'label' => 'Показывать подкатегории',
  77.                 'required' => false,
  78.                 'label_attr' => ['class' => 'switch-custom'],
  79.             ]);
  80.         return $builder;
  81.     }
  82.     private function getPricesFromQuery(): array
  83.     {
  84.         $prices $this->getRequest()->query->get('prices''');
  85.         if (($prices explode(';'$prices)) && is_array($prices)) {
  86.             $prices array_filter($prices);
  87.         } else {
  88.             $prices = [];
  89.         }
  90.         return array_combine(['from_price_value''to_price_value'], array_pad($prices2null));
  91.     }
  92.     private function getStatisticsOnOptions($page): array
  93.     {
  94.         $statisticsOnOptions = [];
  95.         foreach ($this->optionNameList as $fieldName) {
  96.             $queryBuilder $this->getProductItemQueryByPages(
  97.                 $this->getChildPagesId($page),
  98.                 $this->getSortingRules()
  99.             );
  100.             $queryBuilder->select('ProductItem.' $fieldName)
  101.                 ->andWhere(
  102.                     $queryBuilder->expr()->isNotNull('ProductItem.' $fieldName)
  103.                 )
  104.                 ->groupBy('ProductItem.' $fieldName)
  105.                 ->orderBy('ProductItem.' $fieldName'ASC');
  106.             $statisticsOnOptions[$fieldName] = $queryBuilder->getQuery()->getResult();
  107.         }
  108.         return $statisticsOnOptions;
  109.     }
  110.     private function getStatisticsOnPrices($page): array
  111.     {
  112.         $queryBuilder $this->getProductItemQueryByPages(
  113.             $this->getChildPagesId($page),
  114.             $this->getSortingRules()
  115.         );
  116.         $queryBuilder->select('MIN(Price.value) as min_price_value, MAX(Price.value) as max_price_value');
  117.         try {
  118.             $statisticsOnPrices $queryBuilder->getQuery()->getSingleResult();
  119.         } catch (UnexpectedResultException $exception) {
  120.             $statisticsOnPrices = [
  121.                 'min_price_value' => null,
  122.                 'max_price_value' => null,
  123.             ];
  124.         }
  125.         return array_merge($statisticsOnPrices$this->getPricesFromQuery());
  126.     }
  127.     /**
  128.      * @param mixed $queryBuilder
  129.      * @return PaginationInterface
  130.      */
  131.     private function getPagination($queryBuilder): PaginationInterface
  132.     {
  133.         /** @var integer $pageLimit */
  134.         $pageLimit $this->getRequest()->query->get('page'1);
  135.         $paginator = new Paginator();
  136.         $pagination $paginator->paginate(
  137.             $queryBuilder$pageLimit$this->getPageLimit(), ['wrap-queries' => true]
  138.         );
  139.         $pagination->renderer = function ($data) {
  140.             return $this->render('@MLDevCatalog/pagination.html.twig'$data);
  141.         };
  142.         return $pagination;
  143.     }
  144.     /**
  145.      * @param Page $entity
  146.      * @return array
  147.      */
  148.     private function getChildPagesId(Page $entity): array
  149.     {
  150.         /**
  151.          * @var PageRepository $repository
  152.          */
  153.         $repository $this->getDoctrine()->getRepository(Page::class);
  154.         $children $repository->getChildrenIds($entity);
  155.         $children[] = $entity->getId();
  156.         return $children;
  157.     }
  158.     /**
  159.      * @return mixed|string
  160.      */
  161.     private function getViewMode(): mixed
  162.     {
  163.         if (($viewMode $this->getRequest()->query->get('view'))) {
  164.             if (!in_array($viewMode, ['row''card'])) {
  165.                 $viewMode 'card';
  166.             }
  167.             if ($viewMode !== $this->getRequest()->getSession()->get('mldev-catalog-view')) {
  168.                 $this->getRequest()->getSession()->set('mldev-catalog-view'$viewMode);
  169.             }
  170.         } else {
  171.             $viewMode $this->getRequest()->getSession()->get('mldev-catalog-view''card');
  172.         }
  173.         return $viewMode;
  174.     }
  175.     /**
  176.      * @return mixed|string
  177.      */
  178.     private function getSortingRules(): mixed
  179.     {
  180.         if (($sortingRule $this->getRequest()->query->get('sorting'))) {
  181.             if (!in_array($sortingRulearray_keys($this->availableSortingRules))) {
  182.                 $sortingRule Product::ORDER_BY_PRIORITY;
  183.             }
  184.             if ($sortingRule !== $this->getRequest()->getSession()->get('mldev-catalog-sorting')) {
  185.                 $this->getRequest()->getSession()->set('mldev-catalog-sorting'$sortingRule);
  186.             }
  187.         } else {
  188.             $sortingRule $this->getRequest()->getSession()->get('mldev-catalog-sorting''relevance_asc');
  189.         }
  190.         return $sortingRule;
  191.     }
  192.     /**
  193.      * @return int
  194.      */
  195.     private function getPageLimit(): int
  196.     {
  197.         if (($pageLimit $this->getRequest()->query->get('limit'))) {
  198.             $pageLimit $pageLimit 48 48 $pageLimit;
  199.             if ($pageLimit !== $this->getRequest()->getSession()->get('mldev-catalog-page-limit')) {
  200.                 $this->getRequest()->getSession()->set('mldev-catalog-page-limit'$pageLimit);
  201.             }
  202.         } else {
  203.             $pageLimit $this->getRequest()->getSession()->get('mldev-catalog-page-limit'12);
  204.         }
  205.         return $pageLimit;
  206.     }
  207.     /**
  208.      * @param array $pages
  209.      * @param string|null $orderBy
  210.      * @return QueryBuilder
  211.      */
  212.     private function getProductItemQueryByPages(array $pages, ?string $orderBy null): QueryBuilder
  213.     {
  214.         $predicates sprintf('Page.id in (%s)'implode(','$pages));
  215.         $qb $this->getDoctrine()->createQueryBuilder();
  216.         $qb $qb
  217.             ->select(['ProductItem''Product'])
  218.             ->from(ProductItem::class, 'ProductItem')
  219.             ->join('ProductItem.product''Product')
  220.             ->join('Product.pages''Page')
  221.             ->leftJoin('ProductItem.prices''Price')
  222.             ->where($predicates)
  223.             ->andWhere('Product.isActive = true')
  224.             ->andWhere('ProductItem.isActive = true');
  225.         if (true === (bool)$this->getRequest()->query->get('available'false)) {
  226.             $qb->andWhere(
  227.                 $qb->expr()->gt('ProductItem.amount'0)
  228.             );
  229.         }
  230.         if ($orderBy == 'price_asc') {
  231.             $qb->addOrderBy('Price.value''ASC');
  232.         }
  233.         if ($orderBy == 'price_desc') {
  234.             $qb->addOrderBy('Price.value''DESC');
  235.         }
  236.         if ($orderBy == 'name_asc') {
  237.             $qb->addOrderBy('ProductItem.name''ASC');
  238.         }
  239.         if ($orderBy == 'relevance_asc') {
  240.             $qb->addOrderBy('ProductItem.amount''DESC');
  241.         }
  242.         $qb->addOrderBy('Product.priority''DESC');
  243.         $qb->addOrderBy('Product.id''ASC');
  244.         return $qb;
  245.     }
  246. }