vendor/ibexa/content-forms/src/lib/Form/Processor/ContentFormProcessor.php line 115

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\ContentForms\Form\Processor;
  8. use Ibexa\ContentForms\Data\Content\ContentCreateData;
  9. use Ibexa\ContentForms\Data\Content\ContentUpdateData;
  10. use Ibexa\ContentForms\Data\NewnessCheckable;
  11. use Ibexa\ContentForms\Event\ContentFormEvents;
  12. use Ibexa\ContentForms\Event\FormActionEvent;
  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 Ibexa\Core\Base\Exceptions\InvalidArgumentException;
  19. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  20. use Symfony\Component\HttpFoundation\RedirectResponse;
  21. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  22. use Symfony\Component\Routing\RouterInterface;
  23. /**
  24.  * Listens for and processes RepositoryForm events: publish, remove draft, save draft...
  25.  */
  26. class ContentFormProcessor implements EventSubscriberInterface
  27. {
  28.     /** @var \Ibexa\Contracts\Core\Repository\ContentService */
  29.     private $contentService;
  30.     /** @var \Ibexa\Contracts\Core\Repository\LocationService */
  31.     private $locationService;
  32.     /** @var \Symfony\Component\Routing\RouterInterface */
  33.     private $router;
  34.     /**
  35.      * @param \Ibexa\Contracts\Core\Repository\ContentService $contentService
  36.      * @param \Ibexa\Contracts\Core\Repository\LocationService $locationService
  37.      * @param \Symfony\Component\Routing\RouterInterface $router
  38.      * @param \Ibexa\Contracts\Core\Repository\URLAliasService $urlAliasService
  39.      */
  40.     public function __construct(
  41.         ContentService $contentService,
  42.         LocationService $locationService,
  43.         RouterInterface $router
  44.     ) {
  45.         $this->contentService $contentService;
  46.         $this->locationService $locationService;
  47.         $this->router $router;
  48.     }
  49.     /**
  50.      * @return array
  51.      */
  52.     public static function getSubscribedEvents(): array
  53.     {
  54.         return [
  55.             ContentFormEvents::CONTENT_PUBLISH => ['processPublish'10],
  56.             ContentFormEvents::CONTENT_CANCEL => ['processCancel'10],
  57.             ContentFormEvents::CONTENT_SAVE_DRAFT => ['processSaveDraft'10],
  58.             ContentFormEvents::CONTENT_CREATE_DRAFT => ['processCreateDraft'10],
  59.         ];
  60.     }
  61.     /**
  62.      * @param \Ibexa\ContentForms\Event\FormActionEvent $event
  63.      *
  64.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\BadStateException
  65.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\ContentFieldValidationException
  66.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\ContentValidationException
  67.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException
  68.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
  69.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
  70.      * @throws \Ibexa\Core\Base\Exceptions\InvalidArgumentException
  71.      */
  72.     public function processSaveDraft(FormActionEvent $event)
  73.     {
  74.         /** @var \Ibexa\ContentForms\Data\Content\ContentCreateData|\Ibexa\ContentForms\Data\Content\ContentUpdateData $data */
  75.         $data $event->getData();
  76.         $form $event->getForm();
  77.         $formConfig $form->getConfig();
  78.         $languageCode $formConfig->getOption('languageCode');
  79.         $draft $this->saveDraft($data$languageCode, []);
  80.         $referrerLocation $event->getOption('referrerLocation');
  81.         $contentLocation $this->resolveLocation($draft$referrerLocation$data);
  82.         $event->setPayload('content'$draft);
  83.         $event->setPayload('is_new'$draft->contentInfo->isDraft());
  84.         $defaultUrl $this->router->generate('ibexa.content.draft.edit', [
  85.             'contentId' => $draft->id,
  86.             'versionNo' => $draft->getVersionInfo()->versionNo,
  87.             'language' => $languageCode,
  88.             'locationId' => null !== $contentLocation $contentLocation->id null,
  89.         ]);
  90.         $event->setResponse(new RedirectResponse($formConfig->getAction() ?: $defaultUrl));
  91.     }
  92.     /**
  93.      * @param \Ibexa\ContentForms\Event\FormActionEvent $event
  94.      *
  95.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\BadStateException
  96.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\ContentFieldValidationException
  97.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\ContentValidationException
  98.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException
  99.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
  100.      * @throws \Ibexa\Core\Base\Exceptions\InvalidArgumentException
  101.      */
  102.     public function processPublish(FormActionEvent $event)
  103.     {
  104.         /** @var \Ibexa\ContentForms\Data\Content\ContentCreateData|\Ibexa\ContentForms\Data\Content\ContentUpdateData $data */
  105.         $data $event->getData();
  106.         $form $event->getForm();
  107.         $draft $this->saveDraft($data$form->getConfig()->getOption('languageCode'));
  108.         $versionInfo $draft->versionInfo;
  109.         $content $this->contentService->publishVersion($versionInfo, [$versionInfo->initialLanguageCode]);
  110.         $event->setPayload('content'$content);
  111.         $event->setPayload('is_new'$draft->contentInfo->isDraft());
  112.         $redirectUrl $form['redirectUrlAfterPublish']->getData() ?: $this->router->generate(
  113.             'ibexa.content.view',
  114.             [
  115.                 'contentId' => $content->id,
  116.                 'locationId' => $content->contentInfo->mainLocationId,
  117.             ]
  118.         );
  119.         $event->setResponse(new RedirectResponse($redirectUrl));
  120.     }
  121.     /**
  122.      * @param \Ibexa\ContentForms\Event\FormActionEvent $event
  123.      *
  124.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\BadStateException
  125.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
  126.      */
  127.     public function processCancel(FormActionEvent $event)
  128.     {
  129.         /** @var \Ibexa\ContentForms\Data\Content\ContentCreateData|\Ibexa\ContentForms\Data\Content\ContentUpdateData $data */
  130.         $data $event->getData();
  131.         if ($data->isNew()) {
  132.             $parentLocation $this->locationService->loadLocation($data->getLocationStructs()[0]->parentLocationId);
  133.             $response = new RedirectResponse($this->router->generate(
  134.                 'ibexa.content.view',
  135.                 [
  136.                     'contentId' => $parentLocation->contentId,
  137.                     'locationId' => $parentLocation->id,
  138.                 ]
  139.             ));
  140.             $event->setResponse($response);
  141.             return;
  142.         }
  143.         $content $data->contentDraft;
  144.         $contentInfo $content->contentInfo;
  145.         $versionInfo $data->contentDraft->getVersionInfo();
  146.         $event->setPayload('content'$content);
  147.         // if there is only one version you have to remove whole content instead of a version itself
  148.         if (=== count($this->contentService->loadVersions($contentInfo))) {
  149.             $parentLocation $this->locationService->loadParentLocationsForDraftContent($versionInfo)[0];
  150.             $redirectionLocationId $parentLocation->id;
  151.             $redirectionContentId $parentLocation->contentId;
  152.         } else {
  153.             $redirectionLocationId $contentInfo->mainLocationId;
  154.             $redirectionContentId $contentInfo->id;
  155.         }
  156.         $this->contentService->deleteVersion($versionInfo);
  157.         $url $this->router->generate(
  158.             'ibexa.content.view',
  159.             [
  160.                 'contentId' => $redirectionContentId,
  161.                 'locationId' => $redirectionLocationId,
  162.             ],
  163.             UrlGeneratorInterface::ABSOLUTE_URL
  164.         );
  165.         $event->setResponse(new RedirectResponse($url));
  166.     }
  167.     /**
  168.      * @param \Ibexa\ContentForms\Event\FormActionEvent $event
  169.      *
  170.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
  171.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
  172.      */
  173.     public function processCreateDraft(FormActionEvent $event)
  174.     {
  175.         /** @var $createContentDraft \Ibexa\ContentForms\Data\Content\CreateContentDraftData */
  176.         $createContentDraft $event->getData();
  177.         $contentInfo $this->contentService->loadContentInfo($createContentDraft->contentId);
  178.         $versionInfo $this->contentService->loadVersionInfo($contentInfo$createContentDraft->fromVersionNo);
  179.         $contentDraft $this->contentService->createContentDraft($contentInfo$versionInfo);
  180.         $referrerLocation $event->getOption('referrerLocation');
  181.         $event->setPayload('content'$contentDraft);
  182.         $event->setPayload('is_new'$contentDraft->contentInfo->isDraft());
  183.         $contentEditUrl $this->router->generate('ibexa.content.draft.edit', [
  184.             'contentId' => $contentDraft->id,
  185.             'versionNo' => $contentDraft->getVersionInfo()->versionNo,
  186.             'language' => $contentDraft->contentInfo->mainLanguageCode,
  187.             'locationId' => null !== $referrerLocation $referrerLocation->id null,
  188.         ]);
  189.         $event->setResponse(new RedirectResponse($contentEditUrl));
  190.     }
  191.     /**
  192.      * Saves content draft corresponding to $data.
  193.      * Depending on the nature of $data (create or update data), the draft will either be created or simply updated.
  194.      *
  195.      * @param \Ibexa\Contracts\Core\Repository\Values\Content\ContentStruct|\Ibexa\ContentForms\Data\Content\ContentCreateData|\Ibexa\ContentForms\Data\Content\ContentUpdateData $data
  196.      * @param $languageCode
  197.      *
  198.      * @return \Ibexa\Contracts\Core\Repository\Values\Content\Content
  199.      *
  200.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\BadStateException
  201.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\ContentFieldValidationException
  202.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\ContentValidationException
  203.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException
  204.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
  205.      * @throws \Ibexa\Core\Base\Exceptions\InvalidArgumentException
  206.      */
  207.     private function saveDraft(ContentStruct $datastring $languageCode, ?array $fieldIdentifiersToValidate null)
  208.     {
  209.         $mainLanguageCode $this->resolveMainLanguageCode($data);
  210.         foreach ($data->fieldsData as $fieldDefIdentifier => $fieldData) {
  211.             if ($mainLanguageCode != $languageCode && !$fieldData->fieldDefinition->isTranslatable) {
  212.                 continue;
  213.             }
  214.             $data->setField($fieldDefIdentifier$fieldData->value$languageCode);
  215.         }
  216.         if ($data->isNew()) {
  217.             $contentDraft $this->contentService->createContent($data$data->getLocationStructs(), $fieldIdentifiersToValidate);
  218.         } else {
  219.             $contentDraft $this->contentService->updateContent($data->contentDraft->getVersionInfo(), $data$fieldIdentifiersToValidate);
  220.         }
  221.         return $contentDraft;
  222.     }
  223.     /**
  224.      * @param \Ibexa\ContentForms\Data\Content\ContentCreateData|\Ibexa\ContentForms\Data\Content\ContentUpdateData $data
  225.      *
  226.      * @return string
  227.      *
  228.      * @throws \Ibexa\Core\Base\Exceptions\InvalidArgumentException
  229.      */
  230.     private function resolveMainLanguageCode($data): string
  231.     {
  232.         if (!$data instanceof ContentUpdateData && !$data instanceof ContentCreateData) {
  233.             throw new InvalidArgumentException(
  234.                 '$data',
  235.                 'Expected ContentUpdateData or ContentCreateData'
  236.             );
  237.         }
  238.         return $data->isNew()
  239.             ? $data->mainLanguageCode
  240.             $data->contentDraft->getVersionInfo()->getContentInfo()->mainLanguageCode;
  241.     }
  242.     /**
  243.      * @param \Ibexa\Contracts\Core\Repository\Values\Content\Content $content
  244.      * @param \Ibexa\Contracts\Core\Repository\Values\Content\Location|null $referrerLocation
  245.      * @param \Ibexa\ContentForms\Data\NewnessCheckable $data
  246.      *
  247.      * @return \Ibexa\Contracts\Core\Repository\Values\Content\Location|null
  248.      *
  249.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
  250.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
  251.      */
  252.     private function resolveLocation(Content $content, ?Location $referrerLocationNewnessCheckable $data): ?Location
  253.     {
  254.         if ($data->isNew() || (!$content->contentInfo->published && null === $content->contentInfo->mainLocationId)) {
  255.             return null// no location exists until new content is published
  256.         }
  257.         return $referrerLocation ?? $this->locationService->loadLocation($content->contentInfo->mainLocationId);
  258.     }
  259. }
  260. class_alias(ContentFormProcessor::class, 'EzSystems\EzPlatformContentForms\Form\Processor\ContentFormProcessor');