vendor/ibexa/admin-ui/src/lib/Form/Processor/PreviewFormProcessor.php line 76

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\AdminUi\Form\Processor;
  8. use Exception;
  9. use Ibexa\AdminUi\Form\Event\ContentEditEvents;
  10. use Ibexa\ContentForms\Data\NewnessCheckable;
  11. use Ibexa\ContentForms\Event\FormActionEvent;
  12. use Ibexa\Contracts\AdminUi\Notification\TranslatableNotificationHandlerInterface;
  13. use Ibexa\Contracts\Core\Repository\ContentService;
  14. use Ibexa\Contracts\Core\Repository\LocationService;
  15. use Ibexa\Contracts\Core\Repository\Values\Content\Content;
  16. use Ibexa\Contracts\Core\Repository\Values\Content\ContentStruct;
  17. use Ibexa\Contracts\Core\Repository\Values\Content\Location;
  18. use JMS\TranslationBundle\Annotation\Desc;
  19. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  20. use Symfony\Component\HttpFoundation\RedirectResponse;
  21. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  22. /**
  23. * Listens for and processes RepositoryForm events.
  24. */
  25. class PreviewFormProcessor implements EventSubscriberInterface
  26. {
  27. /** @var \Ibexa\Contracts\Core\Repository\ContentService */
  28. private $contentService;
  29. /** @var \Symfony\Component\Routing\Generator\UrlGeneratorInterface */
  30. private $urlGenerator;
  31. /** @var \Ibexa\Contracts\AdminUi\Notification\TranslatableNotificationHandlerInterface */
  32. private $notificationHandler;
  33. /** @var \Ibexa\Contracts\Core\Repository\LocationService */
  34. private $locationService;
  35. /**
  36. * @param \Ibexa\Contracts\Core\Repository\ContentService $contentService
  37. * @param \Symfony\Component\Routing\Generator\UrlGeneratorInterface $urlGenerator
  38. * @param \Ibexa\Contracts\AdminUi\Notification\TranslatableNotificationHandlerInterface $notificationHandler
  39. * @param \Ibexa\Contracts\Core\Repository\LocationService $locationService
  40. */
  41. public function __construct(
  42. ContentService $contentService,
  43. UrlGeneratorInterface $urlGenerator,
  44. TranslatableNotificationHandlerInterface $notificationHandler,
  45. LocationService $locationService
  46. ) {
  47. $this->contentService = $contentService;
  48. $this->urlGenerator = $urlGenerator;
  49. $this->notificationHandler = $notificationHandler;
  50. $this->locationService = $locationService;
  51. }
  52. /**
  53. * {@inheritdoc}
  54. */
  55. public static function getSubscribedEvents(): array
  56. {
  57. return [
  58. ContentEditEvents::CONTENT_PREVIEW => ['processPreview', 10],
  59. ];
  60. }
  61. /**
  62. * @param \Ibexa\ContentForms\Event\FormActionEvent $event
  63. *
  64. * @throws \InvalidArgumentException
  65. */
  66. public function processPreview(FormActionEvent $event): void
  67. {
  68. /** @var \Ibexa\ContentForms\Data\Content\ContentCreateData|\Ibexa\ContentForms\Data\Content\ContentUpdateData $data */
  69. $data = $event->getData();
  70. $form = $event->getForm();
  71. $languageCode = $form->getConfig()->getOption('languageCode');
  72. $referrerLocation = $event->getOption('referrerLocation');
  73. try {
  74. $contentDraft = $this->saveDraft($data, $languageCode, []);
  75. $contentLocation = $this->resolveLocation($contentDraft, $referrerLocation, $data);
  76. $url = $this->urlGenerator->generate('ibexa.content.preview', [
  77. 'locationId' => null !== $contentLocation ? $contentLocation->id : null,
  78. 'contentId' => $contentDraft->id,
  79. 'versionNo' => $contentDraft->getVersionInfo()->versionNo,
  80. 'languageCode' => $languageCode,
  81. ]);
  82. } catch (Exception $e) {
  83. $this->notificationHandler->error(
  84. /** @Desc("Cannot save content draft.") */
  85. 'error.preview',
  86. [],
  87. 'ibexa_content_preview'
  88. );
  89. $url = $this->getContentEditUrl($data, $languageCode);
  90. }
  91. $event->setResponse(
  92. new RedirectResponse($url)
  93. );
  94. }
  95. /**
  96. * Saves content draft corresponding to $data.
  97. * Depending on the nature of $data (create or update data), the draft will either be created or simply updated.
  98. *
  99. * @param \Ibexa\ContentForms\Data\Content\ContentCreateData|\Ibexa\Contracts\Core\Repository\Values\Content\ContentStruct|\Ibexa\ContentForms\Data\Content\ContentUpdateData $data
  100. * @param string $languageCode
  101. *
  102. * @return \Ibexa\Contracts\Core\Repository\Values\Content\Content
  103. *
  104. * @throws \Ibexa\Contracts\Core\Repository\Exceptions\BadStateException
  105. * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
  106. * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException
  107. * @throws \Ibexa\Contracts\Core\Repository\Exceptions\ContentValidationException
  108. * @throws \Ibexa\Contracts\Core\Repository\Exceptions\ContentFieldValidationException
  109. */
  110. private function saveDraft(ContentStruct $data, string $languageCode, ?array $fieldIdentifiersToValidate): Content
  111. {
  112. $mainLanguageCode = $this->resolveMainLanguageCode($data);
  113. foreach ($data->fieldsData as $fieldDefIdentifier => $fieldData) {
  114. if ($mainLanguageCode != $languageCode && !$fieldData->fieldDefinition->isTranslatable) {
  115. continue;
  116. }
  117. $data->setField($fieldDefIdentifier, $fieldData->value, $languageCode);
  118. }
  119. if ($data->isNew()) {
  120. $contentDraft = $this->contentService->createContent($data, $data->getLocationStructs(), $fieldIdentifiersToValidate);
  121. } else {
  122. $contentDraft = $this->contentService->updateContent($data->contentDraft->getVersionInfo(), $data, $fieldIdentifiersToValidate);
  123. }
  124. return $contentDraft;
  125. }
  126. /**
  127. * Returns content create or edit URL depending on $data type.
  128. *
  129. * @param \Ibexa\ContentForms\Data\Content\ContentCreateData|\Ibexa\ContentForms\Data\Content\ContentUpdateData $data
  130. * @param string $languageCode
  131. *
  132. * @return string
  133. *
  134. * @throws \Symfony\Component\Routing\Exception\RouteNotFoundException
  135. * @throws \Symfony\Component\Routing\Exception\MissingMandatoryParametersException
  136. * @throws \Symfony\Component\Routing\Exception\InvalidParameterException
  137. */
  138. private function getContentEditUrl($data, string $languageCode): string
  139. {
  140. return $data->isNew()
  141. ? $this->urlGenerator->generate('ibexa.content.create.proxy', [
  142. 'parentLocationId' => $data->getLocationStructs()[0]->parentLocationId,
  143. 'contentTypeIdentifier' => $data->contentType->identifier,
  144. 'languageCode' => $languageCode,
  145. ])
  146. : $this->urlGenerator->generate('ibexa.content.draft.edit', [
  147. 'contentId' => $data->contentDraft->id,
  148. 'versionNo' => $data->contentDraft->getVersionInfo()->versionNo,
  149. 'language' => $languageCode,
  150. ]);
  151. }
  152. /**
  153. * @param \Ibexa\ContentForms\Data\Content\ContentCreateData|\Ibexa\ContentForms\Data\Content\ContentUpdateData|\Ibexa\AdminUi\Form\Data\NewnessChecker $data
  154. *
  155. * @return string
  156. */
  157. private function resolveMainLanguageCode($data): string
  158. {
  159. return $data->isNew()
  160. ? $data->mainLanguageCode
  161. : $data->contentDraft->getVersionInfo()->getContentInfo()->mainLanguageCode;
  162. }
  163. /**
  164. * @param \Ibexa\Contracts\Core\Repository\Values\Content\Content $content
  165. * @param \Ibexa\Contracts\Core\Repository\Values\Content\Location|null $referrerLocation
  166. * @param \Ibexa\ContentForms\Data\NewnessCheckable $data
  167. *
  168. * @return \Ibexa\Contracts\Core\Repository\Values\Content\Location|null
  169. */
  170. private function resolveLocation(Content $content, ?Location $referrerLocation, NewnessCheckable $data): ?Location
  171. {
  172. if ($data->isNew() || (!$content->contentInfo->published && null === $content->contentInfo->mainLocationId)) {
  173. return null; // no location exists until new content is published
  174. }
  175. return $referrerLocation ?? $this->locationService->loadLocation($content->contentInfo->mainLocationId);
  176. }
  177. }
  178. class_alias(PreviewFormProcessor::class, 'EzSystems\EzPlatformAdminUi\Form\Processor\PreviewFormProcessor');