From 954725a6e92eef348cf2dbfd16151f414deb3419 Mon Sep 17 00:00:00 2001 From: Bartek Wajda Date: Thu, 14 Mar 2024 16:50:23 +0100 Subject: [PATCH] IBX-7935: Handled User-related structs in `FieldCollectionType` dispatcher --- src/bundle/Controller/UserController.php | 12 +- src/bundle/Resources/config/services.yaml | 17 +-- src/lib/Event/ContentFormEvents.php | 10 ++ src/lib/Event/UserCreateFieldOptionsEvent.php | 82 ++++++++++++ src/lib/Event/UserUpdateFieldOptionsEvent.php | 98 ++++++++++++++ src/lib/Form/Type/Content/BaseContentType.php | 2 + .../Form/Type/Content/ContentFieldType.php | 2 + .../Form/Type/Content/FieldCollectionType.php | 123 +++++++++++++----- src/lib/Form/Type/User/UserCreateType.php | 3 +- src/lib/Form/Type/User/UserUpdateType.php | 4 +- 10 files changed, 311 insertions(+), 42 deletions(-) create mode 100644 src/lib/Event/UserCreateFieldOptionsEvent.php create mode 100644 src/lib/Event/UserUpdateFieldOptionsEvent.php diff --git a/src/bundle/Controller/UserController.php b/src/bundle/Controller/UserController.php index 1f94138e..d68ef09d 100644 --- a/src/bundle/Controller/UserController.php +++ b/src/bundle/Controller/UserController.php @@ -17,6 +17,7 @@ use Ibexa\ContentForms\User\View\UserCreateView; use Ibexa\ContentForms\User\View\UserUpdateView; use Ibexa\Contracts\ContentForms\Content\Form\Provider\GroupedContentFormFieldsProviderInterface; +use Ibexa\Contracts\Core\Repository\ContentService; use Ibexa\Contracts\Core\Repository\ContentTypeService; use Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException; use Ibexa\Contracts\Core\Repository\LanguageService; @@ -53,6 +54,9 @@ class UserController extends Controller /** @var \Ibexa\Contracts\ContentForms\Content\Form\Provider\GroupedContentFormFieldsProviderInterface */ private $groupedContentFormFieldsProvider; + /** @var \Ibexa\Contracts\Core\Repository\ContentService */ + private $contentService; + public function __construct( ContentTypeService $contentTypeService, UserService $userService, @@ -61,7 +65,8 @@ public function __construct( ActionDispatcherInterface $userActionDispatcher, PermissionResolver $permissionResolver, UserLanguagePreferenceProviderInterface $userLanguagePreferenceProvider, - GroupedContentFormFieldsProviderInterface $groupedContentFormFieldsProvider + GroupedContentFormFieldsProviderInterface $groupedContentFormFieldsProvider, + ContentService $contentService ) { $this->contentTypeService = $contentTypeService; $this->userService = $userService; @@ -71,6 +76,7 @@ public function __construct( $this->permissionResolver = $permissionResolver; $this->userLanguagePreferenceProvider = $userLanguagePreferenceProvider; $this->groupedContentFormFieldsProvider = $groupedContentFormFieldsProvider; + $this->contentService = $contentService; } /** @@ -114,6 +120,7 @@ public function createAction( $form = $this->createForm(UserCreateType::class, $data, [ 'languageCode' => $language->languageCode, 'mainLanguageCode' => $language->languageCode, + 'userCreateStruct' => $data, ]); $form->handleRequest($request); @@ -152,6 +159,7 @@ public function createAction( * @throws \Ibexa\Contracts\Core\Repository\Exceptions\BadStateException * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException + * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException * @throws \Ibexa\Core\Base\Exceptions\InvalidArgumentType * @throws \Ibexa\Core\Base\Exceptions\UnauthorizedException */ @@ -192,8 +200,10 @@ public function editAction( $userUpdate, [ 'location' => $location, + 'content' => $this->contentService->loadContent($contentId), 'languageCode' => $language, 'mainLanguageCode' => $user->contentInfo->mainLanguageCode, + 'userUpdateStruct' => $userUpdate, ] ); $form->handleRequest($request); diff --git a/src/bundle/Resources/config/services.yaml b/src/bundle/Resources/config/services.yaml index eed59f8b..2d9f0621 100644 --- a/src/bundle/Resources/config/services.yaml +++ b/src/bundle/Resources/config/services.yaml @@ -99,14 +99,15 @@ services: Ibexa\Bundle\ContentForms\Controller\UserController: arguments: - - '@ibexa.api.service.content_type' - - '@ibexa.api.service.user' - - '@ibexa.api.service.location' - - '@ibexa.api.service.language' - - '@Ibexa\ContentForms\Form\ActionDispatcher\UserDispatcher' - - '@Ibexa\Contracts\Core\Repository\PermissionResolver' - - '@Ibexa\Core\MVC\Symfony\Locale\UserLanguagePreferenceProvider' - - '@Ibexa\ContentForms\Content\Form\Provider\GroupedContentFormFieldsProvider' + $contentTypeService: '@ibexa.api.service.content_type' + $userService: '@ibexa.api.service.user' + $locationService: '@ibexa.api.service.location' + $languageService: '@ibexa.api.service.language' + $userActionDispatcher: '@Ibexa\ContentForms\Form\ActionDispatcher\UserDispatcher' + $permissionResolver: '@Ibexa\Contracts\Core\Repository\PermissionResolver' + $userLanguagePreferenceProvider: '@Ibexa\Core\MVC\Symfony\Locale\UserLanguagePreferenceProvider' + $groupedContentFormFieldsProvider: '@Ibexa\ContentForms\Content\Form\Provider\GroupedContentFormFieldsProvider' + $contentService: '@ibexa.api.service.content' parent: Ibexa\Core\MVC\Symfony\Controller\Controller tags: - { name: controller.service_arguments } diff --git a/src/lib/Event/ContentFormEvents.php b/src/lib/Event/ContentFormEvents.php index e25d4560..601fa79d 100644 --- a/src/lib/Event/ContentFormEvents.php +++ b/src/lib/Event/ContentFormEvents.php @@ -64,6 +64,16 @@ final class ContentFormEvents * Triggered when resolving Field Type options for content create form. */ public const CONTENT_CREATE_FIELD_OPTIONS = 'content.create.field.options'; + + /** + * Triggered when resolving Field Type options for user edit form. + */ + public const USER_EDIT_FIELD_OPTIONS = 'user.edit.field.options'; + + /** + * Triggered when resolving Field Type options for user create form. + */ + public const USER_CREATE_FIELD_OPTIONS = 'user.create.field.options'; } class_alias(ContentFormEvents::class, 'EzSystems\EzPlatformContentForms\Event\ContentFormEvents'); diff --git a/src/lib/Event/UserCreateFieldOptionsEvent.php b/src/lib/Event/UserCreateFieldOptionsEvent.php new file mode 100644 index 00000000..26a05e84 --- /dev/null +++ b/src/lib/Event/UserCreateFieldOptionsEvent.php @@ -0,0 +1,82 @@ + */ + private $options; + + public function __construct( + UserCreateStruct $userCreateStruct, + FormInterface $parentForm, + FieldData $fieldData, + array $options + ) { + $this->userCreateStruct = $userCreateStruct; + $this->parentForm = $parentForm; + $this->fieldData = $fieldData; + $this->options = $options; + } + + public function getUserCreateStruct(): UserCreateStruct + { + return $this->userCreateStruct; + } + + public function getParentForm(): FormInterface + { + return $this->parentForm; + } + + public function getFieldData(): FieldData + { + return $this->fieldData; + } + + /** + * @return array + */ + public function getOptions(): array + { + return $this->options; + } + + /** + * @param array $options + */ + public function setOptions(array $options): void + { + $this->options = $options; + } + + public function setOption(string $option, $value): void + { + $this->options[$option] = $value; + } + + public function getOption(string $option) + { + return $this->options[$option] ?? null; + } +} diff --git a/src/lib/Event/UserUpdateFieldOptionsEvent.php b/src/lib/Event/UserUpdateFieldOptionsEvent.php new file mode 100644 index 00000000..6c2a62c4 --- /dev/null +++ b/src/lib/Event/UserUpdateFieldOptionsEvent.php @@ -0,0 +1,98 @@ + */ + private $options; + + public function __construct( + Content $content, + UserUpdateStruct $userUpdateStruct, + FormInterface $parentForm, + FieldData $fieldData, + array $options + ) { + $this->content = $content; + $this->userUpdateStruct = $userUpdateStruct; + $this->parentForm = $parentForm; + $this->fieldData = $fieldData; + $this->options = $options; + } + + public function getContent(): Content + { + return $this->content; + } + + public function setContent(Content $content): void + { + $this->content = $content; + } + + public function getUserUpdateStruct(): UserUpdateStruct + { + return $this->userUpdateStruct; + } + + public function getParentForm(): FormInterface + { + return $this->parentForm; + } + + public function getFieldData(): FieldData + { + return $this->fieldData; + } + + /** + * @return array + */ + public function getOptions(): array + { + return $this->options; + } + + /** + * @param array $options + */ + public function setOptions(array $options): void + { + $this->options = $options; + } + + public function setOption(string $option, $value): void + { + $this->options[$option] = $value; + } + + public function getOption(string $option) + { + return $this->options[$option] ?? null; + } +} diff --git a/src/lib/Form/Type/Content/BaseContentType.php b/src/lib/Form/Type/Content/BaseContentType.php index 52b9b620..5e0d8cd4 100644 --- a/src/lib/Form/Type/Content/BaseContentType.php +++ b/src/lib/Form/Type/Content/BaseContentType.php @@ -43,6 +43,8 @@ public function buildForm(FormBuilderInterface $builder, array $options) 'content' => $options['content'] ?? null, 'contentCreateStruct' => $options['contentCreateStruct'] ?? null, 'contentUpdateStruct' => $options['contentUpdateStruct'] ?? null, + 'userCreateStruct' => $options['userCreateStruct'] ?? null, + 'userUpdateStruct' => $options['userUpdateStruct'] ?? null, ], ]) ->add('redirectUrlAfterPublish', HiddenType::class, [ diff --git a/src/lib/Form/Type/Content/ContentFieldType.php b/src/lib/Form/Type/Content/ContentFieldType.php index a85041bd..d93357da 100644 --- a/src/lib/Form/Type/Content/ContentFieldType.php +++ b/src/lib/Form/Type/Content/ContentFieldType.php @@ -48,6 +48,8 @@ public function configureOptions(OptionsResolver $resolver) 'location' => null, 'contentCreateStruct' => null, 'contentUpdateStruct' => null, + 'userCreateStruct' => null, + 'userUpdateStruct' => null, 'data_class' => FieldData::class, 'translation_domain' => 'ezplatform_content_forms_content', ]) diff --git a/src/lib/Form/Type/Content/FieldCollectionType.php b/src/lib/Form/Type/Content/FieldCollectionType.php index 4873364b..39e9c32c 100644 --- a/src/lib/Form/Type/Content/FieldCollectionType.php +++ b/src/lib/Form/Type/Content/FieldCollectionType.php @@ -11,10 +11,14 @@ use Ibexa\ContentForms\Event\ContentCreateFieldOptionsEvent; use Ibexa\ContentForms\Event\ContentFormEvents; use Ibexa\ContentForms\Event\ContentUpdateFieldOptionsEvent; +use Ibexa\ContentForms\Event\UserCreateFieldOptionsEvent; +use Ibexa\ContentForms\Event\UserUpdateFieldOptionsEvent; +use Ibexa\Contracts\ContentForms\Data\Content\FieldData; use Symfony\Component\Form\Extension\Core\Type\CollectionType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; +use Symfony\Component\Form\FormInterface; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; class FieldCollectionType extends CollectionType @@ -43,40 +47,12 @@ public function buildForm( } // Then add all rows again in the correct order - foreach ($data as $name => $value) { + foreach ($data as $name => $entryData) { $entryOptions = array_replace([ 'property_path' => '[' . $name . ']', ], $options['entry_options']); - $entryData = $data[$name]; - - if ($this->isContentUpdate($entryOptions)) { - /** @var \Ibexa\ContentForms\Event\ContentUpdateFieldOptionsEvent $contentUpdateFieldOptionsEvent */ - $contentUpdateFieldOptionsEvent = $this->eventDispatcher->dispatch( - new ContentUpdateFieldOptionsEvent( - $entryOptions['content'], - $entryOptions['contentUpdateStruct'], - $form, - $entryData, - $entryOptions - ), - ContentFormEvents::CONTENT_EDIT_FIELD_OPTIONS - ); - - $entryOptions = $contentUpdateFieldOptionsEvent->getOptions(); - } elseif ($this->isContentCreate($entryOptions)) { - /** @var \Ibexa\ContentForms\Event\ContentCreateFieldOptionsEvent $contentUpdateFieldOptionsEvent */ - $contentCreateFieldOptionsEvent = $this->eventDispatcher->dispatch( - new ContentCreateFieldOptionsEvent( - $entryOptions['contentCreateStruct'], - $form, - $entryData, - $entryOptions - ), - ContentFormEvents::CONTENT_CREATE_FIELD_OPTIONS - ); - - $entryOptions = $contentCreateFieldOptionsEvent->getOptions(); - } + + $entryOptions = $this->dispatchFieldOptionsEvent($entryData, $entryOptions, $form); $form->add($name, $options['entry_type'], $entryOptions); } @@ -92,6 +68,91 @@ private function isContentUpdate(array $entryOptions): bool { return !empty($entryOptions['content']) && !empty($entryOptions['contentUpdateStruct']); } + + /** + * @param array $entryOptions + */ + private function isUserCreate(array $entryOptions): bool + { + return !empty($entryOptions['userCreateStruct']); + } + + /** + * @param array $entryOptions + */ + private function isUserUpdate(array $entryOptions): bool + { + return !empty($entryOptions['userUpdateStruct']); + } + + /** + * @param array $entryOptions + * + * @return array $entryOptions + */ + private function dispatchFieldOptionsEvent( + FieldData $entryData, + array $entryOptions, + FormInterface $form + ): array { + if ($this->isContentUpdate($entryOptions)) { + /** @var \Ibexa\ContentForms\Event\ContentUpdateFieldOptionsEvent $contentUpdateFieldOptionsEvent */ + $contentUpdateFieldOptionsEvent = $this->eventDispatcher->dispatch( + new ContentUpdateFieldOptionsEvent( + $entryOptions['content'], + $entryOptions['contentUpdateStruct'], + $form, + $entryData, + $entryOptions + ), + ContentFormEvents::CONTENT_EDIT_FIELD_OPTIONS + ); + + $entryOptions = $contentUpdateFieldOptionsEvent->getOptions(); + } elseif ($this->isContentCreate($entryOptions)) { + /** @var \Ibexa\ContentForms\Event\ContentCreateFieldOptionsEvent $contentUpdateFieldOptionsEvent */ + $contentCreateFieldOptionsEvent = $this->eventDispatcher->dispatch( + new ContentCreateFieldOptionsEvent( + $entryOptions['contentCreateStruct'], + $form, + $entryData, + $entryOptions + ), + ContentFormEvents::CONTENT_CREATE_FIELD_OPTIONS + ); + + $entryOptions = $contentCreateFieldOptionsEvent->getOptions(); + } elseif ($this->isUserCreate($entryOptions)) { + /** @var \Ibexa\ContentForms\Event\UserCreateFieldOptionsEvent $userCreateFieldOptionsEvent */ + $userCreateFieldOptionsEvent = $this->eventDispatcher->dispatch( + new UserCreateFieldOptionsEvent( + $entryOptions['userCreateStruct'], + $form, + $entryData, + $entryOptions + ), + ContentFormEvents::USER_CREATE_FIELD_OPTIONS + ); + + $entryOptions = $userCreateFieldOptionsEvent->getOptions(); + } elseif ($this->isUserUpdate($entryOptions)) { + /** @var \Ibexa\ContentForms\Event\UserUpdateFieldOptionsEvent $userUpdateFieldOptionsEvent */ + $userUpdateFieldOptionsEvent = $this->eventDispatcher->dispatch( + new UserUpdateFieldOptionsEvent( + $entryOptions['content'], + $entryOptions['userUpdateStruct'], + $form, + $entryData, + $entryOptions + ), + ContentFormEvents::USER_EDIT_FIELD_OPTIONS + ); + + $entryOptions = $userUpdateFieldOptionsEvent->getOptions(); + } + + return $entryOptions; + } } class_alias(FieldCollectionType::class, 'EzSystems\EzPlatformContentForms\Form\Type\Content\FieldCollectionType'); diff --git a/src/lib/Form/Type/User/UserCreateType.php b/src/lib/Form/Type/User/UserCreateType.php index 7669cb9d..bc92910e 100644 --- a/src/lib/Form/Type/User/UserCreateType.php +++ b/src/lib/Form/Type/User/UserCreateType.php @@ -42,10 +42,11 @@ public function buildForm(FormBuilderInterface $builder, array $options) ->add('create', SubmitType::class, ['label' => /** @Desc("Create") */ 'user.create']); } - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { $resolver ->setDefaults([ + 'userCreateStruct' => null, 'data_class' => UserCreateData::class, 'intent' => 'create', 'translation_domain' => 'ezplatform_content_forms_user', diff --git a/src/lib/Form/Type/User/UserUpdateType.php b/src/lib/Form/Type/User/UserUpdateType.php index 908b1d87..33aa7aac 100644 --- a/src/lib/Form/Type/User/UserUpdateType.php +++ b/src/lib/Form/Type/User/UserUpdateType.php @@ -42,11 +42,13 @@ public function buildForm(FormBuilderInterface $builder, array $options) ->add('update', SubmitType::class, ['label' => /** @Desc("Update") */ 'user.update']); } - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { $resolver ->setDefaults([ 'location' => null, + 'content' => null, + 'userUpdateStruct' => null, 'data_class' => UserUpdateData::class, 'intent' => 'update', 'translation_domain' => 'ezplatform_content_forms_user',