[BUGFIX] Fix handling of ClosureFinisher
[Packages/TYPO3.CMS.git] / typo3 / sysext / form / Classes / Domain / Finishers / AbstractFinisher.php
index b60ec5e..5c011fd 100644 (file)
@@ -42,6 +42,11 @@ abstract class AbstractFinisher implements FinisherInterface
     protected $finisherIdentifier = '';
 
     /**
+     * @var string
+     */
+    protected $shortFinisherIdentifier = '';
+
+    /**
      * The options which have been set from the outside. Instead of directly
      * accessing them, you should rather use parseOption().
      *
@@ -73,8 +78,21 @@ abstract class AbstractFinisher implements FinisherInterface
     }
 
     /**
+     * @param string $finisherIdentifier The identifier for this finisher
+     */
+    public function __construct(string $finisherIdentifier = '')
+    {
+        if (empty($finisherIdentifier)) {
+            $this->finisherIdentifier = (new \ReflectionClass($this))->getShortName();
+        } else {
+            $this->finisherIdentifier = $finisherIdentifier;
+        }
+
+        $this->shortFinisherIdentifier = preg_replace('/Finisher$/', '', $this->finisherIdentifier);
+    }
+
+    /**
      * @param array $options configuration options in the format ['option1' => 'value1', 'option2' => 'value2', ...]
-     * @return void
      * @api
      */
     public function setOptions(array $options)
@@ -87,7 +105,6 @@ abstract class AbstractFinisher implements FinisherInterface
      *
      * @param string $optionName name of the option to be set
      * @param mixed $optionValue value of the option
-     * @return void
      * @api
      */
     public function setOption(string $optionName, $optionValue)
@@ -99,12 +116,10 @@ abstract class AbstractFinisher implements FinisherInterface
      * Executes the finisher
      *
      * @param FinisherContext $finisherContext The Finisher context that contains the current Form Runtime and Response
-     * @return void
      * @api
      */
     final public function execute(FinisherContext $finisherContext)
     {
-        $this->finisherIdentifier = (new \ReflectionClass($this))->getShortName();
         $this->finisherContext = $finisherContext;
         $this->executeInternal();
     }
@@ -114,7 +129,6 @@ abstract class AbstractFinisher implements FinisherInterface
      *
      * Override and fill with your own implementation!
      *
-     * @return void
      * @api
      */
     abstract protected function executeInternal();
@@ -160,34 +174,54 @@ abstract class AbstractFinisher implements FinisherInterface
             return $optionValue;
         }
 
+        if ($optionValue instanceof \Closure) {
+            return $optionValue;
+        }
+
         $formRuntime = $this->finisherContext->getFormRuntime();
 
         // You can encapsulate a option value with {}.
         // This enables you to access every getable property from the
-        // TYPO3\CMS\Form\Domain\Runtime.
+        // TYPO3\CMS\Form\Domain\Runtime\FormRuntime.
         //
         // For example: {formState.formValues.<elemenIdentifier>}
         // or {<elemenIdentifier>}
         //
         // Both examples are equal to "$formRuntime->getFormState()->getFormValues()[<elemenIdentifier>]"
         // If the value is not a string nothing will be replaced.
+        // There is a special option value '{__currentTimestamp}'.
+        // This will be replaced with the current timestamp.
         $optionValue = preg_replace_callback('/{([^}]+)}/', function ($match) use ($formRuntime) {
-            $value = ObjectAccess::getPropertyPath($formRuntime, $match[1]);
-            if (!is_string($value)) {
+            if ($match[1] === '__currentTimestamp') {
+                $value = time();
+            } else {
+                // try to resolve the path '{...}' within the FormRuntime
+                $value = ObjectAccess::getPropertyPath($formRuntime, $match[1]);
+                if ($value === null) {
+                    // try to resolve the path '{...}' within the FinisherVariableProvider
+                    $value = ObjectAccess::getPropertyPath(
+                        $this->finisherContext->getFinisherVariableProvider(),
+                        $match[1]
+                    );
+                }
+            }
+            if (!is_string($value) && !is_int($value)) {
                 $value = '{' . $match[1] . '}';
             }
             return $value;
         }, $optionValue);
 
-        if (isset($this->options['translation']['translationFile'])) {
-            $optionValue = TranslationService::getInstance()->translateFinisherOption(
-                $formRuntime,
-                $this->finisherIdentifier,
-                $optionName,
-                $optionValue,
-                $this->options['translation']
-            );
-        }
+        $renderingOptions = is_array($this->options['translation'])
+                            ? $this->options['translation']
+                            : [];
+
+        $optionValue = TranslationService::getInstance()->translateFinisherOption(
+            $formRuntime,
+            $this->finisherIdentifier,
+            $optionName,
+            $optionValue,
+            $renderingOptions
+        );
 
         if (empty($optionValue)) {
             if ($defaultValue !== null) {