vendor/ibexa/personalization/src/lib/Event/Subscriber/RecommendationEventSubscriber.php line 72

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;
  8. use Ibexa\Contracts\Core\Repository\Values\Content\Content;
  9. use Ibexa\Core\MVC\Symfony\Locale\LocaleConverterInterface;
  10. use Ibexa\Personalization\Config\Repository\RepositoryConfigResolverInterface;
  11. use Ibexa\Personalization\Event\PersonalizationEvent;
  12. use Ibexa\Personalization\Event\RecommendationResponseEvent;
  13. use Ibexa\Personalization\OutputType\OutputTypeResolverInterface;
  14. use Ibexa\Personalization\Request\BasicRecommendationRequest as Request;
  15. use Ibexa\Personalization\Service\RecommendationServiceInterface;
  16. use Ibexa\Personalization\SPI\RecommendationRequest;
  17. use Psr\Http\Message\ResponseInterface;
  18. use Psr\Log\LoggerAwareInterface;
  19. use Psr\Log\LoggerAwareTrait;
  20. use Psr\Log\LoggerInterface;
  21. use Psr\Log\NullLogger;
  22. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  23. use Symfony\Component\HttpFoundation\ParameterBag;
  24. use Symfony\Component\HttpFoundation\Response;
  25. final class RecommendationEventSubscriber implements EventSubscriberInterface, LoggerAwareInterface
  26. {
  27. use LoggerAwareTrait;
  28. private const DEFAULT_LOCALE = 'eng-GB';
  29. private const LOCALE_REQUEST_KEY = '_locale';
  30. private LocaleConverterInterface $localeConverter;
  31. private OutputTypeResolverInterface $outputTypeResolver;
  32. private RecommendationServiceInterface $recommendationService;
  33. private RepositoryConfigResolverInterface $repositoryConfigResolver;
  34. public function __construct(
  35. LocaleConverterInterface $localeConverter,
  36. OutputTypeResolverInterface $outputTypeResolver,
  37. RecommendationServiceInterface $recommendationService,
  38. RepositoryConfigResolverInterface $repositoryConfigResolver,
  39. ?LoggerInterface $logger = null
  40. ) {
  41. $this->localeConverter = $localeConverter;
  42. $this->outputTypeResolver = $outputTypeResolver;
  43. $this->recommendationService = $recommendationService;
  44. $this->repositoryConfigResolver = $repositoryConfigResolver;
  45. $this->logger = $logger ?? new NullLogger();
  46. }
  47. /**
  48. * {@inheritdoc}
  49. */
  50. public static function getSubscribedEvents(): array
  51. {
  52. return [
  53. RecommendationResponseEvent::class => ['onRecommendationResponse', PersonalizationEvent::DEFAULT_PRIORITY],
  54. ];
  55. }
  56. /**
  57. * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
  58. * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
  59. */
  60. public function onRecommendationResponse(RecommendationResponseEvent $event): void
  61. {
  62. $recommendationRequest = $this->getRecommendationRequest($event->getParameterBag());
  63. $response = $this->recommendationService->getRecommendations($recommendationRequest);
  64. if (!$response) {
  65. return;
  66. }
  67. $event->setRecommendationItems($this->extractRecommendationItems($response));
  68. }
  69. /**
  70. * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
  71. * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
  72. */
  73. private function getRecommendationRequest(ParameterBag $parameterBag): Request
  74. {
  75. $parameters = [
  76. RecommendationRequest::SCENARIO => $parameterBag->get(RecommendationRequest::SCENARIO, ''),
  77. Request::LIMIT_KEY => (int) $parameterBag->get(Request::LIMIT_KEY, 3),
  78. Request::OUTPUT_TYPE_KEY => $this->outputTypeResolver->resolveFromParameterBag($parameterBag),
  79. Request::LANGUAGE_KEY => $this->getRequestLanguage($parameterBag->get(self::LOCALE_REQUEST_KEY)),
  80. Request::ATTRIBUTES_KEY => $parameterBag->get(Request::ATTRIBUTES_KEY, []),
  81. Request::FILTERS_KEY => $parameterBag->get(Request::FILTERS_KEY, []),
  82. ];
  83. $content = $parameterBag->get(Request::CONTEXT_ITEMS_KEY);
  84. if ($content instanceof Content) {
  85. $parameters[Request::CONTEXT_ITEMS_KEY] = $this->repositoryConfigResolver->useRemoteId()
  86. ? $content->contentInfo->remoteId
  87. : (string) $content->id;
  88. $parameters[Request::CONTENT_TYPE_KEY] = $content->getContentType()->id;
  89. $parameters[Request::CATEGORY_PATH_KEY] = $this->getCategoryPath($content);
  90. }
  91. return new Request($parameters);
  92. }
  93. private function getRequestLanguage(?string $locale): string
  94. {
  95. return $this->localeConverter->convertToEz($locale) ?? self::DEFAULT_LOCALE;
  96. }
  97. private function extractRecommendationItems(ResponseInterface $response): array
  98. {
  99. if ($response->getStatusCode() !== Response::HTTP_OK) {
  100. $this->logger->warning('RecommendationApi: StatusCode: ' . $response->getStatusCode() . ' Message: ' . $response->getReasonPhrase());
  101. }
  102. $recommendations = $response->getBody()->getContents();
  103. $recommendationItems = json_decode($recommendations, true, 512, JSON_THROW_ON_ERROR);
  104. return $this->recommendationService->getRecommendationItems($recommendationItems['recommendationItems']);
  105. }
  106. private function getCategoryPath(Content $content): ?string
  107. {
  108. $mainLocation = $content->contentInfo->getMainLocation();
  109. if (null === $mainLocation) {
  110. return null;
  111. }
  112. $parentLocation = $mainLocation->getParentLocation();
  113. return null !== $parentLocation ? $parentLocation->pathString : null;
  114. }
  115. }
  116. class_alias(RecommendationEventSubscriber::class, 'EzSystems\EzRecommendationClient\Event\Subscriber\RecommendationEventSubscriber');