vendor/ibexa/workflow/src/lib/Event/Subscriber/AbstractMenuSubscriber.php line 147

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\Menu\ContentCreateRightSidebarBuilder;
  9. use Ibexa\AdminUi\Menu\ContentEditRightSidebarBuilder;
  10. use Ibexa\AdminUi\Menu\Event\ConfigureMenuEvent;
  11. use Ibexa\Contracts\Core\Repository\PermissionResolver;
  12. use Ibexa\Contracts\Core\Repository\Values\ValueObject;
  13. use Ibexa\Contracts\Workflow\Registry\WorkflowDefinitionMetadataRegistryInterface;
  14. use Ibexa\Contracts\Workflow\Registry\WorkflowRegistryInterface;
  15. use Knp\Menu\FactoryInterface;
  16. use Knp\Menu\ItemInterface;
  17. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  18. use Symfony\Component\Workflow\Exception\LogicException;
  19. use Symfony\Component\Workflow\Workflow;
  20. abstract class AbstractMenuSubscriber implements EventSubscriberInterface
  21. {
  22. protected const PUBLISH_MENU_ITEMS = [
  23. ContentCreateRightSidebarBuilder::ITEM__PUBLISH,
  24. ContentEditRightSidebarBuilder::ITEM__PUBLISH,
  25. ];
  26. /** @var \Knp\Menu\FactoryInterface */
  27. private $menuFactory;
  28. /** @var \Ibexa\Contracts\Workflow\Registry\WorkflowRegistryInterface */
  29. private $workflowRegistry;
  30. /** @var \Ibexa\Workflow\Factory\Registry\WorkflowDefinitionMetadataRegistryFactory */
  31. private $workflowDefinitionMetadataRegistry;
  32. /** @var \Ibexa\Contracts\Core\Repository\PermissionResolver */
  33. private $permissionResolver;
  34. public function __construct(
  35. FactoryInterface $menuFactory,
  36. WorkflowRegistryInterface $workflowRegistry,
  37. WorkflowDefinitionMetadataRegistryInterface $workflowDefinitionMetadataRegistry,
  38. PermissionResolver $permissionResolver
  39. ) {
  40. $this->menuFactory = $menuFactory;
  41. $this->workflowRegistry = $workflowRegistry;
  42. $this->workflowDefinitionMetadataRegistry = $workflowDefinitionMetadataRegistry;
  43. $this->permissionResolver = $permissionResolver;
  44. }
  45. private function getWorkflows(ValueObject $subject): array
  46. {
  47. $workflows = $this->workflowRegistry->getSupportedWorkflows($subject);
  48. return $this->filterWorkflows($workflows, $subject);
  49. }
  50. public function addTransitionButtonsToContentEdit(ConfigureMenuEvent $event): void
  51. {
  52. $root = $event->getMenu();
  53. $options = $event->getOptions();
  54. /** @var \Ibexa\Contracts\Core\Repository\Values\Content\Content $content */
  55. $content = $options['content'];
  56. $workflows = $this->getWorkflows($content);
  57. $workflowMenuItems = [];
  58. foreach ($workflows as $workflow) {
  59. $workflowMenuItems = array_replace(
  60. $workflowMenuItems,
  61. $this->createWorkflowMenuItems($workflow, $workflow->getEnabledTransitions($content), $options)
  62. );
  63. }
  64. $root->setChildren(array_replace($workflowMenuItems, $root->getChildren()));
  65. }
  66. public function addTransitionButtonsToContentCreate(ConfigureMenuEvent $event): void
  67. {
  68. $root = $event->getMenu();
  69. $options = $event->getOptions();
  70. /** @var \Ibexa\Contracts\Core\Repository\Values\Content\ContentCreateStruct $contentCreateStruct */
  71. $contentCreateStruct = $options['content_create_struct'];
  72. $workflows = $this->getWorkflows($contentCreateStruct);
  73. $workflowMenuItems = [];
  74. foreach ($workflows as $workflow) {
  75. $workflowMenuItems = array_replace(
  76. $workflowMenuItems,
  77. $this->createWorkflowMenuItems($workflow, $workflow->getEnabledTransitions($contentCreateStruct), $options)
  78. );
  79. }
  80. $root->setChildren(array_replace($workflowMenuItems, $root->getChildren()));
  81. }
  82. private function filterWorkflows($workflows, ValueObject $subject): array
  83. {
  84. $workflows = array_filter($workflows, static function (Workflow $workflow) use ($subject) {
  85. try {
  86. $workflow->getMarking($subject);
  87. return true;
  88. } catch (LogicException $e) {
  89. return false;
  90. }
  91. });
  92. // quick_review works as fallback so we remove it when there are other workflows
  93. if (count($workflows) > 1) {
  94. unset($workflows['quick_review']);
  95. }
  96. return $workflows;
  97. }
  98. public function removePublishButtonsOnContentEdit(ConfigureMenuEvent $event): void
  99. {
  100. $root = $event->getMenu();
  101. $options = $event->getOptions();
  102. /** @var \Ibexa\Contracts\Core\Repository\Values\Content\Content $content */
  103. $content = $options['content'];
  104. $canPublish = $this->permissionResolver->canUser('content', 'publish', $content);
  105. if ($canPublish) {
  106. return;
  107. }
  108. $workflows = $this->workflowRegistry->getSupportedWorkflows($content);
  109. if (!$this->hasEnabledTransitions($workflows, $content)) {
  110. return;
  111. }
  112. $this->removePublishMenuItems($root);
  113. }
  114. public function removePublishButtonsOnContentCreate(ConfigureMenuEvent $event): void
  115. {
  116. $root = $event->getMenu();
  117. $options = $event->getOptions();
  118. /** @var \Ibexa\Contracts\Core\Repository\Values\Content\ContentCreateStruct $contentCreateStruct */
  119. $contentCreateStruct = $options['content_create_struct'];
  120. $canPublish = $this->permissionResolver->canUser('content', 'publish', $contentCreateStruct);
  121. if ($canPublish) {
  122. return;
  123. }
  124. $workflows = $this->workflowRegistry->getSupportedWorkflows($contentCreateStruct);
  125. if (!$this->hasEnabledTransitions($workflows, $contentCreateStruct)) {
  126. return;
  127. }
  128. $this->removePublishMenuItems($root);
  129. }
  130. private function createWorkflowMenuItems(Workflow $workflow, array $transitions, array $options): array
  131. {
  132. $workflowMetadataRegistry = $this->workflowDefinitionMetadataRegistry->getWorkflowMetadata($workflow->getName());
  133. $workflowTransitionsMetadata = $workflowMetadataRegistry->getTransitionsMetadata();
  134. $menuItems = [];
  135. $orderNumber = 1;
  136. foreach ($transitions as $transition) {
  137. $transitionMetadata = $workflowTransitionsMetadata[$transition->getName()];
  138. $transitionLabel = $transitionMetadata->getLabel();
  139. $transitionValidate = $transitionMetadata->getValidate();
  140. $menuItemKey = sprintf('workflow__apply__%s__%s', $workflow->getName(), $transition->getName());
  141. $menuItemParameters = [
  142. 'label' => $transitionLabel,
  143. 'attributes' => [
  144. 'class' => 'ibexa-btn--extra-actions',
  145. 'data-actions' => $menuItemKey,
  146. 'data-validate' => $transitionValidate,
  147. 'data-focus-element' => '.ibexa-workflow-apply-transition__user-input',
  148. ],
  149. 'extras' => [
  150. 'translation_domain' => 'ibexa_workflow',
  151. 'template' => '@ibexadesign/ibexa_workflow/apply_transition_widget.html.twig',
  152. 'template_parameters' => [
  153. 'action' => $menuItemKey,
  154. 'workflow' => $workflow->getName(),
  155. 'transition' => $transition->getName(),
  156. 'reviewer' => [
  157. 'required' => $transitionMetadata->getReviewersMetadata()->isRequired(),
  158. ],
  159. 'context' => [
  160. 'action' => isset($options['content']) ? 'edit' : 'create',
  161. 'options' => $options,
  162. ],
  163. ],
  164. 'orderNumber' => $orderNumber++,
  165. ],
  166. ];
  167. if ($transitionMetadata->getIcon()) {
  168. $menuItemParameters['extras']['icon_path'] = $transitionMetadata->getIcon();
  169. } else {
  170. $menuItemParameters['extras']['icon'] = 'review';
  171. }
  172. $menuItems[$menuItemKey] = $this->menuFactory->createItem(
  173. $menuItemKey,
  174. $menuItemParameters
  175. );
  176. }
  177. return $menuItems;
  178. }
  179. private function hasEnabledTransitions(array $workflows, $subject): bool
  180. {
  181. $enabledTransitions = [];
  182. foreach ($workflows as $workflow) {
  183. $enabledTransitions = array_merge($enabledTransitions, $workflow->getEnabledTransitions($subject));
  184. }
  185. return !empty($enabledTransitions);
  186. }
  187. private function removePublishMenuItems(ItemInterface $root): void
  188. {
  189. foreach (self::PUBLISH_MENU_ITEMS as $name) {
  190. $root->removeChild($name);
  191. }
  192. }
  193. }
  194. class_alias(AbstractMenuSubscriber::class, 'EzSystems\EzPlatformWorkflow\Event\Subscriber\AbstractMenuSubscriber');