From c506000f20658e3c11695c69d3a0d0b6d0fd309b Mon Sep 17 00:00:00 2001
From: Alex Pott <alex.a.pott@googlemail.com>
Date: Thu, 29 Feb 2024 02:03:50 +0000
Subject: [PATCH] Issue #3422543 by mstrelan, smustgrave, longwave: Make use of
 is_iterable and is_countable functions

---
 .../Drupal/Component/Assertion/Inspector.php  | 22 ++++++++++++-------
 core/lib/Drupal/Core/Form/FormValidator.php   |  3 +--
 .../Value/CacheableNormalization.php          |  2 +-
 .../src/Plugin/migrate/process/SubProcess.php |  2 +-
 .../Component/Assertion/InspectorTest.php     |  6 +++++
 5 files changed, 23 insertions(+), 12 deletions(-)

diff --git a/core/lib/Drupal/Component/Assertion/Inspector.php b/core/lib/Drupal/Component/Assertion/Inspector.php
index 4a8057a8e8d1..dfac2e56ab76 100644
--- a/core/lib/Drupal/Component/Assertion/Inspector.php
+++ b/core/lib/Drupal/Component/Assertion/Inspector.php
@@ -26,9 +26,15 @@ class Inspector {
    *
    * @return bool
    *   TRUE if $traversable can be traversed with foreach.
+   *
+   * @deprecated in drupal:10.3.0 and is removed from drupal:11.0.0. Use
+   *   is_iterable() instead.
+   *
+   * @see https://www.drupal.org/node/3422775
    */
   public static function assertTraversable($traversable) {
-    return is_array($traversable) || $traversable instanceof \Traversable;
+    @trigger_error(__METHOD__ . '() is deprecated in drupal:10.3.0 and is removed from drupal:11.0.0. Use is_iterable() instead. See https://www.drupal.org/node/3422775', E_USER_DEPRECATED);
+    return is_iterable($traversable);
   }
 
   /**
@@ -51,7 +57,7 @@ public static function assertTraversable($traversable) {
    * @see http://php.net/manual/language.types.callable.php
    */
   public static function assertAll(callable $callable, $traversable) {
-    if (static::assertTraversable($traversable)) {
+    if (is_iterable($traversable)) {
       foreach ($traversable as $member) {
         if (!$callable($member)) {
           return FALSE;
@@ -89,7 +95,7 @@ public static function assertAllStrings($traversable) {
    *   objects with __toString().
    */
   public static function assertAllStringable($traversable) {
-    if (static::assertTraversable($traversable)) {
+    if (is_iterable($traversable)) {
       foreach ($traversable as $member) {
         if (!static::assertStringable($member)) {
           return FALSE;
@@ -207,7 +213,7 @@ public static function assertAllHaveKey($traversable) {
     $args = func_get_args();
     unset($args[0]);
 
-    if (static::assertTraversable($traversable)) {
+    if (is_iterable($traversable)) {
       foreach ($traversable as $member) {
         foreach ($args as $key) {
           if (!array_key_exists($key, $member)) {
@@ -270,7 +276,7 @@ public static function assertAllCallable($traversable) {
    *   TRUE if $traversable can be traversed and all members not empty.
    */
   public static function assertAllNotEmpty($traversable) {
-    if (static::assertTraversable($traversable)) {
+    if (is_iterable($traversable)) {
       foreach ($traversable as $member) {
         if (empty($member)) {
           return FALSE;
@@ -311,7 +317,7 @@ public static function assertAllNumeric($traversable) {
    *   containing $pattern.
    */
   public static function assertAllMatch($pattern, $traversable, $case_sensitive = FALSE) {
-    if (static::assertTraversable($traversable)) {
+    if (is_iterable($traversable)) {
       if ($case_sensitive) {
         foreach ($traversable as $member) {
           if (!(is_string($member) && strstr($member, $pattern))) {
@@ -344,7 +350,7 @@ public static function assertAllMatch($pattern, $traversable, $case_sensitive =
    *   matching $pattern.
    */
   public static function assertAllRegularExpressionMatch($pattern, $traversable) {
-    if (static::assertTraversable($traversable)) {
+    if (is_iterable($traversable)) {
       foreach ($traversable as $member) {
         if (!is_string($member)) {
           return FALSE;
@@ -394,7 +400,7 @@ public static function assertAllObjects($traversable) {
     $args = func_get_args();
     unset($args[0]);
 
-    if (static::assertTraversable($traversable)) {
+    if (is_iterable($traversable)) {
       foreach ($traversable as $member) {
         if (count($args) > 0) {
           foreach ($args as $instance) {
diff --git a/core/lib/Drupal/Core/Form/FormValidator.php b/core/lib/Drupal/Core/Form/FormValidator.php
index c28260f7915d..f8c62379ce0c 100644
--- a/core/lib/Drupal/Core/Form/FormValidator.php
+++ b/core/lib/Drupal/Core/Form/FormValidator.php
@@ -256,8 +256,7 @@ protected function doValidateForm(&$elements, FormStateInterface &$form_state, $
         // length if it's a string, and the item count if it's an array.
         // An unchecked checkbox has a #value of integer 0, different than
         // string '0', which could be a valid value.
-        $is_countable = is_array($elements['#value']) || $elements['#value'] instanceof \Countable;
-        $is_empty_multiple = $is_countable && count($elements['#value']) == 0;
+        $is_empty_multiple = is_countable($elements['#value']) && count($elements['#value']) == 0;
         $is_empty_string = (is_string($elements['#value']) && mb_strlen(trim($elements['#value'])) == 0);
         $is_empty_value = ($elements['#value'] === 0);
         $is_empty_null = is_null($elements['#value']);
diff --git a/core/modules/jsonapi/src/Normalizer/Value/CacheableNormalization.php b/core/modules/jsonapi/src/Normalizer/Value/CacheableNormalization.php
index 518bd71cfeb3..a1dd3667468a 100644
--- a/core/modules/jsonapi/src/Normalizer/Value/CacheableNormalization.php
+++ b/core/modules/jsonapi/src/Normalizer/Value/CacheableNormalization.php
@@ -130,7 +130,7 @@ public static function aggregate(array $cacheable_normalizations) {
    */
   protected static function hasNoNestedInstances($array) {
     foreach ($array as $value) {
-      if ((is_array($value) || $value instanceof \Traversable) && !static::hasNoNestedInstances($value) || $value instanceof static) {
+      if (is_iterable($value) && !static::hasNoNestedInstances($value) || $value instanceof static) {
         return FALSE;
       }
     }
diff --git a/core/modules/migrate/src/Plugin/migrate/process/SubProcess.php b/core/modules/migrate/src/Plugin/migrate/process/SubProcess.php
index 1f7d6b8a94ff..f9fd876f6ef1 100644
--- a/core/modules/migrate/src/Plugin/migrate/process/SubProcess.php
+++ b/core/modules/migrate/src/Plugin/migrate/process/SubProcess.php
@@ -203,7 +203,7 @@ public function transform($value, MigrateExecutableInterface $migrate_executable
       $source[$key] = $row->getSource();
     }
 
-    if (is_array($value) || $value instanceof \Traversable) {
+    if (is_iterable($value)) {
       foreach ($value as $key => $new_value) {
         if (!is_array($new_value)) {
           throw new MigrateException(sprintf("Input array should hold elements of type array, instead element was of type '%s'", gettype($new_value)));
diff --git a/core/tests/Drupal/Tests/Component/Assertion/InspectorTest.php b/core/tests/Drupal/Tests/Component/Assertion/InspectorTest.php
index eb5772781a38..ef3dff30f8be 100644
--- a/core/tests/Drupal/Tests/Component/Assertion/InspectorTest.php
+++ b/core/tests/Drupal/Tests/Component/Assertion/InspectorTest.php
@@ -6,6 +6,7 @@
 
 use PHPUnit\Framework\TestCase;
 use Drupal\Component\Assertion\Inspector;
+use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
 
 /**
  * @coversDefaultClass \Drupal\Component\Assertion\Inspector
@@ -13,12 +14,17 @@
  */
 class InspectorTest extends TestCase {
 
+  use ExpectDeprecationTrait;
+
   /**
    * Tests asserting argument is an array or traversable object.
    *
    * @covers ::assertTraversable
+   *
+   * @group legacy
    */
   public function testAssertTraversable() {
+    $this->expectDeprecation('Drupal\Component\Assertion\Inspector::assertTraversable() is deprecated in drupal:10.3.0 and is removed from drupal:11.0.0. Use is_iterable() instead. See https://www.drupal.org/node/3422775');
     $this->assertTrue(Inspector::assertTraversable([]));
     $this->assertTrue(Inspector::assertTraversable(new \ArrayObject()));
     $this->assertFalse(Inspector::assertTraversable(new \stdClass()));
-- 
GitLab