TypeError: count(): Argument #1 ($value) must be of type Countable|array, null given in count()

Created on 11 March 2024, 9 months ago
Updated 5 April 2024, 8 months ago

Problem/Motivation

An AJAX error (500) occurs when the validation for an SHS element is triggered with no selection ('_none') made. This behavior occurs exclusively on PHP version 8.0 or later. In earlier versions, it would have resulted in a PHP warning.
Stack trace:

TypeError: count(): Argument #1 ($value) must be of type Countable|array, null given in count() (line 348 of /var/www/html/web/modules/contrib/shs/src/Plugin/Field/FieldWidget/OptionsShsWidget.php).
#0 /var/www/html/web/modules/contrib/shs/src/Plugin/Field/FieldWidget/OptionsShsWidget.php(348): count(NULL)
#1 [internal function]: Drupal\shs\Plugin\Field\FieldWidget\OptionsShsWidget::validateElement(Array, Object(Drupal\Core\Form\FormState), Array)
#2 /var/www/html/web/core/lib/Drupal/Core/Form/FormValidator.php(282): call_user_func_array(Array, Array)
#3 /var/www/html/web/core/lib/Drupal/Core/Form/FormValidator.php(238): Drupal\Core\Form\FormValidator->doValidateForm(Array, Object(Drupal\Core\Form\FormState))
#4 /var/www/html/web/core/lib/Drupal/Core/Form/FormValidator.php(238): Drupal\Core\Form\FormValidator->doValidateForm(Array, Object(Drupal\Core\Form\FormState))
#5 /var/www/html/web/core/lib/Drupal/Core/Form/FormValidator.php(118): Drupal\Core\Form\FormValidator->doValidateForm(Array, Object(Drupal\Core\Form\FormState), 'node_article_fo...')
#6 /var/www/html/web/core/lib/Drupal/Core/Form/FormBuilder.php(593): Drupal\Core\Form\FormValidator->validateForm('node_article_fo...', Array, Object(Drupal\Core\Form\FormState))
#7 /var/www/html/web/core/lib/Drupal/Core/Form/FormBuilder.php(325): Drupal\Core\Form\FormBuilder->processForm('node_article_fo...', Array, Object(Drupal\Core\Form\FormState))
#8 /var/www/html/web/core/lib/Drupal/Core/Controller/FormController.php(73): Drupal\Core\Form\FormBuilder->buildForm(Object(Drupal\node\NodeForm), Object(Drupal\Core\Form\FormState))
#9 [internal function]: Drupal\Core\Controller\FormController->getContentResult(Object(Symfony\Component\HttpFoundation\Request), Object(Drupal\Core\Routing\RouteMatch))
#10 /var/www/html/web/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(123): call_user_func_array(Array, Array)
#11 /var/www/html/web/core/lib/Drupal/Core/Render/Renderer.php(627): Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}()
#12 /var/www/html/web/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(124): Drupal\Core\Render\Renderer->executeInRenderContext(Object(Drupal\Core\Render\RenderContext), Object(Closure))
#13 /var/www/html/web/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(97): Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array)
#14 /var/www/html/vendor/symfony/http-kernel/HttpKernel.php(181): Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}()
#15 /var/www/html/vendor/symfony/http-kernel/HttpKernel.php(76): Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object(Symfony\Component\HttpFoundation\Request), 1)
#16 /var/www/html/web/core/lib/Drupal/Core/StackMiddleware/Session.php(58): Symfony\Component\HttpKernel\HttpKernel->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#17 /var/www/html/web/core/lib/Drupal/Core/StackMiddleware/KernelPreHandle.php(48): Drupal\Core\StackMiddleware\Session->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#18 /var/www/html/web/core/lib/Drupal/Core/StackMiddleware/ContentLength.php(28): Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#19 /var/www/html/web/core/modules/big_pipe/src/StackMiddleware/ContentLength.php(32): Drupal\Core\StackMiddleware\ContentLength->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#20 /var/www/html/web/core/modules/page_cache/src/StackMiddleware/PageCache.php(106): Drupal\big_pipe\StackMiddleware\ContentLength->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#21 /var/www/html/web/core/modules/page_cache/src/StackMiddleware/PageCache.php(85): Drupal\page_cache\StackMiddleware\PageCache->pass(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#22 /var/www/html/web/core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php(48): Drupal\page_cache\StackMiddleware\PageCache->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#23 /var/www/html/web/core/lib/Drupal/Core/StackMiddleware/NegotiationMiddleware.php(51): Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#24 /var/www/html/web/core/lib/Drupal/Core/StackMiddleware/AjaxPageState.php(36): Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#25 /var/www/html/web/core/lib/Drupal/Core/StackMiddleware/StackedHttpKernel.php(51): Drupal\Core\StackMiddleware\AjaxPageState->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#26 /var/www/html/web/core/lib/Drupal/Core/DrupalKernel.php(704): Drupal\Core\StackMiddleware\StackedHttpKernel->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#27 /var/www/html/web/index.php(19): Drupal\Core\DrupalKernel->handle(Object(Symfony\Component\HttpFoundation\Request))
#28 {main}

