vendor/ibexa/admin-ui/src/lib/Form/Processor/ContentType/ContentTypeFormProcessor.php line 173

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. namespace Ibexa\AdminUi\Form\Processor\ContentType;
  7. use Ibexa\ContentForms\Event\FormActionEvent;
  8. use Ibexa\Contracts\AdminUi\Event\FormEvents;
  9. use Ibexa\Contracts\Core\Repository\ContentTypeService;
  10. use Ibexa\Contracts\Core\Repository\Values\ContentType\ContentTypeDraft;
  11. use Ibexa\Contracts\Core\Repository\Values\ContentType\FieldDefinition;
  12. use Ibexa\Contracts\Core\Repository\Values\ContentType\FieldDefinitionCreateStruct;
  13. use Ibexa\Core\Base\Exceptions\InvalidArgumentException;
  14. use Ibexa\Core\Helper\FieldsGroups\FieldsGroupsList;
  15. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  16. use Symfony\Component\HttpFoundation\RedirectResponse;
  17. use Symfony\Component\Routing\RouterInterface;
  18. class ContentTypeFormProcessor implements EventSubscriberInterface
  19. {
  20. /**
  21. * @var \Ibexa\Contracts\Core\Repository\ContentTypeService
  22. */
  23. private $contentTypeService;
  24. /**
  25. * @var \Symfony\Component\Routing\RouterInterface
  26. */
  27. private $router;
  28. /**
  29. * @var array
  30. */
  31. private $options;
  32. /**
  33. * @var \Ibexa\Core\Helper\FieldsGroups\FieldsGroupsList
  34. */
  35. private $groupsList;
  36. public function __construct(
  37. ContentTypeService $contentTypeService,
  38. RouterInterface $router,
  39. array $options = []
  40. ) {
  41. $this->contentTypeService = $contentTypeService;
  42. $this->router = $router;
  43. $this->setOptions($options);
  44. }
  45. public function setGroupsList(FieldsGroupsList $groupsList)
  46. {
  47. $this->groupsList = $groupsList;
  48. }
  49. public function setOptions(array $options = [])
  50. {
  51. $this->options = $options + ['redirectRouteAfterPublish' => null];
  52. }
  53. public static function getSubscribedEvents()
  54. {
  55. return [
  56. FormEvents::CONTENT_TYPE_UPDATE => 'processDefaultAction',
  57. FormEvents::CONTENT_TYPE_ADD_FIELD_DEFINITION => 'processAddFieldDefinition',
  58. FormEvents::CONTENT_TYPE_REMOVE_FIELD_DEFINITION => 'processRemoveFieldDefinition',
  59. FormEvents::CONTENT_TYPE_PUBLISH => 'processPublishContentType',
  60. FormEvents::CONTENT_TYPE_PUBLISH_AND_EDIT => 'processPublishAndEditContentType',
  61. FormEvents::CONTENT_TYPE_REMOVE_DRAFT => 'processRemoveContentTypeDraft',
  62. ];
  63. }
  64. public function processDefaultAction(FormActionEvent $event)
  65. {
  66. // Don't update anything if we just want to cancel the draft.
  67. if ($event->getClickedButton() === 'removeDraft') {
  68. return;
  69. }
  70. // Always update FieldDefinitions and ContentTypeDraft
  71. /** @var \Ibexa\AdminUi\Form\Data\ContentTypeData $contentTypeData */
  72. $contentTypeData = $event->getData();
  73. $contentTypeDraft = $contentTypeData->contentTypeDraft;
  74. foreach ($contentTypeData->getFlatFieldDefinitionsData() as $fieldDefData) {
  75. $this->contentTypeService->updateFieldDefinition($contentTypeDraft, $fieldDefData->fieldDefinition, $fieldDefData);
  76. }
  77. // Update enabled FieldDefinitions and remove disabled.
  78. foreach ($contentTypeData->getFlatMetaFieldDefinitionsData() as $fieldDefData) {
  79. if ($fieldDefData->enabled) {
  80. $this->contentTypeService->updateFieldDefinition(
  81. $contentTypeDraft,
  82. $fieldDefData->fieldDefinition,
  83. $fieldDefData
  84. );
  85. } else {
  86. $this->contentTypeService->removeFieldDefinition($contentTypeDraft, $fieldDefData->fieldDefinition);
  87. }
  88. }
  89. $contentTypeData->sortFieldDefinitions();
  90. $this->contentTypeService->updateContentTypeDraft($contentTypeDraft, $contentTypeData);
  91. }
  92. public function processAddFieldDefinition(FormActionEvent $event)
  93. {
  94. // Reload the draft, to make sure we include any changes made in the current form submit
  95. $contentTypeDraft = $this->contentTypeService->loadContentTypeDraft($event->getData()->contentTypeDraft->id);
  96. $fieldTypeIdentifier = $event->getForm()->get('fieldTypeSelection')->getData();
  97. $targetLanguageCode = $event->getForm()->getConfig()->getOption('languageCode');
  98. if ($contentTypeDraft->mainLanguageCode !== $targetLanguageCode) {
  99. throw new InvalidArgumentException(
  100. 'languageCode',
  101. 'Field definitions can only be added to the main language translation'
  102. );
  103. }
  104. $maxFieldPos = 0;
  105. foreach ($contentTypeDraft->fieldDefinitions as $existingFieldDef) {
  106. if ($existingFieldDef->position > $maxFieldPos) {
  107. $maxFieldPos = $existingFieldDef->position;
  108. }
  109. }
  110. $fieldDefCreateStruct = new FieldDefinitionCreateStruct([
  111. 'fieldTypeIdentifier' => $fieldTypeIdentifier,
  112. 'identifier' => $this->resolveNewFieldDefinitionIdentifier(
  113. $contentTypeDraft,
  114. $maxFieldPos,
  115. $fieldTypeIdentifier
  116. ),
  117. 'names' => [$event->getOption('languageCode') => 'New FieldDefinition'],
  118. 'position' => $maxFieldPos + 1,
  119. ]);
  120. if (isset($this->groupsList)) {
  121. $fieldDefCreateStruct->fieldGroup = $this->groupsList->getDefaultGroup();
  122. }
  123. $this->contentTypeService->addFieldDefinition($contentTypeDraft, $fieldDefCreateStruct);
  124. }
  125. public function processRemoveFieldDefinition(FormActionEvent $event)
  126. {
  127. /** @var \Ibexa\Contracts\Core\Repository\Values\ContentType\ContentTypeDraft $contentTypeDraft */
  128. $contentTypeDraft = $event->getData()->contentTypeDraft;
  129. // Accessing FieldDefinition user selection through the form and not the data,
  130. // as "selected" is not a property of FieldDefinitionData.
  131. /** @var \Symfony\Component\Form\FormInterface $fieldDefForm */
  132. foreach ($event->getForm()->get('fieldDefinitionsData') as $fieldDefForm) {
  133. if ($fieldDefForm->get('selected')->getData() === true) {
  134. $this->contentTypeService->removeFieldDefinition($contentTypeDraft, $fieldDefForm->getData()->fieldDefinition);
  135. }
  136. }
  137. }
  138. public function processPublishContentType(FormActionEvent $event)
  139. {
  140. $contentTypeDraft = $event->getData()->contentTypeDraft;
  141. $this->contentTypeService->publishContentTypeDraft($contentTypeDraft);
  142. if (isset($this->options['redirectRouteAfterPublish'])) {
  143. $event->setResponse(
  144. new RedirectResponse($this->router->generate($this->options['redirectRouteAfterPublish']))
  145. );
  146. }
  147. }
  148. public function processPublishAndEditContentType(FormActionEvent $event): void
  149. {
  150. $eventData = $event->getData();
  151. /** @var \Ibexa\Contracts\Core\Repository\Values\ContentType\ContentTypeDraft $contentTypeDraft */
  152. $contentTypeDraft = $eventData->contentTypeDraft;
  153. $languageCode = $eventData->languageCode;
  154. $this->contentTypeService->publishContentTypeDraft($contentTypeDraft);
  155. $contentType = $this->contentTypeService->loadContentType($contentTypeDraft->id, [$languageCode]);
  156. $this->contentTypeService->createContentTypeDraft($contentType);
  157. }
  158. public function processRemoveContentTypeDraft(FormActionEvent $event)
  159. {
  160. $contentTypeDraft = $event->getData()->contentTypeDraft;
  161. $this->contentTypeService->deleteContentType($contentTypeDraft);
  162. if (isset($this->options['redirectRouteAfterPublish'])) {
  163. $event->setResponse(
  164. new RedirectResponse($this->router->generate($this->options['redirectRouteAfterPublish']))
  165. );
  166. }
  167. }
  168. /**
  169. * Resolves unique field definition identifier.
  170. *
  171. * @param \Ibexa\Contracts\Core\Repository\Values\ContentType\ContentTypeDraft $contentTypeDraft
  172. * @param int $startIndex
  173. * @param string $fieldTypeIdentifier
  174. *
  175. * @return string
  176. */
  177. private function resolveNewFieldDefinitionIdentifier(
  178. ContentTypeDraft $contentTypeDraft,
  179. int $startIndex,
  180. string $fieldTypeIdentifier
  181. ): string {
  182. $fieldDefinitionIdentifiers = $contentTypeDraft
  183. ->getFieldDefinitions()
  184. ->map(static function (FieldDefinition $fieldDefinition): string {
  185. return $fieldDefinition->identifier;
  186. });
  187. do {
  188. $fieldDefinitionIdentifier = sprintf('new_%s_%d', $fieldTypeIdentifier, ++$startIndex);
  189. } while (in_array($fieldDefinitionIdentifier, $fieldDefinitionIdentifiers, true));
  190. return $fieldDefinitionIdentifier;
  191. }
  192. }
  193. class_alias(ContentTypeFormProcessor::class, 'EzSystems\EzPlatformAdminUi\Form\Processor\ContentType\ContentTypeFormProcessor');