vendor/ibexa/personalization/src/lib/Event/Subscriber/ContentEventSubscriber.php line 172

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\Limitation\Target;
  9. use Ibexa\Contracts\Core\Repository\ContentService as CoreContentService;
  10. use Ibexa\Contracts\Core\Repository\Events\Content\BeforeDeleteContentEvent;
  11. use Ibexa\Contracts\Core\Repository\Events\Content\BeforeDeleteTranslationEvent;
  12. use Ibexa\Contracts\Core\Repository\Events\Content\CopyContentEvent;
  13. use Ibexa\Contracts\Core\Repository\Events\Content\HideContentEvent;
  14. use Ibexa\Contracts\Core\Repository\Events\Content\PublishVersionEvent;
  15. use Ibexa\Contracts\Core\Repository\Events\Content\RevealContentEvent;
  16. use Ibexa\Contracts\Core\Repository\Events\Content\UpdateContentMetadataEvent;
  17. use Ibexa\Contracts\Core\Repository\LocationService;
  18. use Ibexa\Contracts\Core\Repository\PermissionResolver;
  19. use Ibexa\Contracts\Core\Repository\Repository;
  20. use Ibexa\Contracts\Core\Repository\SearchService;
  21. use Ibexa\Contracts\Core\Repository\Values\Content\ContentInfo;
  22. use Ibexa\Core\Base\Exceptions\UnauthorizedException;
  23. use Ibexa\Core\Query\QueryFactoryInterface;
  24. use Ibexa\Personalization\Config\ItemType\IncludedItemTypeResolverInterface;
  25. use Ibexa\Personalization\Event\PersonalizationEvent;
  26. use Ibexa\Personalization\Service\Content\ContentServiceInterface;
  27. use Ibexa\Personalization\Service\Setting\SettingServiceInterface;
  28. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  29. final class ContentEventSubscriber extends AbstractRepositoryEventSubscriber implements EventSubscriberInterface
  30. {
  31. private PermissionResolver $permissionResolver;
  32. private SettingServiceInterface $settingService;
  33. public function __construct(
  34. CoreContentService $coreContentService,
  35. ContentServiceInterface $contentService,
  36. IncludedItemTypeResolverInterface $includedItemTypeResolver,
  37. LocationService $locationService,
  38. Repository $repository,
  39. PermissionResolver $permissionResolver,
  40. SettingServiceInterface $settingService,
  41. QueryFactoryInterface $queryFactory,
  42. SearchService $searchService
  43. ) {
  44. parent::__construct(
  45. $coreContentService,
  46. $contentService,
  47. $includedItemTypeResolver,
  48. $locationService,
  49. $repository,
  50. $queryFactory,
  51. $searchService
  52. );
  53. $this->permissionResolver = $permissionResolver;
  54. $this->settingService = $settingService;
  55. }
  56. public static function getSubscribedEvents(): array
  57. {
  58. return [
  59. BeforeDeleteContentEvent::class => ['onBeforeDeleteContent', PersonalizationEvent::DEFAULT_PRIORITY],
  60. BeforeDeleteTranslationEvent::class => ['onBeforeDeleteTranslation', PersonalizationEvent::DEFAULT_PRIORITY],
  61. HideContentEvent::class => ['onHideContent', PersonalizationEvent::DEFAULT_PRIORITY],
  62. RevealContentEvent::class => ['onRevealContent', PersonalizationEvent::DEFAULT_PRIORITY],
  63. UpdateContentMetadataEvent::class => ['onUpdateContentMetadata', PersonalizationEvent::DEFAULT_PRIORITY],
  64. CopyContentEvent::class => ['onCopyContent', PersonalizationEvent::DEFAULT_PRIORITY],
  65. PublishVersionEvent::class => ['onPublishVersion', PersonalizationEvent::DEFAULT_PRIORITY],
  66. ];
  67. }
  68. /**
  69. * @throws \Ibexa\Contracts\Core\Repository\Exceptions\BadStateException
  70. * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException
  71. * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
  72. * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
  73. */
  74. public function onBeforeDeleteContent(BeforeDeleteContentEvent $event): void
  75. {
  76. if (!$this->settingService->isInstallationKeyFound()) {
  77. return;
  78. }
  79. $contentInfo = $event->getContentInfo();
  80. if (!$this->canDelete($contentInfo)) {
  81. throw new UnauthorizedException('content', 'remove', ['contentId' => $contentInfo->getId()]);
  82. }
  83. $this->deleteContentWithChildrenFromAllLocations($contentInfo);
  84. $relations = $this->getContentRelations($contentInfo);
  85. if (empty($relations)) {
  86. return;
  87. }
  88. $this->contentService->updateContentItems($relations);
  89. }
  90. /**
  91. * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
  92. * @throws \Ibexa\Contracts\Core\Repository\Exceptions\BadStateException
  93. * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException
  94. * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
  95. */
  96. public function onBeforeDeleteTranslation(BeforeDeleteTranslationEvent $event): void
  97. {
  98. if (!$this->settingService->isInstallationKeyFound()) {
  99. return;
  100. }
  101. $contentInfo = $event->getContentInfo();
  102. $languageCodes = [$event->getLanguageCode()];
  103. if (!$this->canDelete($contentInfo, $languageCodes)) {
  104. throw new UnauthorizedException('content', 'remove', ['contentId' => $contentInfo->getId()]);
  105. }
  106. $content = $this->coreContentService->loadContentByContentInfo($event->getContentInfo());
  107. if (!$this->includedItemTypeResolver->isContentIncluded($content)) {
  108. return;
  109. }
  110. $this->contentService->deleteContent($content, $languageCodes);
  111. }
  112. public function onHideContent(HideContentEvent $event): void
  113. {
  114. if (!$this->settingService->isInstallationKeyFound()) {
  115. return;
  116. }
  117. $this->deleteContentWithChildrenFromAllLocations($event->getContentInfo());
  118. $relations = $this->getContentRelations($event->getContentInfo());
  119. if (empty($relations)) {
  120. return;
  121. }
  122. $this->contentService->updateContentItems($relations);
  123. }
  124. public function onRevealContent(RevealContentEvent $event): void
  125. {
  126. if (!$this->settingService->isInstallationKeyFound()) {
  127. return;
  128. }
  129. $this->updateContentWithChildrenFromAllLocationsAndRelations(
  130. $event->getContentInfo()
  131. );
  132. }
  133. public function onUpdateContentMetadata(UpdateContentMetadataEvent $event): void
  134. {
  135. if (!$this->settingService->isInstallationKeyFound()) {
  136. return;
  137. }
  138. $content = $event->getContent();
  139. if (!$this->includedItemTypeResolver->isContentIncluded($content)) {
  140. return;
  141. }
  142. $this->contentService->updateContent($event->getContent());
  143. }
  144. public function onCopyContent(CopyContentEvent $event): void
  145. {
  146. if (!$this->settingService->isInstallationKeyFound()) {
  147. return;
  148. }
  149. $content = $event->getContent();
  150. if (!$this->includedItemTypeResolver->isContentIncluded($content)) {
  151. return;
  152. }
  153. $this->contentService->updateContent($content);
  154. }
  155. public function onPublishVersion(PublishVersionEvent $event): void
  156. {
  157. if (!$this->settingService->isInstallationKeyFound()) {
  158. return;
  159. }
  160. $content = $event->getContent();
  161. if (!$this->includedItemTypeResolver->isContentIncluded($content)) {
  162. return;
  163. }
  164. $this->contentService->updateContent($content, $event->getTranslations());
  165. }
  166. /**
  167. * @param array<string>|null $languageCodes
  168. *
  169. * @throws \Ibexa\Contracts\Core\Repository\Exceptions\BadStateException
  170. * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException
  171. * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
  172. * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
  173. */
  174. private function canDelete(
  175. ContentInfo $contentInfo,
  176. ?array $languageCodes = null
  177. ): bool {
  178. if (empty($languageCodes)) {
  179. $versionInfo = $this->coreContentService->loadVersionInfo($contentInfo);
  180. $languageCodes = $this->getTranslationsToDelete($versionInfo->getLanguages());
  181. }
  182. $target = (new Target\Version())->deleteTranslations($languageCodes);
  183. return $this->permissionResolver->canUser('content', 'remove', $contentInfo, [$target]);
  184. }
  185. /**
  186. * @param iterable<\Ibexa\Contracts\Core\Repository\Values\Content\Language> $languages
  187. *
  188. * @return array<string>
  189. */
  190. private function getTranslationsToDelete(iterable $languages): array
  191. {
  192. $translations = [];
  193. foreach ($languages as $language) {
  194. $translations[] = $language->getLanguageCode();
  195. }
  196. return $translations;
  197. }
  198. }
  199. class_alias(ContentEventSubscriber::class, 'EzSystems\EzRecommendationClient\Event\Subscriber\ContentEventSubscriber');