vendor/ibexa/workflow/src/lib/Event/Subscriber/VersionLockSubscriber.php line 108

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\Workflow\Event\Subscriber;
  8. use Ibexa\AdminUi\Event\CancelEditVersionDraftEvent;
  9. use Ibexa\ContentForms\Content\View\ContentEditView;
  10. use Ibexa\Contracts\Core\Event\View\PostBuildViewEvent;
  11. use Ibexa\Contracts\Core\Repository\Events\Content\BeforePublishVersionEvent;
  12. use Ibexa\Contracts\Core\Repository\Events\Content\DeleteContentEvent;
  13. use Ibexa\Contracts\Core\Repository\Events\Content\DeleteVersionEvent;
  14. use Ibexa\Contracts\Core\Repository\Events\User\DeleteUserEvent;
  15. use Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException as APINotFoundException;
  16. use Ibexa\Contracts\Core\Repository\PermissionResolver;
  17. use Ibexa\Contracts\Core\Repository\UserService;
  18. use Ibexa\Contracts\Core\Repository\Values\Content\Content;
  19. use Ibexa\Contracts\Core\Repository\Values\Content\VersionInfo;
  20. use Ibexa\Contracts\Workflow\Service\WorkflowServiceInterface;
  21. use Ibexa\Core\Base\Exceptions\NotFoundException;
  22. use Ibexa\Scheduler\Event\ScheduledPublish;
  23. use Ibexa\Workflow\Exception\VersionLockedException;
  24. use Ibexa\Workflow\Registry\WorkflowRegistry;
  25. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  26. use Symfony\Component\Workflow\Event\EnteredEvent;
  27. final class VersionLockSubscriber implements EventSubscriberInterface
  28. {
  29.     /** @var \Ibexa\Contracts\Core\Repository\UserService */
  30.     private $userService;
  31.     /** @var \Ibexa\Contracts\Workflow\Service\WorkflowServiceInterface */
  32.     private $workflowService;
  33.     /** @var \Ibexa\Workflow\Registry\WorkflowRegistry */
  34.     private $workflowRegistry;
  35.     /** @var \Ibexa\Contracts\Core\Repository\PermissionResolver */
  36.     private $permissionResolver;
  37.     public function __construct(
  38.         UserService $userService,
  39.         WorkflowServiceInterface $workflowService,
  40.         WorkflowRegistry $workflowRegistry,
  41.         PermissionResolver $permissionResolver
  42.     ) {
  43.         $this->userService $userService;
  44.         $this->workflowService $workflowService;
  45.         $this->permissionResolver $permissionResolver;
  46.         $this->workflowRegistry $workflowRegistry;
  47.     }
  48.     public static function getSubscribedEvents(): array
  49.     {
  50.         return [
  51.             PostBuildViewEvent::class => 'onBuildContentEditView',
  52.             BeforePublishVersionEvent::class => 'onBeforePublishVersion',
  53.             ScheduledPublish::class => 'onScheduledPublish',
  54.             CancelEditVersionDraftEvent::class => 'onCancelEditVersionDraft',
  55.             'workflow.entered' => 'onWorkflowEntered',
  56.             DeleteUserEvent::class => 'onDeleteUser',
  57.             DeleteContentEvent::class => 'onDeleteContent',
  58.             DeleteVersionEvent::class => 'onDeleteVersion',
  59.         ];
  60.     }
  61.     /**
  62.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
  63.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\BadStateException
  64.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException
  65.      * @throws \Ibexa\Workflow\Exception\VersionLockedException
  66.      */
  67.     public function onBuildContentEditView(PostBuildViewEvent $event): void
  68.     {
  69.         $view $event->getView();
  70.         if (!$view instanceof ContentEditView) {
  71.             return;
  72.         }
  73.         $content $view->getContent();
  74.         $location $view->getLocation();
  75.         $workflows $this->workflowRegistry->getSupportedWorkflows($content);
  76.         if (!$this->hasNonInitialWorkflowPlace($workflows$content)) {
  77.             return;
  78.         }
  79.         if (!$this->permissionResolver->canUser('content''edit'$content, [$location])) {
  80.             try {
  81.                 $versionLock $this->workflowService->getVersionLock($content->versionInfo);
  82.                 $user $this->userService->loadUser($versionLock->userId);
  83.                 throw new VersionLockedException($versionLock$user);
  84.             } catch (NotFoundException $exception) {
  85.                 // pass
  86.             }
  87.         } else {
  88.             $this->workflowService->lockVersion($content->versionInfo);
  89.         }
  90.     }
  91.     public function onCancelEditVersionDraft(CancelEditVersionDraftEvent $event): void
  92.     {
  93.         $this->unlockVersion($event->getContent()->versionInfo);
  94.     }
  95.     public function onDeleteContent(DeleteContentEvent $event)
  96.     {
  97.         $this->workflowService->deleteContentLocks($event->getContentInfo()->id);
  98.     }
  99.     public function onDeleteUser(DeleteUserEvent $event)
  100.     {
  101.         $this->workflowService->deleteUserLocks($event->getUser()->id);
  102.     }
  103.     public function onDeleteVersion(DeleteVersionEvent $event)
  104.     {
  105.         try {
  106.             $this->workflowService->deleteLock(
  107.                 $this->workflowService->getVersionLock($event->getVersionInfo())
  108.             );
  109.         } catch (APINotFoundException $exception) {
  110.             // pass
  111.         }
  112.     }
  113.     public function onBeforePublishVersion(BeforePublishVersionEvent $event): void
  114.     {
  115.         $this->unlockVersion($event->getVersionInfo());
  116.     }
  117.     public function onScheduledPublish(ScheduledPublish $event)
  118.     {
  119.         $scheduledEntry $event->getScheduledEntry();
  120.         if (null !== $scheduledEntry->versionInfo) {
  121.             $this->unlockVersion($scheduledEntry->versionInfo);
  122.         }
  123.     }
  124.     public function onWorkflowEntered(EnteredEvent $event): void
  125.     {
  126.         $workflowName $event->getWorkflowName();
  127.         $subject $event->getSubject();
  128.         // guard is not needed for workflows not based on our content model
  129.         if (!$subject instanceof Content || !$this->workflowRegistry->hasWorkflow($workflowName)) {
  130.             return;
  131.         }
  132.         $this->unlockVersion($subject->versionInfo);
  133.     }
  134.     private function unlockVersion(VersionInfo $versionInfo): void
  135.     {
  136.         $isDraft $versionInfo->isDraft();
  137.         $canUnlock $this->permissionResolver->canUser('content''unlock'$versionInfo);
  138.         $isLocked $this->workflowService->isVersionLocked($versionInfo);
  139.         if ($isDraft && $isLocked && $canUnlock) {
  140.             $this->workflowService->unlockVersion($versionInfo);
  141.         }
  142.     }
  143.     private function hasNonInitialWorkflowPlace(array $workflowsContent $content): bool
  144.     {
  145.         foreach ($workflows as $workflow) {
  146.             $marking $workflow->getMarking($content);
  147.             $places array_keys($marking->getPlaces());
  148.             $initialPlaces $workflow->getDefinition()->getInitialPlaces();
  149.             if (count(array_diff($places$initialPlaces)) > 0) {
  150.                 return true;
  151.             }
  152.         }
  153.         return false;
  154.     }
  155. }