vendor/ibexa/personalization/src/lib/Event/Subscriber/TrashEventSubscriber.php line 78

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\Trash\BeforeTrashEvent;
  11. use Ibexa\Contracts\Core\Repository\Events\Trash\RecoverEvent;
  12. use Ibexa\Contracts\Core\Repository\LocationService;
  13. use Ibexa\Contracts\Core\Repository\PermissionCriterionResolver;
  14. use Ibexa\Contracts\Core\Repository\PermissionResolver;
  15. use Ibexa\Contracts\Core\Repository\Repository;
  16. use Ibexa\Contracts\Core\Repository\SearchService;
  17. use Ibexa\Contracts\Core\Repository\Values\Content\ContentInfo;
  18. use Ibexa\Contracts\Core\Repository\Values\Content\Location;
  19. use Ibexa\Contracts\Core\Repository\Values\Content\Query;
  20. use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion;
  21. use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion\LogicalAnd as CriterionLogicalAnd;
  22. use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion\LogicalNot as CriterionLogicalNot;
  23. use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion\Subtree as CriterionSubtree;
  24. use Ibexa\Core\Base\Exceptions\UnauthorizedException;
  25. use Ibexa\Core\Query\QueryFactoryInterface;
  26. use Ibexa\Personalization\Config\ItemType\IncludedItemTypeResolverInterface;
  27. use Ibexa\Personalization\Event\PersonalizationEvent;
  28. use Ibexa\Personalization\Service\Content\ContentServiceInterface;
  29. use Ibexa\Personalization\Service\Setting\SettingServiceInterface;
  30. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  31. final class TrashEventSubscriber extends AbstractRepositoryEventSubscriber implements EventSubscriberInterface
  32. {
  33.     private PermissionResolver $permissionResolver;
  34.     private PermissionCriterionResolver $permissionCriterionResolver;
  35.     private SettingServiceInterface $settingService;
  36.     public function __construct(
  37.         CoreContentService $coreContentService,
  38.         ContentServiceInterface $contentService,
  39.         IncludedItemTypeResolverInterface $includedItemTypeResolver,
  40.         LocationService $locationService,
  41.         Repository $repository,
  42.         PermissionResolver $permissionResolver,
  43.         PermissionCriterionResolver $permissionCriterionResolver,
  44.         SearchService $searchService,
  45.         SettingServiceInterface $settingService,
  46.         QueryFactoryInterface $queryFactory
  47.     ) {
  48.         parent::__construct(
  49.             $coreContentService,
  50.             $contentService,
  51.             $includedItemTypeResolver,
  52.             $locationService,
  53.             $repository,
  54.             $queryFactory,
  55.             $searchService
  56.         );
  57.         $this->permissionResolver $permissionResolver;
  58.         $this->permissionCriterionResolver $permissionCriterionResolver;
  59.         $this->settingService $settingService;
  60.     }
  61.     public static function getSubscribedEvents(): array
  62.     {
  63.         return [
  64.             RecoverEvent::class => ['onRecover'PersonalizationEvent::DEFAULT_PRIORITY],
  65.             BeforeTrashEvent::class => ['onBeforeTrash'PersonalizationEvent::DEFAULT_PRIORITY],
  66.         ];
  67.     }
  68.     public function onRecover(RecoverEvent $event): void
  69.     {
  70.         if (!$this->settingService->isInstallationKeyFound()) {
  71.             return;
  72.         }
  73.         $location $event->getLocation();
  74.         $content $location->getContent();
  75.         if (!$this->includedItemTypeResolver->isContentIncluded($content)) {
  76.             return;
  77.         }
  78.         $contentItems array_merge(
  79.             [$content],
  80.             $this->getContentRelations($location->getContentInfo()),
  81.         );
  82.         $this->contentService->updateContentItems($contentItems);
  83.     }
  84.     /**
  85.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException
  86.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidCriterionArgumentException
  87.      * @throws \Ibexa\Core\Base\Exceptions\UnauthorizedException
  88.      */
  89.     public function onBeforeTrash(BeforeTrashEvent $event): void
  90.     {
  91.         if (!$this->settingService->isInstallationKeyFound()) {
  92.             return;
  93.         }
  94.         $location $event->getLocation();
  95.         $contentInfo $location->getContentInfo();
  96.         if (!$this->canDelete($contentInfo$location)) {
  97.             throw new UnauthorizedException('content''remove');
  98.         }
  99.         $this->deleteLocationWithChildren($location);
  100.         $relations $this->getContentRelations($location->getContentInfo());
  101.         if (empty($relations)) {
  102.             return;
  103.         }
  104.         $this->contentService->updateContentItems($relations);
  105.     }
  106.     /**
  107.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidCriterionArgumentException
  108.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException
  109.      */
  110.     private function canDelete(ContentInfo $contentInfoLocation $location): bool
  111.     {
  112.         if (!$this->hasContentRemovePermission($contentInfo$location)) {
  113.             return false;
  114.         }
  115.         return $this->hasSubtreeRemovePermission($location);
  116.     }
  117.     private function hasContentRemovePermission(ContentInfo $contentInfoLocation $location): bool
  118.     {
  119.         $target = (new Target\Version())->deleteTranslations($location->getContent()->getVersionInfo()->languageCodes);
  120.         return $this->permissionResolver->canUser('content''remove'$contentInfo, [$location$target]);
  121.     }
  122.     /**
  123.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException
  124.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidCriterionArgumentException
  125.      */
  126.     private function hasSubtreeRemovePermission(Location $location): bool
  127.     {
  128.         $contentRemoveCriterion $this->permissionCriterionResolver->getPermissionsCriterion('content''remove');
  129.         if (is_bool($contentRemoveCriterion)) {
  130.             return $contentRemoveCriterion;
  131.         }
  132.         $result $this->searchService->findContent(
  133.             $this->getQuery($location$contentRemoveCriterion),
  134.             [],
  135.             false
  136.         );
  137.         return $result->totalCount === 0;
  138.     }
  139.     /**
  140.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidCriterionArgumentException
  141.      */
  142.     private function getQuery(Location $locationCriterion $criterion): Query
  143.     {
  144.         return new Query(
  145.             [
  146.                 'limit' => 0,
  147.                 'filter' => new CriterionLogicalAnd(
  148.                     [
  149.                         new CriterionSubtree($location->getPathString()),
  150.                         new CriterionLogicalNot($criterion),
  151.                     ]
  152.                 ),
  153.             ]
  154.         );
  155.     }
  156. }
  157. class_alias(TrashEventSubscriber::class, 'EzSystems\EzRecommendationClient\Event\Subscriber\TrashEventSubscriber');