From 203b0dae801a0006ebd873bf4db18bb20c3fbcb7 Mon Sep 17 00:00:00 2001
From: Hannes Bochmann <hannes.bochmann@dmk-ebusiness.com>
Date: Wed, 5 Jun 2024 13:31:19 +0200
Subject: [PATCH] [FEATURE] Merge form finishers in variants

Resolves: #93962
---
 Classes/Domain/Finishers/AbstractFinisher.php |  5 ++++
 .../Domain/Finishers/FinisherInterface.php    |  3 +++
 Classes/Domain/Model/FormDefinition.php       | 27 ++++++++++++++++---
 .../Model/Renderable/RenderableVariant.php    |  2 +-
 4 files changed, 32 insertions(+), 5 deletions(-)

diff --git a/Classes/Domain/Finishers/AbstractFinisher.php b/Classes/Domain/Finishers/AbstractFinisher.php
index dd6a5309..30dc8c88 100644
--- a/Classes/Domain/Finishers/AbstractFinisher.php
+++ b/Classes/Domain/Finishers/AbstractFinisher.php
@@ -93,6 +93,11 @@ abstract class AbstractFinisher implements FinisherInterface
         $this->options = $options;
     }
 
+    public function getOptions(): array
+    {
+        return $this->options;
+    }
+
     /**
      * Sets a single finisher option (@see setOptions())
      *
diff --git a/Classes/Domain/Finishers/FinisherInterface.php b/Classes/Domain/Finishers/FinisherInterface.php
index 8a2bd90f..c2641a40 100644
--- a/Classes/Domain/Finishers/FinisherInterface.php
+++ b/Classes/Domain/Finishers/FinisherInterface.php
@@ -38,12 +38,15 @@ interface FinisherInterface
     public function execute(FinisherContext $finisherContext);
 
     public function setFinisherIdentifier(string $finisherIdentifier): void;
+    public function getFinisherIdentifier(): string;
 
     /**
      * @param array $options configuration options in the format ['option1' => 'value1', 'option2' => 'value2', ...]
      */
     public function setOptions(array $options);
 
+    public function getOptions(): array;
+
     /**
      * Sets a single finisher option (@see setOptions())
      *
diff --git a/Classes/Domain/Model/FormDefinition.php b/Classes/Domain/Model/FormDefinition.php
index d8cf7ce8..f6d1373b 100644
--- a/Classes/Domain/Model/FormDefinition.php
+++ b/Classes/Domain/Model/FormDefinition.php
@@ -357,9 +357,8 @@ class FormDefinition extends AbstractCompositeRenderable implements VariableRend
         if (isset($options['finishers'])) {
             if ($resetFinishers) {
                 $this->finishers = [];
-            }
-            foreach ($options['finishers'] as $finisherConfiguration) {
-                $this->createFinisher($finisherConfiguration['identifier'], $finisherConfiguration['options'] ?? []);
+            } elseif (is_array($options['finishers'])) {
+                $this->mergeOrCreateFinishers($options['finishers']);
             }
         }
 
@@ -485,7 +484,27 @@ class FormDefinition extends AbstractCompositeRenderable implements VariableRend
      */
     public function addFinisher(FinisherInterface $finisher)
     {
-        $this->finishers[] = $finisher;
+        $this->finishers[$finisher->getFinisherIdentifier()] = $finisher;
+    }
+
+    /**
+     * Merge given finishers with existing finisher options or create new finishers.
+     *
+     * @param list<array{identifier?: string, options?: array<string, mixed>}> $finishers
+     * @internal
+     */
+    protected function mergeOrCreateFinishers(array $finishers): void
+    {
+        foreach ($finishers as $finisherConfiguration) {
+            $finisher = $this->finishers[$finisherConfiguration['identifier']] ?? null;
+            if ($finisher !== null) {
+                $finisherOptions = $finisher->getOptions();
+                ArrayUtility::mergeRecursiveWithOverrule($finisherOptions, $finisherConfiguration['options'] ?? []);
+                $finisher->setOptions($finisherOptions);
+            } else {
+                $this->createFinisher($finisherConfiguration['identifier'], $finisherConfiguration['options'] ?? []);
+            }
+        }
     }
 
     /**
diff --git a/Classes/Domain/Model/Renderable/RenderableVariant.php b/Classes/Domain/Model/Renderable/RenderableVariant.php
index b7a7f738..3e21a963 100644
--- a/Classes/Domain/Model/Renderable/RenderableVariant.php
+++ b/Classes/Domain/Model/Renderable/RenderableVariant.php
@@ -81,7 +81,7 @@ class RenderableVariant implements RenderableVariantInterface
      */
     public function apply(): void
     {
-        $this->renderable->setOptions($this->options, true);
+        $this->renderable->setOptions($this->options);
         $this->applied = true;
     }
 
-- 
2.39.2

