From 86c1956772ea7d6811807fcaca6d5bb2da1e5557 Mon Sep 17 00:00:00 2001
From: Daniel Siepmann <daniel.siepmann@typo3.org>
Date: Mon, 27 Jan 2020 12:24:02 +0100
Subject: [PATCH] [FEATURE] Support bit-wise and in TypoScript checkIf

Allows direct checks whether an expected bit is part of a bit set, e.g.
in a stored checkbox or radio of a record.

Resolves: #90213
Releases: master
Change-Id: I2ff188c74b207376f5f44307f0a8a2e9514ea6d8
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/63046
Tested-by: Georg Ringer <georg.ringer@gmail.com>
Tested-by: TYPO3com <noreply@typo3.com>
Tested-by: Stefan Froemken <froemken@gmail.com>
Tested-by: Benni Mack <benni@typo3.org>
Reviewed-by: Georg Ringer <georg.ringer@gmail.com>
Reviewed-by: Stefan Froemken <froemken@gmail.com>
Reviewed-by: Benni Mack <benni@typo3.org>
---
 ...213-SupportBitAndInTypoScriptStdWrapIf.rst | 38 +++++++++++++++++++
 .../ContentObject/ContentObjectRenderer.php   |  7 ++++
 .../ContentObjectRendererTest.php             | 34 +++++++++++++++++
 3 files changed, 79 insertions(+)
 create mode 100644 typo3/sysext/core/Documentation/Changelog/master/Feature-90213-SupportBitAndInTypoScriptStdWrapIf.rst

diff --git a/typo3/sysext/core/Documentation/Changelog/master/Feature-90213-SupportBitAndInTypoScriptStdWrapIf.rst b/typo3/sysext/core/Documentation/Changelog/master/Feature-90213-SupportBitAndInTypoScriptStdWrapIf.rst
new file mode 100644
index 000000000000..24a857ec0564
--- /dev/null
+++ b/typo3/sysext/core/Documentation/Changelog/master/Feature-90213-SupportBitAndInTypoScriptStdWrapIf.rst
@@ -0,0 +1,38 @@
+.. include:: ../../Includes.txt
+
+==========================================================
+Feature: #90213 - Support bit and in TypoScript stdWrap_if
+==========================================================
+
+See :issue:`90213`
+
+Description
+===========
+
+It is now possible to use :ts:`bitAnd` within TypoScript :ts:`if`.
+
+TYPO3 uses bits to store radio and checkboxes via TCA.
+Without this feature one would need to check whether any possible bit value is in a
+list. With this feature a simple comparison whether the expected value is part of the
+bit set is possible.
+
+Example
+=======
+
+An example usage could look like this:
+
+.. code-block:: ts
+
+   hideDefaultLanguageOfPage = TEXT
+   hideDefaultLanguageOfPage {
+       value = 0
+       value {
+           override = 1
+           override.if {
+               bitAnd.field = l18n_cfg
+               value = 1
+           }
+       }
+   }
+
+.. index:: ext:frontend, TypoScript, NotScanned
diff --git a/typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php b/typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php
index 81f52ad35629..d9b9e645790e 100644
--- a/typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php
+++ b/typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php
@@ -52,6 +52,7 @@ use TYPO3\CMS\Core\Service\FlexFormService;
 use TYPO3\CMS\Core\Service\MarkerBasedTemplateService;
 use TYPO3\CMS\Core\Site\SiteFinder;
 use TYPO3\CMS\Core\TimeTracker\TimeTracker;
+use TYPO3\CMS\Core\Type\BitSet;
 use TYPO3\CMS\Core\TypoScript\Parser\TypoScriptParser;
 use TYPO3\CMS\Core\TypoScript\TypoScriptService;
 use TYPO3\CMS\Core\Utility\ArrayUtility;
@@ -3076,6 +3077,12 @@ class ContentObjectRenderer implements LoggerAwareInterface
                     $flag = false;
                 }
             }
+            if (isset($conf['bitAnd']) || isset($conf['bitAnd.'])) {
+                $number = isset($conf['bitAnd.']) ? trim($this->stdWrap($conf['bitAnd'], $conf['bitAnd.'])) : trim($conf['bitAnd']);
+                if ((new BitSet($number))->get($value) === false) {
+                    $flag = false;
+                }
+            }
         }
         if ($conf['negate'] ?? false) {
             $flag = !$flag;
diff --git a/typo3/sysext/frontend/Tests/Unit/ContentObject/ContentObjectRendererTest.php b/typo3/sysext/frontend/Tests/Unit/ContentObject/ContentObjectRendererTest.php
index 323324df4ac5..9ec5e0714771 100644
--- a/typo3/sysext/frontend/Tests/Unit/ContentObject/ContentObjectRendererTest.php
+++ b/typo3/sysext/frontend/Tests/Unit/ContentObject/ContentObjectRendererTest.php
@@ -5898,6 +5898,40 @@ class ContentObjectRendererTest extends UnitTestCase
         self::assertSame($stop, $subject->_get('stopRendering')[1]);
     }
 
+    /**
+     * Data provider for checkIf.
+     *
+     * @return array [$expect, $conf]
+     */
+    public function checkIfDataProvider(): array
+    {
+        return [
+            'true bitAnd the same' => [true, ['bitAnd' => '4', 'value' => '4']],
+            'true bitAnd included' => [true, ['bitAnd' => '6', 'value' => '4']],
+            'false bitAnd' => [false, ['bitAnd' => '4', 'value' => '3']],
+            'negate true bitAnd the same' => [false, ['bitAnd' => '4', 'value' => '4', 'negate' => '1']],
+            'negate true bitAnd included' => [false, ['bitAnd' => '6', 'value' => '4', 'negate' => '1']],
+            'negate false bitAnd' => [true, ['bitAnd' => '3', 'value' => '4', 'negate' => '1']],
+        ];
+    }
+
+    /**
+     * Check if checkIf works properly.
+     *
+     * @test
+     * @dataProvider checkIfDataProvider
+     * @param bool $expect Whether result should be true or false.
+     * @param array $conf TypoScript configuration to pass into checkIf
+     */
+    public function checkIf(bool $expect, array $conf)
+    {
+        $subject = $this->getAccessibleMock(
+            ContentObjectRenderer::class,
+            ['stdWrap']
+        );
+        self::assertSame($expect, $subject->checkIf($conf));
+    }
+
     /**
      * Data provider for stdWrap_ifBlank.
      *
-- 
GitLab