vendor/ibexa/product-catalog/src/bundle/EventSubscriber/PageBuilder/CatalogBlockSubscriber.php line 69

Open in your IDE?
  1. <?php
  2. /**
  3. * @copyright Copyright (C) Ibexa AS. All rights reserved.
  4. * @license For full copyright and license information view LICENSE file distributed with this source code.
  5. */
  6. declare(strict_types=1);
  7. namespace Ibexa\Bundle\ProductCatalog\EventSubscriber\PageBuilder;
  8. use Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException;
  9. use Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException;
  10. use Ibexa\Contracts\FieldTypePage\FieldType\LandingPage\Model\BlockValue;
  11. use Ibexa\Contracts\ProductCatalog\CatalogServiceInterface;
  12. use Ibexa\Contracts\ProductCatalog\CustomerGroupResolverInterface;
  13. use Ibexa\Contracts\ProductCatalog\ProductServiceInterface;
  14. use Ibexa\Contracts\ProductCatalog\Values\CatalogInterface;
  15. use Ibexa\Contracts\ProductCatalog\Values\CustomerGroupInterface;
  16. use Ibexa\Contracts\ProductCatalog\Values\Product\ProductQuery;
  17. use Ibexa\Contracts\ProductCatalog\Values\Product\Query\CriterionInterface;
  18. use Ibexa\FieldTypePage\FieldType\Page\Block\Renderer\BlockRenderEvents;
  19. use Ibexa\FieldTypePage\FieldType\Page\Block\Renderer\Event\PreRenderEvent;
  20. use Ibexa\ProductCatalog\Pagerfanta\Adapter\ProductListAdapter;
  21. use Pagerfanta\Pagerfanta;
  22. use Psr\Log\LoggerAwareInterface;
  23. use Psr\Log\LoggerAwareTrait;
  24. use Psr\Log\LoggerInterface;
  25. use Psr\Log\NullLogger;
  26. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  27. use Symfony\Component\HttpFoundation\RequestStack;
  28. final class CatalogBlockSubscriber implements EventSubscriberInterface, LoggerAwareInterface
  29. {
  30. private const BLOCK_IDENTIFIER = 'catalog';
  31. private const PAGE_PARAM = 'page_';
  32. private const DEFAULT_CURRENT_PAGE = 1;
  33. use LoggerAwareTrait;
  34. private CatalogServiceInterface $catalogService;
  35. private CustomerGroupResolverInterface $customerGroupResolver;
  36. private ProductServiceInterface $productService;
  37. private RequestStack $requestStack;
  38. public function __construct(
  39. CatalogServiceInterface $catalogService,
  40. CustomerGroupResolverInterface $customerGroupResolver,
  41. ProductServiceInterface $productService,
  42. RequestStack $requestStack,
  43. ?LoggerInterface $logger = null
  44. ) {
  45. $this->catalogService = $catalogService;
  46. $this->customerGroupResolver = $customerGroupResolver;
  47. $this->productService = $productService;
  48. $this->requestStack = $requestStack;
  49. $this->logger = $logger ?? new NullLogger();
  50. }
  51. public static function getSubscribedEvents(): array
  52. {
  53. return [
  54. BlockRenderEvents::getBlockPreRenderEventName(self::BLOCK_IDENTIFIER) => 'onBlockPreRender',
  55. ];
  56. }
  57. public function onBlockPreRender(PreRenderEvent $event): void
  58. {
  59. /** @var \Ibexa\FieldTypePage\FieldType\Page\Block\Renderer\Twig\TwigRenderRequest $renderRequest */
  60. $renderRequest = $event->getRenderRequest();
  61. $parameters = $renderRequest->getParameters();
  62. $blockValue = $event->getBlockValue();
  63. $catalog = $this->getMappedCatalog($blockValue) ?? $this->getDefaultCatalog($blockValue);
  64. $products = [];
  65. if (null !== $catalog) {
  66. $products = $this->getProductList(
  67. $catalog->getQuery(),
  68. (int) $parameters['limit'],
  69. $this->getCurrentPage(self::PAGE_PARAM . $blockValue->getId())
  70. );
  71. }
  72. $parameters['products'] = $products;
  73. unset($parameters['default_catalog'], $parameters['catalog_map']);
  74. $renderRequest->setParameters($parameters);
  75. }
  76. private function getMappedCatalog(BlockValue $blockValue): ?CatalogInterface
  77. {
  78. $catalogMap = $this->getCatalogMap($blockValue);
  79. $customerGroup = $this->resolveCustomerGroup();
  80. if (
  81. !empty($catalogMap)
  82. && null !== $customerGroup
  83. ) {
  84. foreach ($catalogMap as $data) {
  85. if ($customerGroup->getId() === $data['customer_group']) {
  86. return $this->getCatalog((int) $data['catalog']);
  87. }
  88. }
  89. }
  90. return null;
  91. }
  92. /**
  93. * @return \Pagerfanta\Pagerfanta<\Ibexa\Contracts\ProductCatalog\Values\ProductInterface>
  94. */
  95. private function getProductList(
  96. CriterionInterface $criterion,
  97. int $limit,
  98. int $currentPage
  99. ): Pagerfanta {
  100. $products = new Pagerfanta(
  101. new ProductListAdapter(
  102. $this->productService,
  103. new ProductQuery($criterion)
  104. )
  105. );
  106. $products->setMaxPerPage($limit);
  107. $products->setCurrentPage($currentPage);
  108. return $products;
  109. }
  110. private function resolveCustomerGroup(): ?CustomerGroupInterface
  111. {
  112. try {
  113. return $this->customerGroupResolver->resolveCustomerGroup();
  114. } catch (NotFoundException | UnauthorizedException $exception) {
  115. $this->logger->warning($exception->getMessage());
  116. return null;
  117. }
  118. }
  119. private function getCatalog(int $id): ?CatalogInterface
  120. {
  121. try {
  122. return $this->catalogService->getCatalog($id);
  123. } catch (NotFoundException | UnauthorizedException $exception) {
  124. $this->logger->warning($exception->getMessage());
  125. return null;
  126. }
  127. }
  128. private function getDefaultCatalog(BlockValue $blockValue): ?CatalogInterface
  129. {
  130. $catalog = $blockValue->getAttribute('default_catalog');
  131. if (null === $catalog) {
  132. return null;
  133. }
  134. return $this->getCatalog((int) $catalog->getValue());
  135. }
  136. /**
  137. * @return array<array{
  138. * 'customer_group': int,
  139. * 'catalog': int,
  140. * }>
  141. *
  142. * @throws \JsonException
  143. */
  144. private function getCatalogMap(BlockValue $blockValue): array
  145. {
  146. $catalogMapAttribute = $blockValue->getAttribute('catalog_map');
  147. if (null === $catalogMapAttribute) {
  148. return [];
  149. }
  150. return json_decode(
  151. $catalogMapAttribute->getValue(),
  152. true,
  153. 512,
  154. JSON_THROW_ON_ERROR
  155. );
  156. }
  157. private function getCurrentPage(string $pageParam): int
  158. {
  159. $request = $this->requestStack->getMainRequest();
  160. if (null === $request) {
  161. return self::DEFAULT_CURRENT_PAGE;
  162. }
  163. return $request->query->getInt($pageParam, self::DEFAULT_CURRENT_PAGE);
  164. }
  165. }