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.         $referrerLocation $event->getOption('referrerLocation');
  108.         $draft $this->saveDraft($data$form->getConfig()->getOption('languageCode'));
  109.         $versionInfo $draft->versionInfo;
  110.         $content $this->contentService->publishVersion($versionInfo, [$versionInfo->initialLanguageCode]);
  111.         $event->setPayload('content'$content);
  112.         $event->setPayload('is_new'$draft->contentInfo->isDraft());
  113.         $locationId $referrerLocation !== null && $data instanceof ContentUpdateData
  114.             $referrerLocation->id
  115.             $content->contentInfo->mainLocationId;
  116.         $redirectUrl $form['redirectUrlAfterPublish']->getData() ?: $this->router->generate(
  117.             'ibexa.content.view',
  118.             [
  119.                 'contentId' => $content->id,
  120.                 'locationId' => $locationId,
  121.             ]
  122.         );
  123.         $event->setResponse(new RedirectResponse($redirectUrl));
  124.     }
  125.     /**
  126.      * @param \Ibexa\ContentForms\Event\FormActionEvent $event
  127.      *
  128.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\BadStateException
  129.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
  130.      */
  131.     public function processCancel(FormActionEvent $event)
  132.     {
  133.         /** @var \Ibexa\ContentForms\Data\Content\ContentCreateData|\Ibexa\ContentForms\Data\Content\ContentUpdateData $data */
  134.         $data $event->getData();
  135.         if ($data->isNew()) {
  136.             $parentLocation $this->locationService->loadLocation($data->getLocationStructs()[0]->parentLocationId);
  137.             $response = new RedirectResponse($this->router->generate(
  138.                 'ibexa.content.view',
  139.                 [
  140.                     'contentId' => $parentLocation->contentId,
  141.                     'locationId' => $parentLocation->id,
  142.                 ]
  143.             ));
  144.             $event->setResponse($response);
  145.             return;
  146.         }
  147.         $content $data->contentDraft;
  148.         $contentInfo $content->contentInfo;
  149.         $versionInfo $data->contentDraft->getVersionInfo();
  150.         $event->setPayload('content'$content);
  151.         // if there is only one version you have to remove whole content instead of a version itself
  152.         if (=== count($this->contentService->loadVersions($contentInfo))) {
  153.             $parentLocation $this->locationService->loadParentLocationsForDraftContent($versionInfo)[0];
  154.             $redirectionLocationId $parentLocation->id;
  155.             $redirectionContentId $parentLocation->contentId;
  156.         } else {
  157.             $redirectionLocationId $contentInfo->mainLocationId;
  158.             $redirectionContentId $contentInfo->id;
  159.         }
  160.         $this->contentService->deleteVersion($versionInfo);
  161.         $url $this->router->generate(
  162.             'ibexa.content.view',
  163.             [
  164.                 'contentId' => $redirectionContentId,
  165.                 'locationId' => $redirectionLocationId,
  166.             ],
  167.             UrlGeneratorInterface::ABSOLUTE_URL
  168.         );
  169.         $event->setResponse(new RedirectResponse($url));
  170.     }
  171.     /**
  172.      * @param \Ibexa\ContentForms\Event\FormActionEvent $event
  173.      *
  174.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
  175.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
  176.      */
  177.     public function processCreateDraft(FormActionEvent $event)
  178.     {
  179.         /** @var $createContentDraft \Ibexa\ContentForms\Data\Content\CreateContentDraftData */
  180.         $createContentDraft $event->getData();
  181.         $contentInfo $this->contentService->loadContentInfo($createContentDraft->contentId);
  182.         $versionInfo $this->contentService->loadVersionInfo($contentInfo$createContentDraft->fromVersionNo);
  183.         $contentDraft $this->contentService->createContentDraft($contentInfo$versionInfo);
  184.         $referrerLocation $event->getOption('referrerLocation');
  185.         $event->setPayload('content'$contentDraft);
  186.         $event->setPayload('is_new'$contentDraft->contentInfo->isDraft());
  187.         $contentEditUrl $this->router->generate('ibexa.content.draft.edit', [
  188.             'contentId' => $contentDraft->id,
  189.             'versionNo' => $contentDraft->getVersionInfo()->versionNo,
  190.             'language' => $contentDraft->contentInfo->mainLanguageCode,
  191.             'locationId' => null !== $referrerLocation $referrerLocation->id null,
  192.         ]);
  193.         $event->setResponse(new RedirectResponse($contentEditUrl));
  194.     }
  195.     /**
  196.      * Saves content draft corresponding to $data.
  197.      * Depending on the nature of $data (create or update data), the draft will either be created or simply updated.
  198.      *
  199.      * @param \Ibexa\Contracts\Core\Repository\Values\Content\ContentStruct|\Ibexa\ContentForms\Data\Content\ContentCreateData|\Ibexa\ContentForms\Data\Content\ContentUpdateData $data
  200.      * @param $languageCode
  201.      *
  202.      * @return \Ibexa\Contracts\Core\Repository\Values\Content\Content
  203.      *
  204.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\BadStateException
  205.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\ContentFieldValidationException
  206.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\ContentValidationException
  207.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException
  208.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
  209.      * @throws \Ibexa\Core\Base\Exceptions\InvalidArgumentException
  210.      */
  211.     private function saveDraft(ContentStruct $datastring $languageCode, ?array $fieldIdentifiersToValidate null)
  212.     {
  213.         $mainLanguageCode $this->resolveMainLanguageCode($data);
  214.         foreach ($data->fieldsData as $fieldDefIdentifier => $fieldData) {
  215.             if ($mainLanguageCode != $languageCode && !$fieldData->fieldDefinition->isTranslatable) {
  216.                 continue;
  217.             }
  218.             $data->setField($fieldDefIdentifier$fieldData->value$languageCode);
  219.         }
  220.         if ($data->isNew()) {
  221.             $contentDraft $this->contentService->createContent($data$data->getLocationStructs(), $fieldIdentifiersToValidate);
  222.         } else {
  223.             $contentDraft $this->contentService->updateContent($data->contentDraft->getVersionInfo(), $data$fieldIdentifiersToValidate);
  224.         }
  225.         return $contentDraft;
  226.     }
  227.     /**
  228.      * @param \Ibexa\ContentForms\Data\Content\ContentCreateData|\Ibexa\ContentForms\Data\Content\ContentUpdateData $data
  229.      *
  230.      * @return string
  231.      *
  232.      * @throws \Ibexa\Core\Base\Exceptions\InvalidArgumentException
  233.      */
  234.     private function resolveMainLanguageCode($data): string
  235.     {
  236.         if (!$data instanceof ContentUpdateData && !$data instanceof ContentCreateData) {
  237.             throw new InvalidArgumentException(
  238.                 '$data',
  239.                 'Expected ContentUpdateData or ContentCreateData'
  240.             );
  241.         }
  242.         return $data->isNew()
  243.             ? $data->mainLanguageCode
  244.             $data->contentDraft->getVersionInfo()->getContentInfo()->mainLanguageCode;
  245.     }
  246.     /**
  247.      * @param \Ibexa\Contracts\Core\Repository\Values\Content\Content $content
  248.      * @param \Ibexa\Contracts\Core\Repository\Values\Content\Location|null $referrerLocation
  249.      * @param \Ibexa\ContentForms\Data\NewnessCheckable $data
  250.      *
  251.      * @return \Ibexa\Contracts\Core\Repository\Values\Content\Location|null
  252.      *
  253.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
  254.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
  255.      */
  256.     private function resolveLocation(Content $content, ?Location $referrerLocationNewnessCheckable $data): ?Location
  257.     {
  258.         if ($data->isNew() || (!$content->contentInfo->published && null === $content->contentInfo->mainLocationId)) {
  259.             return null// no location exists until new content is published
  260.         }
  261.         return $referrerLocation ?? $this->locationService->loadLocation($content->contentInfo->mainLocationId);
  262.     }
  263. }
  264. class_alias(ContentFormProcessor::class, 'EzSystems\EzPlatformContentForms\Form\Processor\ContentFormProcessor');