From 70326e6d7b2e5261cc01237ba25e91d0afb8b050 Mon Sep 17 00:00:00 2001 From: Daniel Lienert Date: Tue, 3 May 2022 16:48:39 +0200 Subject: [PATCH] FEATURE: Make formState initialization extendable This adds a mechanism to hook into the form state initialization and define custom initializers. Resolves: #152 --- Classes/Core/Model/FormDefinition.php | 26 ++++++++++-- Classes/Core/Runtime/FormRuntime.php | 18 +-------- .../FormState/DefaultFormStateInitializer.php | 40 +++++++++++++++++++ .../FormStateInitializerInterface.php | 23 +++++++++++ Configuration/Settings.yaml | 1 + composer.json | 2 +- 6 files changed, 89 insertions(+), 21 deletions(-) create mode 100644 Classes/FormState/DefaultFormStateInitializer.php create mode 100644 Classes/FormState/FormStateInitializerInterface.php diff --git a/Classes/Core/Model/FormDefinition.php b/Classes/Core/Model/FormDefinition.php index 9564e09..0575b6d 100644 --- a/Classes/Core/Model/FormDefinition.php +++ b/Classes/Core/Model/FormDefinition.php @@ -18,6 +18,8 @@ use Neos\Form\Exception; use Neos\Form\Exception\IdentifierNotValidException; use Neos\Form\Exception\TypeDefinitionNotFoundException; +use Neos\Form\FormState\DefaultFormStateInitializer; +use Neos\Form\FormState\FormStateInitializerInterface; use Neos\Form\Utility\Arrays as FormArrays; use Neos\Form\Utility\SupertypeResolver; use Neos\Utility\Arrays; @@ -318,6 +320,8 @@ class FormDefinition extends Renderable\AbstractCompositeRenderable */ protected $finisherPresets; + protected FormStateInitializerInterface $formStateInitializer; + /** * Constructor. Creates a new FormDefinition with the given identifier. * @@ -329,13 +333,20 @@ class FormDefinition extends Renderable\AbstractCompositeRenderable */ public function __construct($identifier, $formDefaults = [], $type = 'Neos.Form:Form') { - $this->formFieldTypeManager = new SupertypeResolver(isset($formDefaults['formElementTypes']) ? $formDefaults['formElementTypes'] : []); - $this->validatorPresets = isset($formDefaults['validatorPresets']) ? $formDefaults['validatorPresets'] : []; - $this->finisherPresets = isset($formDefaults['finisherPresets']) ? $formDefaults['finisherPresets'] : []; + $this->formFieldTypeManager = new SupertypeResolver($formDefaults['formElementTypes'] ?? []); + $this->validatorPresets = $formDefaults['validatorPresets'] ?? []; + $this->finisherPresets = $formDefaults['finisherPresets'] ?? []; if (!is_string($identifier) || strlen($identifier) === 0) { throw new IdentifierNotValidException('The given identifier was not a string or the string was empty.', 1325574803); } + + $formStateInitializer = $formDefaults['formStateInitializer'] ?? DefaultFormStateInitializer::class; + if (!is_a($formStateInitializer, FormStateInitializerInterface::class, true)) { + throw new \RuntimeException(sprintf('The given class "%s" does not implement the interface %s', $formStateInitializer, FormStateInitializerInterface::class), 1648204540); + } + $this->formStateInitializer = new $formStateInitializer(); + $this->identifier = $identifier; $this->type = $type; @@ -703,4 +714,13 @@ public function getValidatorPresets() { return $this->validatorPresets; } + + /** + * @internal + * @return FormStateInitializerInterface + */ + public function getFormStateInitializer(): FormStateInitializerInterface + { + return $this->formStateInitializer; + } } diff --git a/Classes/Core/Runtime/FormRuntime.php b/Classes/Core/Runtime/FormRuntime.php index 543e706..c0ba106 100644 --- a/Classes/Core/Runtime/FormRuntime.php +++ b/Classes/Core/Runtime/FormRuntime.php @@ -162,7 +162,7 @@ public function __construct(FormDefinition $formDefinition, ActionRequest $reque */ public function initializeObject() { - $this->initializeFormStateFromRequest(); + $this->formState = $this->formDefinition->getFormStateInitializer()->initializeFormState($this->formDefinition, $this->request); $this->initializeCurrentPageFromRequest(); if (!$this->isFirstRequest()) { @@ -170,22 +170,6 @@ public function initializeObject() } } - /** - * @return void - * @internal - */ - protected function initializeFormStateFromRequest() - { - $serializedFormStateWithHmac = $this->request->getInternalArgument('__state'); - if ($serializedFormStateWithHmac === null) { - $this->formState = new FormState(); - } else { - $serializedFormState = $this->hashService->validateAndStripHmac($serializedFormStateWithHmac); - /** @noinspection UnserializeExploitsInspection The unserialize call is safe because of the HMAC check above */ - $this->formState = unserialize(base64_decode($serializedFormState)); - } - } - /** * @return void * @internal diff --git a/Classes/FormState/DefaultFormStateInitializer.php b/Classes/FormState/DefaultFormStateInitializer.php new file mode 100644 index 0000000..13d1921 --- /dev/null +++ b/Classes/FormState/DefaultFormStateInitializer.php @@ -0,0 +1,40 @@ +getInternalArgument('__state'); + if ($serializedFormStateWithHmac !== null) { + $serializedFormState = $this->hashService->validateAndStripHmac($serializedFormStateWithHmac); + /** @noinspection UnserializeExploitsInspection The unserialize call is safe because of the HMAC check above */ + return unserialize(base64_decode($serializedFormState)); + } + + return new FormState(); + } +} diff --git a/Classes/FormState/FormStateInitializerInterface.php b/Classes/FormState/FormStateInitializerInterface.php new file mode 100644 index 0000000..8a108a1 --- /dev/null +++ b/Classes/FormState/FormStateInitializerInterface.php @@ -0,0 +1,23 @@ +=7.1.0", + "php": ">=7.4.0", "neos/flow": ">=6.0 || dev-master" }, "replace": {