From f6927ef20aa21dc0b9921429692c4510b32cf7c9 Mon Sep 17 00:00:00 2001
From: Simon Praetorius <simon@praetorius.me>
Date: Tue, 2 May 2023 11:15:06 +0200
Subject: [PATCH] [BUGFIX] Allow ViewHelpers from libraries
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

With TYPO3 11 it was possible to use ViewHelpers from composer libraries
that aren't TYPO3 extensions and thus don't use Symfony dependency
injection. With the removal of objectManager, this doesn't work anymore
in TYPO3 12 because the dependency injection can only instantiate
ViewHelper classes that are defined as public services explicitly.

This change reintroduces that functionality by falling back to "new" if
the class exists but isn't registered as a service. Fluid standalone
uses the same method to instantiate a ViewHelper.

Resolves: #100785
Releases: main, 12.4
Change-Id: I495e006fa15eb815fb3734b4c73361821869f4ad
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/78917
Tested-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Tested-by: Stefan Bürk <stefan@buerk.tech>
Reviewed-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Reviewed-by: Stefan Bürk <stefan@buerk.tech>
Tested-by: core-ci <typo3@b13.com>
---
 composer.json                                 |  3 +-
 .../Core/ViewHelper/ViewHelperResolver.php    |  9 +-
 .../sysext/fluid/Configuration/Services.yaml  | 83 -------------------
 .../viewhelper_library/composer.json          | 11 +++
 .../src/ViewHelpers/TestViewHelper.php        | 35 ++++++++
 .../Functional/ViewhelperLibraryTest.php      | 42 ++++++++++
 6 files changed, 97 insertions(+), 86 deletions(-)
 create mode 100644 typo3/sysext/fluid/Tests/Functional/Fixtures/Libraries/viewhelper_library/composer.json
 create mode 100644 typo3/sysext/fluid/Tests/Functional/Fixtures/Libraries/viewhelper_library/src/ViewHelpers/TestViewHelper.php
 create mode 100644 typo3/sysext/fluid/Tests/Functional/ViewhelperLibraryTest.php

diff --git a/composer.json b/composer.json
index 9cc671cb75ea..4661a03b0a12 100644
--- a/composer.json
+++ b/composer.json
@@ -315,7 +315,8 @@
 			"TYPO3Tests\\TestMeta\\": "typo3/sysext/core/Tests/Functional/Fixtures/Extensions/test_meta/Classes/",
 			"TYPO3Tests\\TestTyposcriptAstFunctionEvent\\": "typo3/sysext/core/Tests/Functional/Fixtures/Extensions/test_typoscript_ast_function_event/Classes/",
 			"TYPO3Tests\\TestTyposcriptPagetsconfigfactory\\": "typo3/sysext/core/Tests/Functional/Fixtures/Extensions/test_typoscript_pagetsconfigfactory/Classes/",
-			"TYPO3Tests\\TypeConverterTest\\": "typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/type_converter_test/Classes/"
+			"TYPO3Tests\\TypeConverterTest\\": "typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/type_converter_test/Classes/",
+			"TYPO3Tests\\ViewhelperLibrary\\": "typo3/sysext/fluid/Tests/Functional/Fixtures/Libraries/viewhelper_library/src/"
 		}
 	}
 }
diff --git a/typo3/sysext/fluid/Classes/Core/ViewHelper/ViewHelperResolver.php b/typo3/sysext/fluid/Classes/Core/ViewHelper/ViewHelperResolver.php
index f8b8a3109563..02e89d08c373 100644
--- a/typo3/sysext/fluid/Classes/Core/ViewHelper/ViewHelperResolver.php
+++ b/typo3/sysext/fluid/Classes/Core/ViewHelper/ViewHelperResolver.php
@@ -95,8 +95,13 @@ class ViewHelperResolver extends \TYPO3Fluid\Fluid\Core\ViewHelper\ViewHelperRes
             return $viewHelperInstance;
         }
 
-        /** @var ViewHelperInterface $viewHelperInstance */
-        $viewHelperInstance = $this->container->get($viewHelperClassName);
+        if ($this->container->has($viewHelperClassName)) {
+            /** @var ViewHelperInterface $viewHelperInstance */
+            $viewHelperInstance = $this->container->get($viewHelperClassName);
+        } else {
+            /** @var ViewHelperInterface $viewHelperInstance */
+            $viewHelperInstance = new $viewHelperClassName();
+        }
         return $viewHelperInstance;
     }
 
