From 124d43c7079961b4f2576014b510111deb0252f8 Mon Sep 17 00:00:00 2001 From: Daniel Lienert Date: Fri, 25 Mar 2022 12:42:03 +0100 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/Runtime/FormRuntime.php | 25 ++++------ .../FormState/FormStateInitializerChain.php | 47 +++++++++++++++++++ .../FormStateInitializerInterface.php | 23 +++++++++ ...SerializedFormStateArgumentInitializer.php | 43 +++++++++++++++++ Configuration/Settings.yaml | 7 +++ 5 files changed, 128 insertions(+), 17 deletions(-) create mode 100644 Classes/FormState/FormStateInitializerChain.php create mode 100644 Classes/FormState/FormStateInitializerInterface.php create mode 100644 Classes/FormState/SerializedFormStateArgumentInitializer.php diff --git a/Classes/Core/Runtime/FormRuntime.php b/Classes/Core/Runtime/FormRuntime.php index 209d3a8..fa03824 100644 --- a/Classes/Core/Runtime/FormRuntime.php +++ b/Classes/Core/Runtime/FormRuntime.php @@ -26,6 +26,7 @@ use Neos\Form\Core\Renderer\RendererInterface; use Neos\Form\Exception\PropertyMappingException; use Neos\Form\Exception\RenderingException; +use Neos\Form\FormState\FormStateInitializerChain; use Neos\Utility\Arrays; /** @@ -99,6 +100,12 @@ class FormRuntime implements RootRenderableInterface, \ArrayAccess */ protected $formState; + /** + * @Flow\Inject + * @var FormStateInitializerChain + */ + protected $formStateInitializerChain; + /** * The current page is the page which will be displayed to the user * during rendering. @@ -162,7 +169,7 @@ public function __construct(FormDefinition $formDefinition, ActionRequest $reque */ public function initializeObject() { - $this->initializeFormStateFromRequest(); + $this->formState = $this->formStateInitializerChain->initializeFormState($this->formDefinition, $this->request); $this->initializeCurrentPageFromRequest(); if (!$this->isFirstRequest()) { @@ -170,22 +177,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/FormStateInitializerChain.php b/Classes/FormState/FormStateInitializerChain.php new file mode 100644 index 0000000..4d701e8 --- /dev/null +++ b/Classes/FormState/FormStateInitializerChain.php @@ -0,0 +1,47 @@ +formStateInitializerChain))->toArray(); + + foreach ($sortedChain as $initializer) { + $class = $initializer['class'] ?? ''; + if (!is_a($class, FormStateInitializerInterface::class)) { + throw new \RuntimeException(sprintf('The given class "%s" does not implement the interface %s', $class, FormStateInitializerInterface::class), 1648204540); + } + + $formState = (new $class())->initializeState($formDefinition, $actionRequest, $formState); + } + + return $formState; + } +} diff --git a/Classes/FormState/FormStateInitializerInterface.php b/Classes/FormState/FormStateInitializerInterface.php new file mode 100644 index 0000000..44c574c --- /dev/null +++ b/Classes/FormState/FormStateInitializerInterface.php @@ -0,0 +1,23 @@ +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 $previousFormState; + } +} diff --git a/Configuration/Settings.yaml b/Configuration/Settings.yaml index f76073d..7ff52ba 100644 --- a/Configuration/Settings.yaml +++ b/Configuration/Settings.yaml @@ -3,8 +3,10 @@ Neos: Form: yamlPersistenceManager: savePath: '%FLOW_PATH_DATA%Forms/' + supertypeResolver: hiddenProperties: { } + presets: default: title: Default @@ -200,3 +202,8 @@ Neos: implementationClassName: Neos\Flow\Validation\Validator\RegularExpressionValidator 'Neos.Flow:Count': implementationClassName: Neos\Flow\Validation\Validator\CountValidator + + formStateInitializerChain: + serializedFormStateArgument: + class: 'Neos\Form\FormState\SerializedFormStateArgumentInitializer' + position: 'start'