From 6b0bb323b6d816c329a97ac3ba9cae4e548931ff Mon Sep 17 00:00:00 2001
From: Oliver Hader <oliver@typo3.org>
Date: Sat, 12 Nov 2022 17:01:56 +0100
Subject: [PATCH] [TASK] Streamline
 TYPO3\CMS\Core\Utility\ArrayUtility::filterRecursive
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* actually use `array_filter` internally
* allow using `array_filter` modes `ARRAY_FILTER_USE_KEY`
  and `ARRAY_FILTER_USE_BOTH`

Resolves: #99071
Releases: main, 11.5
Change-Id: I1b95ae0a7551250125a9eeabbd0ee7e66e25a6d9
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/76571
Tested-by: core-ci <typo3@b13.com>
Tested-by: Georg Ringer <georg.ringer@gmail.com>
Reviewed-by: Georg Ringer <georg.ringer@gmail.com>
Tested-by: Nikita Hovratov <nikita.h@live.de>
Reviewed-by: Nikita Hovratov <nikita.h@live.de>
Tested-by: Stefan Bürk <stefan@buerk.tech>
Reviewed-by: Stefan Bürk <stefan@buerk.tech>
---
 .../core/Classes/Utility/ArrayUtility.php     | 21 +++++++++-------
 .../Tests/Unit/Utility/ArrayUtilityTest.php   | 25 ++++++++++++++-----
 2 files changed, 31 insertions(+), 15 deletions(-)

diff --git a/typo3/sysext/core/Classes/Utility/ArrayUtility.php b/typo3/sysext/core/Classes/Utility/ArrayUtility.php
index ca99a894a6ed..590329341cd9 100644
--- a/typo3/sysext/core/Classes/Utility/ArrayUtility.php
+++ b/typo3/sysext/core/Classes/Utility/ArrayUtility.php
@@ -931,23 +931,26 @@ class ArrayUtility
     /**
      * Recursively filter an array
      *
-     * @see https://secure.php.net/manual/en/function.array-filter.php
+     * Example:
+     * filterRecursive(
+     *   ['a' => ['b' =>  null]],
+     *   static fn ($item) => $item !== null,
+     *   ARRAY_FILTER_USE_BOTH
+     * )
+     *
+     * @param 0|ARRAY_FILTER_USE_KEY|ARRAY_FILTER_USE_BOTH $mode
+     * @see https://www.php.net/manual/en/function.array-filter.php
      */
-    public static function filterRecursive(array $array, callable $callback = null): array
+    public static function filterRecursive(array $array, callable $callback = null, int $mode = 0): array
     {
         $callback ??= static fn ($value) => (bool)$value;
 
         foreach ($array as $key => $value) {
             if (is_array($value)) {
-                $array[$key] = self::filterRecursive($value, $callback);
-            }
-
-            if (!$callback($value)) {
-                unset($array[$key]);
+                $array[$key] = self::filterRecursive($value, $callback, $mode);
             }
         }
-
-        return $array;
+        return array_filter($array, $callback, $mode);
     }
 
     /**
diff --git a/typo3/sysext/core/Tests/Unit/Utility/ArrayUtilityTest.php b/typo3/sysext/core/Tests/Unit/Utility/ArrayUtilityTest.php
index 2111a1bc62a4..c17ee8a41827 100644
--- a/typo3/sysext/core/Tests/Unit/Utility/ArrayUtilityTest.php
+++ b/typo3/sysext/core/Tests/Unit/Utility/ArrayUtilityTest.php
@@ -3449,7 +3449,6 @@ class ArrayUtilityTest extends UnitTestCase
                         'baz' => [
                             'foo' => [
                                 'bamboo' => 5,
-                                'fooAndBoo' => [],
                             ],
                         ],
                     ],
@@ -3600,20 +3599,34 @@ class ArrayUtilityTest extends UnitTestCase
                 $expectedResult,
                 [new ArrayUtilityFilterRecursiveCallbackFixture(), 'callbackViaInstanceMethod'],
             ],
+            'only keep2 key is kept' => [
+                $input,
+                ['keep2' => 'keep'],
+                static fn ($key): bool => $key === 'keep2',
+                ARRAY_FILTER_USE_KEY,
+            ],
+            'keys baz, keep1 and empty arrays are removed' => [
+                $input,
+                ['foo' => 'remove', 'keep2' => 'keep'],
+                static fn ($value, $key): bool => $value !== [] && !in_array($key, ['baz', 'keep1'], true),
+                ARRAY_FILTER_USE_BOTH,
+            ],
         ];
     }
 
     /**
      * @test
      * @dataProvider filterRecursiveSupportsCallableCallbackDataProvider
-     * @param array    $input
-     * @param array    $expectedResult
-     * @param callable $callback
      * @see https://forge.typo3.org/issues/84485
+     *
+     * @param array $input
+     * @param array $expectedResult
+     * @param callable $callback
+     * @param 0|ARRAY_FILTER_USE_KEY|ARRAY_FILTER_USE_BOTH $mode
      */
-    public function filterRecursiveSupportsCallableCallback(array $input, array $expectedResult, callable $callback): void
+    public function filterRecursiveSupportsCallableCallback(array $input, array $expectedResult, callable $callback, int $mode = 0): void
     {
-        $result = ArrayUtility::filterRecursive($input, $callback);
+        $result = ArrayUtility::filterRecursive($input, $callback, $mode);
         self::assertEquals($expectedResult, $result);
     }
 
-- 
GitLab