From 851bac6ed764b4e49ef2bfadcadd5a355de0ecad Mon Sep 17 00:00:00 2001
From: Andreas Fernandez <a.fernandez@scripting-base.de>
Date: Mon, 25 Sep 2017 10:40:38 +0200
Subject: [PATCH] [BUGFIX] Fix handling of ClosureFinisher

Check if the incoming optionValue is a closure and return early in such
case.

Resolves: #82550
Releases: master, 8.7
Change-Id: I0f6b12b8ed777906bfe7bc6849841b246e95bbd3
Reviewed-on: https://review.typo3.org/54213
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Ralf Zimmermann <ralf.zimmermann@tritum.de>
Reviewed-by: Bjoern Jacob <bjoern.jacob@tritum.de>
Reviewed-by: Joerg Boesche <typo3@joergboesche.de>
Reviewed-by: Wouter Wolters <typo3@wouterwolters.nl>
Tested-by: Bjoern Jacob <bjoern.jacob@tritum.de>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
Reviewed-by: Andreas Fernandez <typo3@scripting-base.de>
Tested-by: Andreas Fernandez <typo3@scripting-base.de>
---
 .../Domain/Finishers/AbstractFinisher.php     |  4 ++
 .../Domain/Finishers/ClosureFinisherTest.php  | 58 +++++++++++++++++++
 2 files changed, 62 insertions(+)
 create mode 100644 typo3/sysext/form/Tests/Unit/Domain/Finishers/ClosureFinisherTest.php

diff --git a/typo3/sysext/form/Classes/Domain/Finishers/AbstractFinisher.php b/typo3/sysext/form/Classes/Domain/Finishers/AbstractFinisher.php
index 38b957c1aec8..5c011fd2dddd 100644
--- a/typo3/sysext/form/Classes/Domain/Finishers/AbstractFinisher.php
+++ b/typo3/sysext/form/Classes/Domain/Finishers/AbstractFinisher.php
@@ -174,6 +174,10 @@ abstract class AbstractFinisher implements FinisherInterface
             return $optionValue;
         }
 
+        if ($optionValue instanceof \Closure) {
+            return $optionValue;
+        }
+
         $formRuntime = $this->finisherContext->getFormRuntime();
 
         // You can encapsulate a option value with {}.
diff --git a/typo3/sysext/form/Tests/Unit/Domain/Finishers/ClosureFinisherTest.php b/typo3/sysext/form/Tests/Unit/Domain/Finishers/ClosureFinisherTest.php
new file mode 100644
index 000000000000..336a1f080bdb
--- /dev/null
+++ b/typo3/sysext/form/Tests/Unit/Domain/Finishers/ClosureFinisherTest.php
@@ -0,0 +1,58 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Tests\Unit\Domain\Finishers;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use Prophecy\Argument;
+use Prophecy\Prophecy\ObjectProphecy;
+use TYPO3\CMS\Form\Domain\Finishers\ClosureFinisher;
+use TYPO3\CMS\Form\Domain\Finishers\FinisherContext;
+use TYPO3\CMS\Form\Domain\Runtime\FormRuntime;
+
+/**
+ * Test case
+ */
+class ClosureFinisherTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
+{
+
+    /**
+     * @test
+     */
+    public function closureOptionForFinisherCanBeSetAndIsFunctional()
+    {
+        $closure = function (FinisherContext $finisherContext) {
+            return 'foobar';
+        };
+
+        /** @var ClosureFinisher|\PHPUnit_Framework_MockObject_MockObject|\TYPO3\TestingFramework\Core\AccessibleObjectInterface $mockClosureFinisher */
+        $mockClosureFinisher = $this->getAccessibleMock(ClosureFinisher::class, ['dummy'], [], '', false);
+
+        $mockClosureFinisher->_set('options', [
+            'closure' => $closure
+        ]);
+
+        $finisherContextProphecy = $this->prophesize(FinisherContext::class);
+        $formRuntimeProphecy = $this->prophesize(FormRuntime::class);
+        $finisherContextProphecy->getFormRuntime(Argument::cetera())->willReturn($formRuntimeProphecy->reveal());
+
+        /** @var FinisherContext|ObjectProphecy $revealedFinisherContext */
+        $revealedFinisherContext = $finisherContextProphecy->reveal();
+
+        $mockClosureFinisher->_set('finisherContext', $revealedFinisherContext);
+        $closure = $mockClosureFinisher->_call('parseOption', 'closure');
+
+        $this->assertSame('foobar', $closure($revealedFinisherContext));
+    }
+}
-- 
GitLab