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. $loginPolicies = [];
  169. /** @var \Ibexa\Contracts\Core\Repository\Values\User\PolicyDraft $policy */
  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');