diff --git a/typo3/sysext/fluid/Configuration/Services.yaml b/typo3/sysext/fluid/Configuration/Services.yaml
index 4d6a5f44b9c4..aed2f9271518 100644
--- a/typo3/sysext/fluid/Configuration/Services.yaml
+++ b/typo3/sysext/fluid/Configuration/Services.yaml
@@ -39,86 +39,3 @@ services:
   TYPO3Fluid\Fluid\Core\Parser\TemplateProcessor\NamespaceDetectionTemplateProcessor:
     public: true
     shared: false
-
-  # VH's of base package
-  TYPO3Fluid\Fluid\ViewHelpers\Cache\DisableViewHelper:
-    tags: [ 'fluid.viewhelper' ]
-    autowire: false
-  TYPO3Fluid\Fluid\ViewHelpers\Cache\StaticViewHelper:
-    tags: [ 'fluid.viewhelper' ]
-    autowire: false
-  TYPO3Fluid\Fluid\ViewHelpers\Cache\WarmupViewHelper:
-    tags: [ 'fluid.viewhelper' ]
-    autowire: false
-  TYPO3Fluid\Fluid\ViewHelpers\Format\CdataViewHelper:
-    tags: [ 'fluid.viewhelper' ]
-    autowire: false
-  TYPO3Fluid\Fluid\ViewHelpers\Format\HtmlspecialcharsViewHelper:
-    tags: [ 'fluid.viewhelper' ]
-    autowire: false
-  TYPO3Fluid\Fluid\ViewHelpers\Format\PrintfViewHelper:
-    tags: [ 'fluid.viewhelper' ]
-    autowire: false
-  TYPO3Fluid\Fluid\ViewHelpers\Format\RawViewHelper:
-    tags: [ 'fluid.viewhelper' ]
-    autowire: false
-  TYPO3Fluid\Fluid\ViewHelpers\AliasViewHelper:
-    tags: [ 'fluid.viewhelper' ]
-    autowire: false
-  TYPO3Fluid\Fluid\ViewHelpers\CaseViewHelper:
-    tags: [ 'fluid.viewhelper' ]
-    autowire: false
-  TYPO3Fluid\Fluid\ViewHelpers\CommentViewHelper:
-    tags: [ 'fluid.viewhelper' ]
-    autowire: false
-  TYPO3Fluid\Fluid\ViewHelpers\CountViewHelper:
-    tags: [ 'fluid.viewhelper' ]
-    autowire: false
-  TYPO3Fluid\Fluid\ViewHelpers\CycleViewHelper:
-    tags: [ 'fluid.viewhelper' ]
-    autowire: false
-  TYPO3Fluid\Fluid\ViewHelpers\DebugViewHelper:
-    tags: [ 'fluid.viewhelper' ]
-    autowire: false
-  TYPO3Fluid\Fluid\ViewHelpers\DefaultCaseViewHelper:
-    tags: [ 'fluid.viewhelper' ]
-    autowire: false
-  TYPO3Fluid\Fluid\ViewHelpers\ElseViewHelper:
-    tags: [ 'fluid.viewhelper' ]
-    autowire: false
-  TYPO3Fluid\Fluid\ViewHelpers\ForViewHelper:
-    tags: [ 'fluid.viewhelper' ]
-    autowire: false
-  TYPO3Fluid\Fluid\ViewHelpers\GroupedForViewHelper:
-    tags: [ 'fluid.viewhelper' ]
-    autowire: false
-  TYPO3Fluid\Fluid\ViewHelpers\IfViewHelper:
-    tags: [ 'fluid.viewhelper' ]
-    autowire: false
-  TYPO3Fluid\Fluid\ViewHelpers\InlineViewHelper:
-    tags: [ 'fluid.viewhelper' ]
-    autowire: false
-  TYPO3Fluid\Fluid\ViewHelpers\LayoutViewHelper:
-    tags: [ 'fluid.viewhelper' ]
-    autowire: false
-  TYPO3Fluid\Fluid\ViewHelpers\OrViewHelper:
-    tags: [ 'fluid.viewhelper' ]
-    autowire: false
-  TYPO3Fluid\Fluid\ViewHelpers\RenderViewHelper:
-    tags: [ 'fluid.viewhelper' ]
-    autowire: false
-  TYPO3Fluid\Fluid\ViewHelpers\SectionViewHelper:
-    tags: [ 'fluid.viewhelper' ]
-    autowire: false
-  TYPO3Fluid\Fluid\ViewHelpers\SpacelessViewHelper:
-    tags: [ 'fluid.viewhelper' ]
-    autowire: false
-  TYPO3Fluid\Fluid\ViewHelpers\SwitchViewHelper:
-    tags: [ 'fluid.viewhelper' ]
-    autowire: false
-  TYPO3Fluid\Fluid\ViewHelpers\ThenViewHelper:
-    tags: [ 'fluid.viewhelper' ]
-    autowire: false
-  TYPO3Fluid\Fluid\ViewHelpers\VariableViewHelper:
-    tags: [ 'fluid.viewhelper' ]
-    autowire: false
diff --git a/typo3/sysext/fluid/Tests/Functional/Fixtures/Libraries/viewhelper_library/composer.json b/typo3/sysext/fluid/Tests/Functional/Fixtures/Libraries/viewhelper_library/composer.json
new file mode 100644
index 000000000000..af75e71bf365
--- /dev/null
+++ b/typo3/sysext/fluid/Tests/Functional/Fixtures/Libraries/viewhelper_library/composer.json
@@ -0,0 +1,11 @@
+{
+	"name": "typo3tests/viewhelper-library",
+	"description": "Standalone library to test viewhelpers without dependency injection",
+	"license": "GPL-2.0-or-later",
+	"type": "library",
+	"autoload": {
+		"psr-4": {
+			"TYPO3Tests\\ViewhelperLibrary\\": "src/"
+		}
+	}
+}
diff --git a/typo3/sysext/fluid/Tests/Functional/Fixtures/Libraries/viewhelper_library/src/ViewHelpers/TestViewHelper.php b/typo3/sysext/fluid/Tests/Functional/Fixtures/Libraries/viewhelper_library/src/ViewHelpers/TestViewHelper.php
new file mode 100644
index 000000000000..206b8637f973
--- /dev/null
+++ b/typo3/sysext/fluid/Tests/Functional/Fixtures/Libraries/viewhelper_library/src/ViewHelpers/TestViewHelper.php
@@ -0,0 +1,35 @@
+<?php
+
+declare(strict_types=1);
+
+/*
+ * 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!
+ */
+
+namespace TYPO3Tests\ViewhelperLibrary\ViewHelpers;
+
+use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
+use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
+use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
+
+final class TestViewHelper extends AbstractViewHelper
+{
+    use CompileWithRenderStatic;
+
+    public static function renderStatic(
+        array $arguments,
+        \Closure $renderChildrenClosure,
+        RenderingContextInterface $renderingContext
+    ) {
+        return 'test viewhelper working';
+    }
+}
diff --git a/typo3/sysext/fluid/Tests/Functional/ViewhelperLibraryTest.php b/typo3/sysext/fluid/Tests/Functional/ViewhelperLibraryTest.php
new file mode 100644
index 000000000000..1409f3e2db7d
--- /dev/null
+++ b/typo3/sysext/fluid/Tests/Functional/ViewhelperLibraryTest.php
@@ -0,0 +1,42 @@
+<?php
+
+declare(strict_types=1);
+
+/*
+ * 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!
+ */
+
+namespace TYPO3\CMS\Fluid\Tests\Functional;
+
+use TYPO3\CMS\Fluid\View\TemplateView;
+use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;
+
+final class ViewhelperLibraryTest extends FunctionalTestCase
+{
+    protected bool $initializeDatabase = false;
+
+    /**
+     * This test case covers the usage of standalone PHP libraries that provide
+     * Fluid ViewHelper classes. These libraries usually don't use TYPO3's
+     * dependency injection container and thus need to be supported separately
+     * in TYPO3's ViewHelperResolver implementation.
+     *
+     * @test
+     */
+    public function viewhelperLibraryCanBeLoadedTest(): void
+    {
+        $view = new TemplateView();
+        $view->getRenderingContext()->getViewHelperResolver()->addNamespace('fl', 'TYPO3Tests\\ViewhelperLibrary\\ViewHelpers');
+        $view->getRenderingContext()->getTemplatePaths()->setTemplateSource('<fl:test />');
+        self::assertSame('test viewhelper working', $view->render());
+    }
+}
-- 
GitLab