Steps to reproduce

  1. Add an entity reference field to the Article node type and choose Taxonomy Term as the entity. You need to set this field as required.
  2. Make sure you have a taxonomy term that has multiple levels
  3. Configure this field to use SHS as its widget
  4. Add another entity reference field to your node, this time select node as the entity and allow for multiple values
  5. Go to 'Add Content' and select Article as the content type
  6. Enter a title, and under your node reference, click on 'Add another item', this should trigger the validate for the shs field, and you should get an AJAX error in your dev console (it doesn't show up on the page). You'll also see it in the recent logs.

Proposed resolution

🐛 Bug report
Status

Fixed

Version

2.0

Component

Code

Created by

Live updates comments and jobs are added and updated live.
  • PHP 8.0

    The issue particularly affects sites running on PHP version 8.0.0 or later.

Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @ramil g
  • 🇨🇦Canada joelpittet Vancouver

    Wrapping the issue summary in code tags

  • Assigned to abhishek_virasat
  • Issue was unassigned.
  • Status changed to Needs review 9 months ago
  • 🇮🇳India abhishek_virasat

    @ramil g, i have fixed the issue and created patch

  • 🇮🇳India Vivek Panicker Kolkata

    First of all, we get $value == _none only when we intially had given a value for the field and saved the content and later selected None from the options.
    So I think that point needs to be mentioned in the description.
    The first time we save the content without selecting any value in the term reference field, we get "" in $value.

    2nd point is regarding this code:

    1.    if ($element['#shs']['settings']['anyValue'] === reset($value)) {
    2.     if (!$element['#required']) {
    3.        return;
    4.      }
    5.      elseif (count($element['#options']) > 1) {
    6.        $form_state->setError($element, t('You need to select a term from the deepest level in field @name.', ['@name' => $element['#title']]));
    7.        return;
    8.      }
    9.    }
    

    Even when there is _none in $value, still the code seems to return from line 2, since the element is not required.

    So I don't get the part where the error is occurring for you.

  • @Vivek, thanks for adding your comment. Sorry, yes the shs field does need to be required, I forgot to mention this above - I have updated the description. And yes there is this weird thing that happens where if you don't touch the dropdown and just have nothing selected, in the code the value shows up as an empty string, but if you just select something else, then change it back to the default, this changes the value to '_none' in the code. We noticed that if you are using Select2, this doesn't happen, the original value is set to '_none', and not ''.
    This is why in my patch, in line 345, I had to add a condition to check if the value is empty to account for this: https://git.drupalcode.org/issue/shs-3427207/-/commit/3e4adfff57cb65db45...

    @abhishek - thanks for adding a patch but I actually did upload a patch yesterday but I used the new way of doing it, which is using git to commit to add the patch instead of uploading a patch file. You should see it above where it says "Issue fork shs-3427207"

  • 🇨🇦Canada joelpittet Vancouver

    @abhishek_gupta1 Thanks for the patch but ramil g had code already in there just missing the MR which he just created. The patch may have some gems but the coding standard whitespace makes it harder to see the fix. You could comment on the MR or change it if there are reasonable fixes to MR27 that would be helpful. I will hide your patch so it's less confusing.

  • 🇮🇳India Vivek Panicker Kolkata

    @ramil g, actually what I am trying to say is that I am not able to reproduce the issue on a fresh Drupal installation with only this contrib module installed.
    So can I request you to try to reproduce the issue on a fresh installation and then note down the exact steps followed to reproduce the issue?

  • Status changed to Fixed 8 months ago
  • 🇨🇦Canada joseph.olstad

    The merge request fell behind and for some reason gitlab refuses to merge in that case.
    Grabbed the patch from the MR and pushed it in, creditted everyone above.

  • Automatically closed - issue fixed for 2 weeks with no activity.

Production build 0.71.5 2024