vendor/ibexa/site-factory/src/lib/Event/Subscriber/UpdateRolesSubscriber.php line 87

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\SiteFactory\Event\Subscriber;
  8. use Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException;
  9. use Ibexa\Contracts\Core\Repository\Exceptions\LimitationValidationException;
  10. use Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException;
  11. use Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException;
  12. use Ibexa\Contracts\Core\Repository\RoleService;
  13. use Ibexa\Contracts\Core\Repository\Values\User\Limitation\SiteAccessLimitation;
  14. use Ibexa\Contracts\Core\Repository\Values\User\PolicyDraft;
  15. use Ibexa\Contracts\Core\Repository\Values\User\RoleDraft;
  16. use Ibexa\Contracts\SiteFactory\Events\CreateSiteEvent;
  17. use Ibexa\Contracts\SiteFactory\Events\DeleteSiteEvent;
  18. use Ibexa\Contracts\SiteFactory\Events\UpdateSiteEvent;
  19. use Psr\Log\LoggerAwareTrait;
  20. use Psr\Log\NullLogger;
  21. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  22. final class UpdateRolesSubscriber implements EventSubscriberInterface
  23. {
  24.     use LoggerAwareTrait;
  25.     /** @var \Ibexa\Contracts\Core\Repository\RoleService */
  26.     private $roleService;
  27.     /** @var string[] */
  28.     private $updateRoles;
  29.     public function __construct(
  30.         RoleService $roleService,
  31.         array $updateRoles
  32.     ) {
  33.         $this->roleService $roleService;
  34.         $this->updateRoles $updateRoles;
  35.         $this->logger = new NullLogger();
  36.     }
  37.     public static function getSubscribedEvents(): array
  38.     {
  39.         return [
  40.             CreateSiteEvent::class => ['onSiteCreate'0],
  41.             DeleteSiteEvent::class => ['onSiteDelete'0],
  42.             UpdateSiteEvent::class => ['onSiteUpdate'0],
  43.         ];
  44.     }
  45.     public function onSiteCreate(CreateSiteEvent $event): void
  46.     {
  47.         $publicAccessIdentifiers $this->getSiteAccessIdentifiers($event);
  48.         foreach ($this->updateRoles as $roleIdentifier) {
  49.             try {
  50.                 $roleDraft $this->getRoleDraft($roleIdentifier);
  51.                 foreach ($this->getLoginPolicies($roleDraft) as $loginPolicy) {
  52.                     foreach ($loginPolicy->getLimitations() as $limitation) {
  53.                         if ($limitation instanceof SiteAccessLimitation) {
  54.                             $updatedLimitationValues array_merge($limitation->limitationValues$publicAccessIdentifiers);
  55.                             $this->updateSiteAccessLimitation($roleDraft$loginPolicy$updatedLimitationValues);
  56.                         }
  57.                     }
  58.                 }
  59.                 $this->roleService->publishRoleDraft($roleDraft);
  60.             } catch (UnauthorizedException LimitationValidationException InvalidArgumentException NotFoundException $e) {
  61.                 if (isset($roleDraft)) {
  62.                     $this->roleService->deleteRoleDraft($roleDraft);
  63.                 }
  64.                 $this->logger->warning(sprintf(
  65.                     'Can not update Role with identifier %s after creation of the Site with ID %d: %s',
  66.                     $roleIdentifier,
  67.                     $event->getSite()->id,
  68.                     $e->getMessage()
  69.                 ));
  70.             }
  71.         }
  72.     }
  73.     public function onSiteDelete(DeleteSiteEvent $event): void
  74.     {
  75.         $publicAccessIdentifiers = [];
  76.         foreach ($event->getSite()->publicAccesses as $publicAccess) {
  77.             $publicAccessIdentifiers[] = $this->generateSiteAccessValue($publicAccess->identifier);
  78.         }
  79.         foreach ($this->updateRoles as $roleIdentifier) {
  80.             try {
  81.                 $roleDraft $this->getRoleDraft($roleIdentifier);
  82.                 foreach ($this->getLoginPolicies($roleDraft) as $loginPolicy) {
  83.                     foreach ($loginPolicy->getLimitations() as $limitation) {
  84.                         if ($limitation instanceof SiteAccessLimitation) {
  85.                             $updatedLimitationValues array_diff($limitation->limitationValues$publicAccessIdentifiers);
  86.                             $this->updateSiteAccessLimitation($roleDraft$loginPolicy$updatedLimitationValues);
  87.                         }
  88.                     }
  89.                 }
  90.                 $this->roleService->publishRoleDraft($roleDraft);
  91.             } catch (UnauthorizedException LimitationValidationException InvalidArgumentException NotFoundException $e) {
  92.                 if (isset($roleDraft)) {
  93.                     $this->roleService->deleteRoleDraft($roleDraft);
  94.                 }
  95.                 $this->logger->warning(sprintf(
  96.                     'Can not update Role with identifier %s after deletion of the Site with ID %d: %s',
  97.                     $roleIdentifier,
  98.                     $event->getSite()->id,
  99.                     $e->getMessage()
  100.                 ));
  101.             }
  102.         }
  103.     }
  104.     public function onSiteUpdate(UpdateSiteEvent $event): void
  105.     {
  106.         $publicAccessIdentifiersBefore = [];
  107.         $publicAccessIdentifiersAfter = [];
  108.         foreach ($event->getSite()->publicAccesses as $publicAccess) {
  109.             $publicAccessIdentifiersBefore[] = $this->generateSiteAccessValue($publicAccess->identifier);
  110.         }
  111.         foreach ($event->getUpdatedSite()->publicAccesses as $publicAccess) {
  112.             $publicAccessIdentifiersAfter[] = $this->generateSiteAccessValue($publicAccess->identifier);
  113.         }
  114.         $addedPublicAccessIdentifiers array_diff($publicAccessIdentifiersAfter$publicAccessIdentifiersBefore);
  115.         $deletedPublicAccessIdentifiers array_diff($publicAccessIdentifiersBefore$publicAccessIdentifiersAfter);
  116.         foreach ($this->updateRoles as $roleIdentifier) {
  117.             try {
  118.                 $roleDraft $this->getRoleDraft($roleIdentifier);
  119.                 foreach ($this->getLoginPolicies($roleDraft) as $loginPolicy) {
  120.                     foreach ($loginPolicy->getLimitations() as $limitation) {
  121.                         if ($limitation instanceof SiteAccessLimitation) {
  122.                             $updatedLimitationValues array_merge($limitation->limitationValues$addedPublicAccessIdentifiers);
  123.                             $updatedLimitationValues array_diff($updatedLimitationValues$deletedPublicAccessIdentifiers);
  124.                             $this->updateSiteAccessLimitation($roleDraft$loginPolicy$updatedLimitationValues);
  125.                         }
  126.                     }
  127.                 }
  128.                 $this->roleService->publishRoleDraft($roleDraft);
  129.             } catch (UnauthorizedException LimitationValidationException InvalidArgumentException NotFoundException $e) {
  130.                 if (isset($roleDraft)) {
  131.                     $this->roleService->deleteRoleDraft($roleDraft);
  132.                 }
  133.                 $this->logger->warning(sprintf(
  134.                     'Can not update Role with identifier %s after edition of the Site with ID %d: %s',
  135.                     $roleIdentifier,
  136.                     $event->getSite()->id,
  137.                     $e->getMessage()
  138.                 ));
  139.             }
  140.         }
  141.     }
  142.     /**
  143.      * Generates the SiteAccess value as CRC32.
  144.      */
  145.     private function generateSiteAccessValue(string $sa): string
  146.     {
  147.         return sprintf('%u'crc32($sa));
  148.     }
  149.     /**
  150.      * @return string[]
  151.      */
  152.     private function getSiteAccessIdentifiers(CreateSiteEvent $event): array
  153.     {
  154.         $publicAccessIdentifiers = [];
  155.         foreach ($event->getSiteCreateStruct()->publicAccesses as $publicAccess) {
  156.             $publicAccessIdentifiers[] = $this->generateSiteAccessValue($publicAccess->identifier);
  157.         }
  158.         return $publicAccessIdentifiers;
  159.     }
  160.     /**
  161.      * Get `user/login` Policies from the Role. They are fetched to perform an update on SiteAccess limitation values.
  162.      * If a Role has no `user/login` Policy then information to logs is written.
  163.      *
  164.      * @return \Ibexa\Contracts\Core\Repository\Values\User\PolicyDraft[]
  165.      */
  166.     private function getLoginPolicies(RoleDraft $roleDraft): array
  167.     {
  168.         /** @var \Ibexa\Contracts\Core\Repository\Values\User\PolicyDraft $policy */
  169.         $loginPolicies = [];
  170.         foreach ($roleDraft->getPolicies() as $policy) {
  171.             if ('user' !== $policy->module || 'login' !== $policy->function) {
  172.                 continue;
  173.             }
  174.             $loginPolicies[] = $policy;
  175.         }
  176.         if (empty($loginPolicies)) {
  177.             $this->logger->warning(
  178.                 sprintf(
  179.                     'Role with ID: %d which is configured to update when new site is created has no user/login policy.
  180.                     Please check your configuration.',
  181.                     $roleDraft->id
  182.                 )
  183.             );
  184.         }
  185.         return $loginPolicies;
  186.     }
  187.     /**
  188.      * @param string[] $limitationValues
  189.      *
  190.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException
  191.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\LimitationValidationException
  192.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
  193.      */
  194.     private function updateSiteAccessLimitation(
  195.         RoleDraft $roleDraft,
  196.         PolicyDraft $policyDraft,
  197.         array $limitationValues
  198.     ): PolicyDraft {
  199.         $policyUpdate $this->roleService->newPolicyUpdateStruct();
  200.         $policyUpdate->addLimitation(
  201.             new SiteAccessLimitation(
  202.                 [
  203.                     'limitationValues' => $limitationValues,
  204.                 ]
  205.             )
  206.         );
  207.         return $this->roleService->updatePolicyByRoleDraft(
  208.             $roleDraft,
  209.             $policyDraft,
  210.             $policyUpdate
  211.         );
  212.     }
  213.     /**
  214.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException
  215.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\LimitationValidationException
  216.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
  217.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
  218.      */
  219.     private function getRoleDraft(string $roleIdentifier): RoleDraft
  220.     {
  221.         $role $this->roleService->loadRoleByIdentifier($roleIdentifier);
  222.         return $this->roleService->createRoleDraft($role);
  223.     }
  224. }
  225. class_alias(UpdateRolesSubscriber::class, 'EzSystems\EzPlatformSiteFactory\Event\Subscriber\UpdateRolesSubscriber');