diff --git a/typo3/sysext/core/Classes/Configuration/ConfigurationManager.php b/typo3/sysext/core/Classes/Configuration/ConfigurationManager.php index 05e60cd2d74b7391d2eb1a72dc3e897d457969c8..d3ce2786c824e63db8c2e71cae69136af029df0d 100644 --- a/typo3/sysext/core/Classes/Configuration/ConfigurationManager.php +++ b/typo3/sysext/core/Classes/Configuration/ConfigurationManager.php @@ -286,6 +286,30 @@ class ConfigurationManager return $result; } + /** + * Enables a certain feature and writes the option to LocalConfiguration.php + * Short-hand method + * + * @param string $featureName something like "InlineSvgImages" + * @return bool true on successful writing the setting + */ + public function enableFeature(string $featureName): bool + { + return $this->setLocalConfigurationValueByPath('SYS/features/' . $featureName, true); + } + + /** + * Disables a feature and writes the option to LocalConfiguration.php + * Short-hand method + * + * @param string $featureName something like "InlineSvgImages" + * @return bool true on successful writing the setting + */ + public function disableFeature(string $featureName): bool + { + return $this->setLocalConfigurationValueByPath('SYS/features/' . $featureName, false); + } + /** * Checks if the configuration can be written. * diff --git a/typo3/sysext/core/Classes/Configuration/Features.php b/typo3/sysext/core/Classes/Configuration/Features.php new file mode 100644 index 0000000000000000000000000000000000000000..1cc4004018360f3a49fe6f888f440ca690ceaf34 --- /dev/null +++ b/typo3/sysext/core/Classes/Configuration/Features.php @@ -0,0 +1,65 @@ +<?php +declare(strict_types=1); +namespace TYPO3\CMS\Core\Configuration; + +/* + * 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! + */ + +/** + * A lightweight API class to check if a feature is enabled. + * + * Features are simple options (true/false), and are stored in the + * global configuration array $TYPO3_CONF_VARS[SYS][features]. + * + * For disabling or enabling a feature the "ConfigurationManager" + * should be used. + * + * -- Naming -- + * + * Feature names should NEVER named "enable" or having a negation, or containing versions or years + * "enableFeatureXyz" + * "disableOverlays" + * "schedulerRevamped" + * "useDoctrineQueries" + * "disablePreparedStatements" + * "disableHooksInFE" + * + * Proper namings for features + * "ExtendedRichtextFormat" + * "NativeYamlParser" + * "InlinePageTranslations" + * "TypoScriptParserIncludesAsXml" + * "NativeDoctrineQueries" + * + * Ideally, these feature switches are added via the Install Tool or via FactoryConfiguration + * and can be used for Extensions as well. + * + * --- Usage --- + * + * if (GeneralUtility::makeInstance(Features::class)->isFeatureEnabled('InlineSvg')) { + * ... do stuff here ... + * } + */ +class Features +{ + /** + * Checks if a feature is active + * + * @param string $featureName the name of the feature + * @return bool + */ + public function isFeatureEnabled(string $featureName): bool + { + return isset($GLOBALS['TYPO3_CONF_VARS']['SYS']['features'][$featureName]) && $GLOBALS['TYPO3_CONF_VARS']['SYS']['features'][$featureName] === true; + } +} diff --git a/typo3/sysext/core/Configuration/DefaultConfiguration.php b/typo3/sysext/core/Configuration/DefaultConfiguration.php index 8a5cc4279d03ec2db01c87cf297b77928afcaf45..6edf83a26d23fb16b9acd70ae0fb0456b8ac6ba7 100644 --- a/typo3/sysext/core/Configuration/DefaultConfiguration.php +++ b/typo3/sysext/core/Configuration/DefaultConfiguration.php @@ -67,6 +67,7 @@ return [ ], 'fileCreateMask' => '0664', 'folderCreateMask' => '2775', + 'features' => [], 'createGroup' => '', 'sitename' => 'TYPO3', 'encryptionKey' => '', diff --git a/typo3/sysext/core/Documentation/Changelog/master/Feature-83429-FeatureToggles.rst b/typo3/sysext/core/Documentation/Changelog/master/Feature-83429-FeatureToggles.rst new file mode 100644 index 0000000000000000000000000000000000000000..952ed62ca7263ac3443e43823fdc4ec2a95867d4 --- /dev/null +++ b/typo3/sysext/core/Documentation/Changelog/master/Feature-83429-FeatureToggles.rst @@ -0,0 +1,40 @@ +.. include:: ../../Includes.txt + +================================= +Feature: #83429 - Feature Toggles +================================= + +See :issue:`83429` + +Description +=========== + +In order to allow better support for alternative functionality while keeping old functionality, a new API +for enabling installation-wide features - called "Feature Toggle" - has been added. + +The new API checks against a system-wide option array within :php:`$TYPO3_CONF_VARS['SYS']['features']` which can be +enabled system-wide. Both TYPO3 Core and Extensions can then provide alternative functionality for a certain +feature. + +Features are usually breaking changes for a minor version / sprint release, which site administrators can enable +at their own risk, or stay fully compatible with third-party extensions. + +Examples for having features are: +* Throw exceptions on certain occasions instead of just returning a string message as error message. +* Disable obsolete functionality which might still be used, but slows down the system. +* Enable alternative PageNotFound handling for an installation. + + +Impact +====== + +Features are documented for TYPO3 Core. For extension authors, the API can be used for any custom +feature provided by an extension: + +.. code-block:: php + + if (GeneralUtility::makeInstance(Features::class)->isFeatureEnabled('myFeatureName')) { + // do custom processing + } + +.. index:: LocalConfiguration, PHP-API diff --git a/typo3/sysext/core/Tests/Unit/Configuration/FeaturesTest.php b/typo3/sysext/core/Tests/Unit/Configuration/FeaturesTest.php new file mode 100644 index 0000000000000000000000000000000000000000..8f093aac07bdd83c457f4b6052cd89a4754f9b75 --- /dev/null +++ b/typo3/sysext/core/Tests/Unit/Configuration/FeaturesTest.php @@ -0,0 +1,64 @@ +<?php +declare(strict_types=1); +namespace TYPO3\CMS\Core\Tests\Unit\Configuration; + +/* + * 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 TYPO3\CMS\Core\Configuration\Features; +use TYPO3\TestingFramework\Core\Unit\UnitTestCase; + +/** + * Test case + */ +class FeaturesTest extends UnitTestCase +{ + /** + * @test + */ + public function nonExistingFeatureReturnsFalse() + { + $features = new Features(); + $this->assertFalse($features->isFeatureEnabled('nonExistingFeature')); + } + + /** + * @test + */ + public function checkIfExistingDisabledFeatureIsDisabled() + { + $GLOBALS['TYPO3_CONF_VARS']['SYS']['features']['nativeFunctionality'] = false; + $features = new Features(); + $this->assertFalse($features->isFeatureEnabled('nativeFunctionality')); + } + + /** + * @test + */ + public function checkIfExistingEnabledFeatureIsEnabled() + { + $GLOBALS['TYPO3_CONF_VARS']['SYS']['features']['nativeFunctionality'] = true; + $features = new Features(); + $this->assertTrue($features->isFeatureEnabled('nativeFunctionality')); + } + + /** + * @test + */ + public function checkIfExistingEnabledFeatureIsDisabled() + { + $GLOBALS['TYPO3_CONF_VARS']['SYS']['features']['nativeFunctionality'] = false; + $features = new Features(); + $this->assertFalse($features->isFeatureEnabled('nativeFunctionality')); + } +}