vendor/ibexa/personalization/src/lib/Event/Subscriber/CustomizableDashboard/TopClickedItemsBlockSubscriber.php line 66

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\Personalization\Event\Subscriber\CustomizableDashboard;
  8. use Ibexa\Contracts\Core\Exception\InvalidArgumentException;
  9. use Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException;
  10. use Ibexa\Contracts\FieldTypePage\FieldType\LandingPage\Model\BlockValue;
  11. use Ibexa\FieldTypePage\FieldType\Page\Block\Renderer\BlockRenderEvents;
  12. use Ibexa\FieldTypePage\FieldType\Page\Block\Renderer\Event\PreRenderEvent;
  13. use Ibexa\Personalization\Client\Consumer\Performance\PopularityDataFetcher;
  14. use Ibexa\Personalization\Form\Data\DashboardData;
  15. use Ibexa\Personalization\Form\Data\PopularityDurationChoiceData;
  16. use Ibexa\Personalization\Form\Type\Block\TopClickedItemsType;
  17. use Ibexa\Personalization\Security\Service\SecurityServiceInterface;
  18. use Ibexa\Personalization\Service\Performance\RecommendationPerformanceServiceInterface;
  19. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  20. use Symfony\Component\Form\FormFactoryInterface;
  21. use Symfony\Component\Form\FormInterface;
  22. use Symfony\Component\HttpFoundation\Request;
  23. use Symfony\Component\HttpFoundation\RequestStack;
  24. /**
  25.  * @internal
  26.  */
  27. final class TopClickedItemsBlockSubscriber implements EventSubscriberInterface
  28. {
  29.     private const BLOCK_IDENTIFIER 'top_clicked_items';
  30.     private RecommendationPerformanceServiceInterface $recommendationPerformanceService;
  31.     private FormFactoryInterface $formFactory;
  32.     private RequestStack $requestStack;
  33.     private SecurityServiceInterface $securityService;
  34.     public function __construct(
  35.         RecommendationPerformanceServiceInterface $recommendationPerformanceService,
  36.         FormFactoryInterface $formFactory,
  37.         RequestStack $requestStack,
  38.         SecurityServiceInterface $securityService
  39.     ) {
  40.         $this->formFactory $formFactory;
  41.         $this->recommendationPerformanceService $recommendationPerformanceService;
  42.         $this->requestStack $requestStack;
  43.         $this->securityService $securityService;
  44.     }
  45.     public static function getSubscribedEvents(): array
  46.     {
  47.         return [
  48.             BlockRenderEvents::getBlockPreRenderEventName(self::BLOCK_IDENTIFIER) => ['onBlockPreRender', -100],
  49.         ];
  50.     }
  51.     /**
  52.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException
  53.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
  54.      */
  55.     public function onBlockPreRender(PreRenderEvent $event): void
  56.     {
  57.         $blockValue $event->getBlockValue();
  58.         $customerId $this->getCustomerId($blockValue);
  59.         try {
  60.             $this->securityService->checkAcceptanceStatus();
  61.         } catch (UnauthorizedException $exception) {
  62.             $this->handleNoPermissionException($event);
  63.             return;
  64.         }
  65.         $form $this->buildDurationSelectorForm($blockValue->getId());
  66.         // current request is a block-rendering sub-request - we expect form submission data on the main request
  67.         $form->handleRequest($this->requestStack->getMainRequest());
  68.         $dashboardFormData $form->getData();
  69.         $popularityDuration $dashboardFormData->getPopularity()->getDuration();
  70.         /** @var \Ibexa\FieldTypePage\FieldType\Page\Block\Renderer\Twig\TwigRenderRequest $twigRenderRequest */
  71.         $twigRenderRequest $event->getRenderRequest();
  72.         $twigRenderRequest->addParameter('form'$form->createView());
  73.         $twigRenderRequest->addParameter(
  74.             'popularity_list',
  75.             $this->recommendationPerformanceService->getPopularityList(
  76.                 $customerId,
  77.                 $popularityDuration
  78.             ),
  79.         );
  80.     }
  81.     private function buildDurationSelectorForm(string $blockId): FormInterface
  82.     {
  83.         $dashboardTimePeriodData = new DashboardData();
  84.         $dashboardTimePeriodData->setPopularity(
  85.             (new PopularityDurationChoiceData())->setDuration(PopularityDataFetcher::DURATION_24H)
  86.         );
  87.         return $this->formFactory->createNamed(
  88.             "top-clicked-items-$blockId",
  89.             TopClickedItemsType::class,
  90.             $dashboardTimePeriodData,
  91.             [
  92.                 'method' => Request::METHOD_GET,
  93.             ]
  94.         );
  95.     }
  96.     /**
  97.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException
  98.      */
  99.     private function getCustomerId(BlockValue $blockValue): int
  100.     {
  101.         $attribute $blockValue->getAttribute('customer_id');
  102.         if (null === $attribute || $attribute->getValue() === null) {
  103.             throw new InvalidArgumentException('$blockValue''Personalization Customer ID has not been configured');
  104.         }
  105.         return (int)$attribute->getValue();
  106.     }
  107.     private function handleNoPermissionException(PreRenderEvent $event): void
  108.     {
  109.         /** @var \Ibexa\FieldTypePage\FieldType\Page\Block\Renderer\Twig\TwigRenderRequest $twigRenderRequest */
  110.         $twigRenderRequest $event->getRenderRequest();
  111.         $twigRenderRequest->addParameter('block_name'$event->getBlockValue()->getName());
  112.         $twigRenderRequest->setTemplate(
  113.             '@ibexadesign/personalization/dashboard/blocks/errors/no_permission.html.twig'
  114.         );
  115.     }
  116. }