From 5602b13f02cbccae1e847928db7a53d4925c0209 Mon Sep 17 00:00:00 2001 From: Dominic Tubach Date: Tue, 19 Nov 2024 16:58:25 +0100 Subject: [PATCH] Add support for vertical tabs in remote forms --- .../FormSpec/AbstractFormElementContainer.php | 16 ++++-- .../Form/FormSpec/FormElementContainer.php | 2 + Civi/RemoteTools/Form/FormSpec/FormSpec.php | 2 + Civi/RemoteTools/Form/FormSpec/FormTab.php | 50 +++++++++++++++++++ .../Form/FormSpec/VerticalTabsContainer.php | 39 +++++++++++++++ .../Factory/Layout/CategorizationFactory.php | 47 +++++++++++++++++ .../Factory/Layout/CategoryFactory.php | 47 +++++++++++++++++ 7 files changed, 198 insertions(+), 5 deletions(-) create mode 100644 Civi/RemoteTools/Form/FormSpec/FormTab.php create mode 100644 Civi/RemoteTools/Form/FormSpec/VerticalTabsContainer.php create mode 100644 Civi/RemoteTools/JsonForms/FormSpec/Factory/Layout/CategorizationFactory.php create mode 100644 Civi/RemoteTools/JsonForms/FormSpec/Factory/Layout/CategoryFactory.php diff --git a/Civi/RemoteTools/Form/FormSpec/AbstractFormElementContainer.php b/Civi/RemoteTools/Form/FormSpec/AbstractFormElementContainer.php index 3f68b4b..2eb1af8 100644 --- a/Civi/RemoteTools/Form/FormSpec/AbstractFormElementContainer.php +++ b/Civi/RemoteTools/Form/FormSpec/AbstractFormElementContainer.php @@ -22,6 +22,8 @@ use Civi\RemoteTools\Form\FormSpec\Button\SubmitButton; /** + * @template T of FormElementInterface + * * @api */ abstract class AbstractFormElementContainer { @@ -29,12 +31,12 @@ abstract class AbstractFormElementContainer { private string $title; /** - * @phpstan-var array + * @phpstan-var array */ private array $elements = []; /** - * @phpstan-param array $elements + * @phpstan-param array $elements */ public function __construct(string $title, array $elements = []) { $this->title = $title; @@ -55,6 +57,8 @@ public function setTitle(string $title): self { } /** + * @phpstan-param T $element + * * @return $this */ public function addElement(FormElementInterface $element): self { @@ -64,7 +68,7 @@ public function addElement(FormElementInterface $element): self { } /** - * @phpstan-return array + * @phpstan-return array */ public function getElements(): array { return $this->elements; @@ -75,6 +79,8 @@ public function hasElements(): bool { } /** + * @phpstan-param T $element + * * @return $this */ public function insertElement(FormElementInterface $element, int $index): self { @@ -84,7 +90,7 @@ public function insertElement(FormElementInterface $element, int $index): self { } /** - * @phpstan-param array $elements + * @phpstan-param array $elements */ public function setElements(array $elements): self { $this->elements = $elements; @@ -102,7 +108,7 @@ public function getFields(): array { if ($element instanceof AbstractFormField) { $fields[$element->getName()] = $element; } - elseif ($element instanceof FormElementContainer) { + elseif ($element instanceof AbstractFormElementContainer) { $containerFields = $element->getFields(); $nonUniqueFields = array_keys(array_intersect_key($fields, $containerFields)); if ([] !== $nonUniqueFields) { diff --git a/Civi/RemoteTools/Form/FormSpec/FormElementContainer.php b/Civi/RemoteTools/Form/FormSpec/FormElementContainer.php index 3f7f2e0..49c090d 100644 --- a/Civi/RemoteTools/Form/FormSpec/FormElementContainer.php +++ b/Civi/RemoteTools/Form/FormSpec/FormElementContainer.php @@ -22,6 +22,8 @@ /** * @codeCoverageIgnore * + * @extends AbstractFormElementContainer + * * @api */ class FormElementContainer extends AbstractFormElementContainer implements FormElementInterface { diff --git a/Civi/RemoteTools/Form/FormSpec/FormSpec.php b/Civi/RemoteTools/Form/FormSpec/FormSpec.php index d25aa6b..834ca9f 100644 --- a/Civi/RemoteTools/Form/FormSpec/FormSpec.php +++ b/Civi/RemoteTools/Form/FormSpec/FormSpec.php @@ -20,6 +20,8 @@ namespace Civi\RemoteTools\Form\FormSpec; /** + * @extends AbstractFormElementContainer + * * @api */ final class FormSpec extends AbstractFormElementContainer { diff --git a/Civi/RemoteTools/Form/FormSpec/FormTab.php b/Civi/RemoteTools/Form/FormSpec/FormTab.php new file mode 100644 index 0000000..e5e6d80 --- /dev/null +++ b/Civi/RemoteTools/Form/FormSpec/FormTab.php @@ -0,0 +1,50 @@ +. + */ + +declare(strict_types = 1); + +namespace Civi\RemoteTools\Form\FormSpec; + +/** + * @codeCoverageIgnore + * + * @api + */ +class FormTab extends AbstractFormElementContainer implements FormElementInterface { + + public ?string $description; + + public function __construct(string $title, array $elements = [], ?string $description = NULL) { + parent::__construct($title, $elements); + $this->description = $description; + } + + public function getType(): string { + return 'tab'; + } + + public function getDescription(): ?string { + return $this->description; + } + + public function setDescription(?string $description): self { + $this->description = $description; + + return $this; + } + +} diff --git a/Civi/RemoteTools/Form/FormSpec/VerticalTabsContainer.php b/Civi/RemoteTools/Form/FormSpec/VerticalTabsContainer.php new file mode 100644 index 0000000..0c28650 --- /dev/null +++ b/Civi/RemoteTools/Form/FormSpec/VerticalTabsContainer.php @@ -0,0 +1,39 @@ +. + */ + +declare(strict_types = 1); + +namespace Civi\RemoteTools\Form\FormSpec; + +/** + * @codeCoverageIgnore + * + * @extends AbstractFormElementContainer + * + * @api + */ +class VerticalTabsContainer extends AbstractFormElementContainer implements FormElementInterface { + + public function __construct(array $elements = []) { + parent::__construct('', $elements); + } + + public function getType(): string { + return 'vertical_tabs'; + } + +} diff --git a/Civi/RemoteTools/JsonForms/FormSpec/Factory/Layout/CategorizationFactory.php b/Civi/RemoteTools/JsonForms/FormSpec/Factory/Layout/CategorizationFactory.php new file mode 100644 index 0000000..de2c992 --- /dev/null +++ b/Civi/RemoteTools/JsonForms/FormSpec/Factory/Layout/CategorizationFactory.php @@ -0,0 +1,47 @@ +. + */ + +declare(strict_types = 1); + +namespace Civi\RemoteTools\JsonForms\FormSpec\Factory\Layout; + +use Civi\RemoteTools\Form\FormSpec\FormElementInterface; +use Civi\RemoteTools\Form\FormSpec\VerticalTabsContainer; +use Civi\RemoteTools\JsonForms\FormSpec\ElementUiSchemaFactoryInterface; +use Civi\RemoteTools\JsonForms\FormSpec\Factory\AbstractConcreteElementUiSchemaFactory; +use Civi\RemoteTools\JsonForms\JsonFormsElement; +use Civi\RemoteTools\JsonForms\Layout\JsonFormsCategorization; +use Webmozart\Assert\Assert; + +final class CategorizationFactory extends AbstractConcreteElementUiSchemaFactory { + + public function createSchema( + FormElementInterface $element, + ElementUiSchemaFactoryInterface $factory + ): JsonFormsElement { + Assert::isInstanceOf($element, VerticalTabsContainer::class); + /** @var \Civi\RemoteTools\Form\FormSpec\VerticalTabsContainer $element */ + $elements = array_map([$factory, 'createSchema'], $element->getElements()); + + return new JsonFormsCategorization($elements); + } + + public function supportsElement(FormElementInterface $element): bool { + return $element instanceof VerticalTabsContainer; + } + +} diff --git a/Civi/RemoteTools/JsonForms/FormSpec/Factory/Layout/CategoryFactory.php b/Civi/RemoteTools/JsonForms/FormSpec/Factory/Layout/CategoryFactory.php new file mode 100644 index 0000000..b81c96c --- /dev/null +++ b/Civi/RemoteTools/JsonForms/FormSpec/Factory/Layout/CategoryFactory.php @@ -0,0 +1,47 @@ +. + */ + +declare(strict_types = 1); + +namespace Civi\RemoteTools\JsonForms\FormSpec\Factory\Layout; + +use Civi\RemoteTools\Form\FormSpec\FormElementInterface; +use Civi\RemoteTools\Form\FormSpec\FormTab; +use Civi\RemoteTools\JsonForms\FormSpec\ElementUiSchemaFactoryInterface; +use Civi\RemoteTools\JsonForms\FormSpec\Factory\AbstractConcreteElementUiSchemaFactory; +use Civi\RemoteTools\JsonForms\JsonFormsElement; +use Civi\RemoteTools\JsonForms\Layout\JsonFormsCategory; +use Webmozart\Assert\Assert; + +final class CategoryFactory extends AbstractConcreteElementUiSchemaFactory { + + public function createSchema( + FormElementInterface $element, + ElementUiSchemaFactoryInterface $factory + ): JsonFormsElement { + Assert::isInstanceOf($element, FormTab::class); + /** @var \Civi\RemoteTools\Form\FormSpec\FormTab $element */ + $elements = array_map([$factory, 'createSchema'], $element->getElements()); + + return new JsonFormsCategory($element->getTitle(), $elements, $element->getDescription()); + } + + public function supportsElement(FormElementInterface $element): bool { + return $element instanceof FormTab; + } + +}