vendor/coreshop/core-shop/src/CoreShop/Bundle/FrontendBundle/Controller/CategoryController.php line 277

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. /*
  4.  * CoreShop
  5.  *
  6.  * This source file is available under two different licenses:
  7.  *  - GNU General Public License version 3 (GPLv3)
  8.  *  - CoreShop Commercial License (CCL)
  9.  * Full copyright and license information is available in
  10.  * LICENSE.md which is distributed with this source code.
  11.  *
  12.  * @copyright  Copyright (c) CoreShop GmbH (https://www.coreshop.org)
  13.  * @license    https://www.coreshop.org/license     GPLv3 and CCL
  14.  *
  15.  */
  16. namespace CoreShop\Bundle\FrontendBundle\Controller;
  17. use CoreShop\Component\Core\Configuration\ConfigurationServiceInterface;
  18. use CoreShop\Component\Core\Context\ShopperContextInterface;
  19. use CoreShop\Component\Core\Model\CategoryInterface;
  20. use CoreShop\Component\Core\Repository\CategoryRepositoryInterface;
  21. use CoreShop\Component\Core\Repository\ProductRepositoryInterface;
  22. use CoreShop\Component\Index\Condition\LikeCondition;
  23. use CoreShop\Component\Index\Factory\FilteredListingFactoryInterface;
  24. use CoreShop\Component\Index\Filter\FilterProcessorInterface;
  25. use CoreShop\Component\Index\Listing\ListingInterface;
  26. use CoreShop\Component\Index\Model\FilterInterface;
  27. use CoreShop\Component\Resource\Model\AbstractObject;
  28. use CoreShop\Component\SEO\SEOPresentationInterface;
  29. use CoreShop\Component\Tracking\Tracker\TrackerInterface;
  30. use Knp\Component\Pager\PaginatorInterface;
  31. use Pimcore\Http\RequestHelper;
  32. use Pimcore\Model\DataObject\Data\UrlSlug;
  33. use Symfony\Component\HttpFoundation\Request;
  34. use Symfony\Component\HttpFoundation\Response;
  35. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  36. class CategoryController extends FrontendController
  37. {
  38.     protected array $validSortProperties;
  39.     protected string $repositoryIdentifier 'oo_id';
  40.     protected string $requestIdentifier 'category';
  41.     protected string $defaultSortName;
  42.     protected string $defaultSortDirection;
  43.     public function __construct(
  44.         array $validSortProperties,
  45.         string $defaultSortName,
  46.         string $defaultSortDirection,
  47.     ) {
  48.         $this->validSortProperties $validSortProperties;
  49.         $this->defaultSortName $defaultSortName;
  50.         $this->defaultSortDirection $defaultSortDirection;
  51.     }
  52.     public function menuAction(): Response
  53.     {
  54.         $categories $this->getRepository()->findFirstLevelForStore($this->getContext()->getStore());
  55.         return $this->render($this->templateConfigurator->findTemplate('Category/_menu.html'), [
  56.             'categories' => $categories,
  57.         ]);
  58.     }
  59.     public function menuLeftAction(Request $request): Response
  60.     {
  61.         $activeCategory $this->getParameterFromRequest($request'activeCategory');
  62.         $activeSubCategories = [];
  63.         $firstLevelCategories $this->getRepository()->findFirstLevelForStore($this->getContext()->getStore());
  64.         if ($activeCategory instanceof CategoryInterface) {
  65.             $activeSubCategories $this->getRepository()->findChildCategoriesForStore($activeCategory$this->getContext()->getStore());
  66.         }
  67.         return $this->render($this->templateConfigurator->findTemplate('Category/_menu-left.html'), [
  68.             'categories' => $firstLevelCategories,
  69.             'activeCategory' => $activeCategory,
  70.             'activeSubCategories' => $activeSubCategories,
  71.         ]);
  72.     }
  73.     public function detailSlugAction(Request $requestCategoryInterface $objectUrlSlug $urlSlug): Response
  74.     {
  75.         return $this->detail($request$object);
  76.     }
  77.     public function indexAction(Request $request): Response
  78.     {
  79.         $id $this->getParameterFromRequest($request$this->requestIdentifier);
  80.         $category $this->getRepository()->findOneBy([
  81.             $this->repositoryIdentifier => $id,
  82.             'pimcore_unpublished' => true,
  83.         ]);
  84.         if (!$category instanceof CategoryInterface) {
  85.             throw new NotFoundHttpException(
  86.                 sprintf(
  87.                     'category with identifier "%s" (%s) not found',
  88.                     $this->repositoryIdentifier,
  89.                     $this->getParameterFromRequest($request$this->requestIdentifier),
  90.                 ),
  91.             );
  92.         }
  93.         return $this->detail($request$category);
  94.     }
  95.     public function detail(Request $requestCategoryInterface $category): Response
  96.     {
  97.         $this->denyAccessUnlessGranted('CORESHOP_CATEGORY_SHOW');
  98.         $listModeDefault $this->getConfigurationService()->getForStore('system.category.list.mode');
  99.         $gridPerPageAllowed $this->getConfigurationService()->getForStore('system.category.grid.per_page');
  100.         $gridPerPageDefault $this->getConfigurationService()->getForStore('system.category.grid.per_page.default');
  101.         $listPerPageAllowed $this->getConfigurationService()->getForStore('system.category.list.per_page');
  102.         $listPerPageDefault $this->getConfigurationService()->getForStore('system.category.list.per_page.default');
  103.         $displaySubCategories $this->getConfigurationService()->getForStore('system.category.list.include_subcategories');
  104.         $variantMode $this->getConfigurationService()->getForStore('system.category.variant_mode');
  105.         $page = (int) $this->getParameterFromRequest($request'page'1) ?: 1;
  106.         $type $this->getParameterFromRequest($request'type'$listModeDefault);
  107.         $defaultPerPage $type === 'list' $listPerPageDefault $gridPerPageDefault;
  108.         $allowedPerPage $type === 'list' $listPerPageAllowed $gridPerPageAllowed;
  109.         $perPage = (int) $this->getParameterFromRequest($request'perPage'$defaultPerPage) ?: 10;
  110.         $this->validateCategory($request$category);
  111.         $viewParameters = [];
  112.         if ($category->getFilter() instanceof FilterInterface) {
  113.             $filteredList $this->get(FilteredListingFactoryInterface::class)->createList($category->getFilter(), $request->request);
  114.             $filteredList->setLocale($request->getLocale());
  115.             $filteredList->setVariantMode($variantMode $variantMode ListingInterface::VARIANT_MODE_HIDE);
  116.             $filteredList->addCondition(new LikeCondition('stores''both'sprintf('%1$s%2$s%1$s'','$this->getContext()->getStore()->getId())), 'stores');
  117.             $filteredList->addCondition(new LikeCondition('parentCategoryIds''both'sprintf(',%s,'$category->getId())), 'parentCategoryIds');
  118.             $orderDirection $category->getFilter()->getOrderDirection();
  119.             $orderKey $category->getFilter()->getOrderKey();
  120.             $sortKey = (empty($orderKey) ? $this->defaultSortName $orderKey) . '_' . (empty($orderDirection) ? $this->defaultSortDirection $orderDirection);
  121.             $sort $this->getParameterFromRequest($request'sort'$sortKey);
  122.             $sortParsed $this->parseSorting($sort);
  123.             $filteredList->setOrderKey($sortParsed['name']);
  124.             $filteredList->setOrder($sortParsed['direction']);
  125.             $currentFilter $this->get(FilterProcessorInterface::class)->processConditions($category->getFilter(), $filteredList$request->query);
  126.             $preparedConditions $this->get(FilterProcessorInterface::class)->prepareConditionsForRendering($category->getFilter(), $filteredList$currentFilter);
  127.             $paginator $this->getPaginator()->paginate(
  128.                 $filteredList,
  129.                 $page,
  130.                 $perPage,
  131.             );
  132.             $viewParameters['list'] = $filteredList;
  133.             $viewParameters['filter'] = $category->getFilter();
  134.             $viewParameters['currentFilter'] = $currentFilter;
  135.             $viewParameters['paginator'] = $paginator;
  136.             $viewParameters['conditions'] = $preparedConditions;
  137.         } else {
  138.             //Classic Listing Mode
  139.             $sort $this->getParameterFromRequest($request'sort'$this->defaultSortName '_' $this->defaultSortDirection);
  140.             $sortParsed $this->parseSorting($sort);
  141.             $categories = [$category];
  142.             if ($displaySubCategories === true) {
  143.                 foreach ($this->getRepository()->findRecursiveChildCategoriesForStore($category$this->getContext()->getStore()) as $subCategory) {
  144.                     $categories[] = $subCategory;
  145.                 }
  146.             }
  147.             $options = [
  148.                 'order_key' => $sortParsed['name'],
  149.                 'order' => $sortParsed['direction'],
  150.                 'categories' => $categories,
  151.                 'store' => $this->getContext()->getStore(),
  152.                 'return_type' => 'list',
  153.             ];
  154.             if ($variantMode !== ListingInterface::VARIANT_MODE_HIDE) {
  155.                 $options['object_types'] = [AbstractObject::OBJECT_TYPE_OBJECTAbstractObject::OBJECT_TYPE_VARIANT];
  156.             }
  157.             $list $this->getProductRepository()->getProductsListing($options);
  158.             $paginator $this->getPaginator()->paginate(
  159.                 $list,
  160.                 $page,
  161.                 $perPage,
  162.             );
  163.             $viewParameters['paginator'] = $paginator;
  164.         }
  165.         $viewParameters['category'] = $category;
  166.         $viewParameters['page'] = $page;
  167.         $viewParameters['perPage'] = $perPage;
  168.         $viewParameters['type'] = $type;
  169.         $viewParameters['perPageAllowed'] = $allowedPerPage;
  170.         $viewParameters['sort'] = $sort;
  171.         $viewParameters['validSortElements'] = $this->validSortProperties;
  172.         foreach ($paginator as $product) {
  173.             $this->get(TrackerInterface::class)->trackProductImpression($product);
  174.         }
  175.         $this->get(SEOPresentationInterface::class)->updateSeoMetadata($category);
  176.         return $this->render($this->templateConfigurator->findTemplate('Category/index.html'), $viewParameters);
  177.     }
  178.     protected function validateCategory(Request $requestCategoryInterface $category): void
  179.     {
  180.         $isFrontendRequestByAdmin false;
  181.         if ($this->get(RequestHelper::class)->isFrontendRequestByAdmin($request)) {
  182.             $isFrontendRequestByAdmin true;
  183.         }
  184.         if ($isFrontendRequestByAdmin === false && !$category->isPublished()) {
  185.             throw new NotFoundHttpException('category not found');
  186.         }
  187.         if (!in_array($this->getContext()->getStore()->getId(), array_values($category->getStores()))) {
  188.             throw new NotFoundHttpException(sprintf(sprintf('store (id %s) not available in category'$this->getContext()->getStore()->getId())));
  189.         }
  190.     }
  191.     protected function parseSorting(string $sortString): array
  192.     {
  193.         $sort = [
  194.             'name' => 'name',
  195.             'direction' => 'asc',
  196.         ];
  197.         $sortString explode('_'$sortString);
  198.         if (count($sortString) < 2) {
  199.             return $sort;
  200.         }
  201.         $name $sortString[0];
  202.         $direction $sortString[1];
  203.         if (in_array($name$this->validSortProperties) && in_array($direction, ['desc''asc'])) {
  204.             return [
  205.                 'name' => $name,
  206.                 'direction' => $direction,
  207.             ];
  208.         }
  209.         return $sort;
  210.     }
  211.     protected function getRepository(): CategoryRepositoryInterface
  212.     {
  213.         return $this->get('coreshop.repository.category');
  214.     }
  215.     protected function getProductRepository(): ProductRepositoryInterface
  216.     {
  217.         return $this->get('coreshop.repository.product');
  218.     }
  219.     protected function getConfigurationService(): ConfigurationServiceInterface
  220.     {
  221.         return $this->get(ConfigurationServiceInterface::class);
  222.     }
  223.     protected function getContext(): ShopperContextInterface
  224.     {
  225.         return $this->get(ShopperContextInterface::class);
  226.     }
  227.     protected function getPaginator(): PaginatorInterface
  228.     {
  229.         return $this->get(PaginatorInterface::class);
  230.     }
  231. }