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

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