vendor/ibexa/scheduler/src/lib/Form/Processor/ContentFormProcessor.php line 130

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\Scheduler\Form\Processor;
  8. use DateTime;
  9. use Exception;
  10. use Ibexa\ContentForms\Data\Content\ContentCreateData;
  11. use Ibexa\ContentForms\Data\Content\ContentUpdateData;
  12. use Ibexa\ContentForms\Event\FormActionEvent;
  13. use Ibexa\Contracts\AdminUi\Notification\TranslatableNotificationHandlerInterface;
  14. use Ibexa\Contracts\Core\Repository\ContentService;
  15. use Ibexa\Contracts\Core\Repository\LocationService;
  16. use Ibexa\Contracts\Core\Repository\Values\Content\Content;
  17. use Ibexa\Contracts\Core\Repository\Values\Content\ContentStruct;
  18. use Ibexa\Contracts\Scheduler\Repository\DateBasedPublishServiceInterface;
  19. use Ibexa\Core\Base\Exceptions\InvalidArgumentException;
  20. use Ibexa\Scheduler\Form\ContentEditTypeExtension;
  21. use Ibexa\Scheduler\Form\Event\ContentEditEvents;
  22. use JMS\TranslationBundle\Annotation\Desc;
  23. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  24. use Symfony\Component\HttpFoundation\RedirectResponse;
  25. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  26. /**
  27. * Listens for and processes RepositoryForm events.
  28. */
  29. class ContentFormProcessor implements EventSubscriberInterface
  30. {
  31. /** @var \Ibexa\Contracts\Core\Repository\ContentService */
  32. private $contentService;
  33. /** @var \Ibexa\Contracts\Core\Repository\LocationService */
  34. private $locationService;
  35. /** @var \Symfony\Component\Routing\Generator\UrlGeneratorInterface */
  36. private $urlGenerator;
  37. /** @var \Ibexa\Contracts\AdminUi\Notification\TranslatableNotificationHandlerInterface */
  38. private $notificationHandler;
  39. /** @var \Ibexa\Contracts\Scheduler\Repository\DateBasedPublishServiceInterface */
  40. private $scheduleService;
  41. public function __construct(
  42. ContentService $contentService,
  43. LocationService $locationService,
  44. UrlGeneratorInterface $urlGenerator,
  45. TranslatableNotificationHandlerInterface $notificationHandler,
  46. DateBasedPublishServiceInterface $scheduleService
  47. ) {
  48. $this->contentService = $contentService;
  49. $this->locationService = $locationService;
  50. $this->urlGenerator = $urlGenerator;
  51. $this->notificationHandler = $notificationHandler;
  52. $this->scheduleService = $scheduleService;
  53. }
  54. /**
  55. * {@inheritdoc}
  56. */
  57. public static function getSubscribedEvents(): array
  58. {
  59. return [
  60. ContentEditEvents::CONTENT_SCHEDULE_PUBLISH => ['processSchedulePublish', 10],
  61. ContentEditEvents::CONTENT_DISCARD_SCHEDULE_PUBLISH => ['processDiscardSchedulePublish', 10],
  62. ];
  63. }
  64. public function processDiscardSchedulePublish(FormActionEvent $event): void
  65. {
  66. /** @var \Ibexa\ContentForms\Data\Content\ContentCreateData|\Ibexa\ContentForms\Data\Content\ContentUpdateData $data */
  67. $data = $event->getData();
  68. $form = $event->getForm();
  69. $languageCode = $form->getConfig()->getOption('languageCode');
  70. try {
  71. $contentDraft = $this->saveDraft($data, $languageCode);
  72. $this->scheduleService->unschedulePublish($contentDraft->versionInfo->id);
  73. $locationId = $contentDraft->versionInfo->contentInfo->mainLocationId;
  74. $contentId = $contentDraft->id;
  75. if (empty($locationId)) {
  76. $locations = $this->locationService->loadParentLocationsForDraftContent($contentDraft->versionInfo);
  77. $location = array_shift($locations);
  78. $locationId = $location->id;
  79. $contentId = $location->contentId;
  80. }
  81. $redirectUrl = $this->urlGenerator->generate('ibexa.content.view', [
  82. 'contentId' => $contentId,
  83. 'locationId' => $locationId,
  84. ]);
  85. $this->notificationHandler->success(
  86. /** @Desc("Canceled scheduled publication.") */
  87. 'date_based_publisher.discard.publish_later',
  88. [],
  89. 'ibexa_scheduler'
  90. );
  91. $event->setResponse(new RedirectResponse($redirectUrl));
  92. } catch (Exception $e) {
  93. $this->notificationHandler->error(
  94. /** @Desc("Cannot cancel future publication: %reason%") */
  95. 'date_based_publisher.error.discard.publish_later',
  96. ['%reason%' => $e->getMessage()],
  97. 'ibexa_scheduler'
  98. );
  99. $event->setResponse(
  100. new RedirectResponse(
  101. $this->getContentEditUrl($data, $languageCode)
  102. )
  103. );
  104. }
  105. }
  106. /**
  107. * @param \Ibexa\ContentForms\Event\FormActionEvent $event
  108. *
  109. * @throws \Ibexa\Core\Base\Exceptions\InvalidArgumentException
  110. */
  111. public function processSchedulePublish(FormActionEvent $event): void
  112. {
  113. /** @var \Ibexa\ContentForms\Data\Content\ContentCreateData|\Ibexa\ContentForms\Data\Content\ContentUpdateData $data */
  114. $data = $event->getData();
  115. $form = $event->getForm();
  116. $languageCode = $form->getConfig()->getOption('languageCode');
  117. $scheduleLater = $form->get(ContentEditTypeExtension::EXTENSION_NAME);
  118. try {
  119. $contentDraft = $this->saveDraft($data, $languageCode);
  120. $locationId = $contentDraft->versionInfo->contentInfo->mainLocationId;
  121. $contentId = $contentDraft->id;
  122. $versionId = $contentDraft->versionInfo->id;
  123. if (empty($locationId)) {
  124. $locations = $this->locationService->loadParentLocationsForDraftContent($contentDraft->versionInfo);
  125. $location = array_shift($locations);
  126. $locationId = $location->id;
  127. $contentId = $location->contentId;
  128. }
  129. $redirectUrl = $this->urlGenerator->generate('ibexa.content.view', [
  130. 'contentId' => $contentId,
  131. 'locationId' => $locationId,
  132. ]);
  133. $when = DateTime::createFromFormat('U', $scheduleLater['timestamp']->getData());
  134. if ($this->scheduleService->isScheduledPublish($versionId)) {
  135. $scheduledVersion = $this->scheduleService->getScheduledPublish($versionId);
  136. $this->scheduleService->updateScheduledPublish($scheduledVersion, $when);
  137. } else {
  138. $this->scheduleService->schedulePublish($contentDraft->versionInfo, $when);
  139. }
  140. $this->notificationHandler->success(
  141. /** @Desc("Scheduled content for publication.") */
  142. 'date_based_publisher.success.publish_later',
  143. [],
  144. 'ibexa_scheduler'
  145. );
  146. $event->setResponse(new RedirectResponse($redirectUrl));
  147. } catch (Exception $e) {
  148. $this->notificationHandler->error(
  149. /** @Desc("Cannot schedule content: %reason%") */
  150. 'date_based_publisher.error.publish_later',
  151. ['%reason%' => $e->getMessage()],
  152. 'ibexa_scheduler'
  153. );
  154. $event->setResponse(
  155. new RedirectResponse(
  156. $this->getContentEditUrl($data, $languageCode)
  157. )
  158. );
  159. }
  160. }
  161. /**
  162. * Saves content draft corresponding to $data.
  163. * Depending on the nature of $data (create or update data), the draft will either be created or simply updated.
  164. *
  165. * @param \Ibexa\Contracts\Core\Repository\Values\Content\ContentStruct|\Ibexa\ContentForms\Data\Content\ContentCreateData|\Ibexa\ContentForms\Data\Content\ContentUpdateData $data
  166. * @param string $languageCode
  167. *
  168. * @return \Ibexa\Contracts\Core\Repository\Values\Content\Content
  169. *
  170. * @throws \Ibexa\Contracts\Core\Repository\Exceptions\BadStateException
  171. * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
  172. * @throws \Ibexa\Core\Base\Exceptions\InvalidArgumentException
  173. * @throws \Ibexa\Contracts\Core\Repository\Exceptions\ContentValidationException
  174. * @throws \Ibexa\Contracts\Core\Repository\Exceptions\ContentFieldValidationException
  175. */
  176. private function saveDraft(ContentStruct $data, string $languageCode): Content
  177. {
  178. if (false === ($data instanceof ContentUpdateData) && false === ($data instanceof ContentCreateData)) {
  179. throw new InvalidArgumentException(
  180. '$data',
  181. 'Expected ContentUpdateData or ContentCreateData'
  182. );
  183. }
  184. $mainLanguageCode = $this->resolveMainLanguageCode($data);
  185. foreach ($data->fieldsData as $fieldDefIdentifier => $fieldData) {
  186. if ($mainLanguageCode !== $languageCode && false === $fieldData->fieldDefinition->isTranslatable) {
  187. continue;
  188. }
  189. $data->setField($fieldDefIdentifier, $fieldData->value, $languageCode);
  190. }
  191. if ($data->isNew()) {
  192. $contentDraft = $this->contentService->createContent($data, $data->getLocationStructs());
  193. } else {
  194. $contentDraft = $this->contentService->updateContent($data->contentDraft->getVersionInfo(), $data);
  195. }
  196. return $contentDraft;
  197. }
  198. /**
  199. * @param \Ibexa\Contracts\Core\Repository\Values\Content\ContentStruct|\Ibexa\ContentForms\Data\Content\ContentCreateData|\Ibexa\ContentForms\Data\Content\ContentUpdateData $data
  200. *
  201. * @return string
  202. */
  203. private function resolveMainLanguageCode(ContentStruct $data): string
  204. {
  205. return $data->isNew()
  206. ? $data->mainLanguageCode
  207. : $data->contentDraft->getVersionInfo()->getContentInfo()->mainLanguageCode;
  208. }
  209. /**
  210. * Returns content create or edit URL depending on $data type.
  211. *
  212. * @param \Ibexa\ContentForms\Data\Content\ContentData|\Ibexa\ContentForms\Data\Content\ContentCreateData|\Ibexa\ContentForms\Data\Content\ContentUpdateData $data
  213. * @param string $languageCode
  214. *
  215. * @return string
  216. *
  217. * @throws \Symfony\Component\Routing\Exception\RouteNotFoundException
  218. * @throws \Symfony\Component\Routing\Exception\MissingMandatoryParametersException
  219. * @throws \Symfony\Component\Routing\Exception\InvalidParameterException
  220. */
  221. private function getContentEditUrl($data, string $languageCode): string
  222. {
  223. return $data->isNew()
  224. ? $this->urlGenerator->generate('ibexa.content.create.proxy', [
  225. 'parentLocationId' => $data->getLocationStructs()[0]->parentLocationId,
  226. 'contentTypeIdentifier' => $data->contentType->identifier,
  227. 'languageCode' => $languageCode,
  228. ])
  229. : $this->urlGenerator->generate('ibexa.content.draft.edit', [
  230. 'contentId' => $data->contentDraft->id,
  231. 'versionNo' => $data->contentDraft->getVersionInfo()->versionNo,
  232. 'language' => $languageCode,
  233. ]);
  234. }
  235. }
  236. class_alias(ContentFormProcessor::class, 'EzSystems\DateBasedPublisher\Core\Form\Processor\ContentFormProcessor');