From c1b817259b48e6213f4a09e44efd6109065a282e Mon Sep 17 00:00:00 2001
From: Simon Praetorius <simon@praetorius.me>
Date: Fri, 14 Jun 2024 18:19:10 +0200
Subject: [PATCH] [FEATURE] ViewHelper to check feature flags

This patch adds a new condition-based Fluid ViewHelper which allows
integrators to check for feature flags from within Fluid templates.

Resolves: #104020
Releases: main
Change-Id: I76d19f4ec4888268b51fb9358812a870d79db41c
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/84719
Tested-by: Georg Ringer <georg.ringer@gmail.com>
Reviewed-by: Georg Ringer <georg.ringer@gmail.com>
Reviewed-by: Garvin Hicking <gh@faktor-e.de>
Reviewed-by: Torben Hansen <derhansen@gmail.com>
Tested-by: Torben Hansen <derhansen@gmail.com>
Tested-by: core-ci <typo3@b13.com>
Tested-by: Garvin Hicking <gh@faktor-e.de>
---
 ...e-104020-ViewHelperToCheckFeatureFlags.rst | 50 ++++++++++++++
 .../Classes/ViewHelpers/FeatureViewHelper.php | 66 +++++++++++++++++++
 .../ViewHelpers/FeatureViewHelperTest.php     | 49 ++++++++++++++
 3 files changed, 165 insertions(+)
 create mode 100644 typo3/sysext/core/Documentation/Changelog/13.2/Feature-104020-ViewHelperToCheckFeatureFlags.rst
 create mode 100644 typo3/sysext/fluid/Classes/ViewHelpers/FeatureViewHelper.php
 create mode 100644 typo3/sysext/fluid/Tests/Functional/ViewHelpers/FeatureViewHelperTest.php

diff --git a/typo3/sysext/core/Documentation/Changelog/13.2/Feature-104020-ViewHelperToCheckFeatureFlags.rst b/typo3/sysext/core/Documentation/Changelog/13.2/Feature-104020-ViewHelperToCheckFeatureFlags.rst
new file mode 100644
index 000000000000..e1ebe7a8e208
--- /dev/null
+++ b/typo3/sysext/core/Documentation/Changelog/13.2/Feature-104020-ViewHelperToCheckFeatureFlags.rst
@@ -0,0 +1,50 @@
+.. include:: /Includes.rst.txt
+
+.. _feature-104020-1718381897:
+
+====================================================
+Feature: #104020 - ViewHelper to check feature flags
+====================================================
+
+See :issue:`104020`
+
+Description
+===========
+
+The `<f:feature>` ViewHelper allows integrators to check for feature flags from within Fluid
+templates. The ViewHelper follows the same rules as the underlying TYPO3 api, which means
+that undefined flags will be treated as `false`.
+
+Examples
+========
+
+Basic usage
+-----------
+
+::
+
+   <f:feature name="myFeatureFlag">
+      This is being shown if the flag is enabled
+   </f:feature>
+
+feature / then / else
+---------------------
+
+::
+
+   <f:feature name="myFeatureFlag">
+      <f:then>
+         Flag is enabled
+      </f:then>
+      <f:else>
+         Flag is undefined or not enabled
+      </f:else>
+   </f:feature>
+
+
+Impact
+======
+
+Feature flags can now be checked from within Fluid templates.
+
+.. index:: Fluid, ext:fluid
diff --git a/typo3/sysext/fluid/Classes/ViewHelpers/FeatureViewHelper.php b/typo3/sysext/fluid/Classes/ViewHelpers/FeatureViewHelper.php
new file mode 100644
index 000000000000..2f9a24e20334
--- /dev/null
+++ b/typo3/sysext/fluid/Classes/ViewHelpers/FeatureViewHelper.php
@@ -0,0 +1,66 @@
+<?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\ViewHelpers;
+
+use TYPO3\CMS\Core\Configuration\Features;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
+use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractConditionViewHelper;
+
+/**
+ * This ViewHelper checks if a feature flag is enabled
+ *
+ * Examples
+ * ========
+ *
+ * Basic usage
+ * -----------
+ *
+ * ::
+ *
+ *    <f:feature name="myFeatureFlag">
+ *       This is being shown if the flag is enabled
+ *    </f:feature>
+ *
+ * feature / then / else
+ * ---------------------
+ *
+ * ::
+ *
+ *    <f:feature name="myFeatureFlag">
+ *       <f:then>
+ *          Flag is enabled
+ *       </f:then>
+ *       <f:else>
+ *          Flag is undefined or not enabled
+ *       </f:else>
+ *    </f:feature>
+ */
+final class FeatureViewHelper extends AbstractConditionViewHelper
+{
+    public function initializeArguments(): void
+    {
+        parent::initializeArguments();
+        $this->registerArgument('name', 'string', 'name of the feature flag that should be checked', true);
+    }
+
+    public static function verdict(array $arguments, RenderingContextInterface $renderingContext): bool
+    {
+        return GeneralUtility::makeInstance(Features::class)->isFeatureEnabled($arguments['name']);
+    }
+}
diff --git a/typo3/sysext/fluid/Tests/Functional/ViewHelpers/FeatureViewHelperTest.php b/typo3/sysext/fluid/Tests/Functional/ViewHelpers/FeatureViewHelperTest.php
new file mode 100644
index 000000000000..3c31d292fea5
--- /dev/null
+++ b/typo3/sysext/fluid/Tests/Functional/ViewHelpers/FeatureViewHelperTest.php
@@ -0,0 +1,49 @@
+<?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\ViewHelpers;
+
+use PHPUnit\Framework\Attributes\DataProvider;
+use PHPUnit\Framework\Attributes\Test;
+use TYPO3\CMS\Fluid\Core\Rendering\RenderingContextFactory;
+use TYPO3\CMS\Fluid\View\TemplateView;
+use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;
+
+final class FeatureViewHelperTest extends FunctionalTestCase
+{
+    public static function renderDataProvider(): array
+    {
+        return [
+            'featureEnabled' => [true, 'enabled'],
+            'featureDisabled' => [false, 'disabled'],
+            'featureUndefined' => [null, 'disabled'],
+        ];
+    }
+
+    #[DataProvider('renderDataProvider')]
+    #[Test]
+    public function render(?bool $featureStatus, string $expected): void
+    {
+        $GLOBALS['TYPO3_CONF_VARS']['SYS']['features']['viewHelperTestFeature'] = $featureStatus;
+
+        $context = $this->get(RenderingContextFactory::class)->create();
+        $context->getTemplatePaths()->setTemplateSource(
+            '<f:feature name="viewHelperTestFeature"><f:then>enabled</f:then><f:else>disabled</f:else></f:feature>'
+        );
+        self::assertSame($expected, (new TemplateView($context))->render());
+    }
+}
-- 
GitLab