Problem/Motivation

Originates from #3576485-7: PHP8.5 deprecation when using empty list items

All list_* widgets in core (OptionsSelectWidget, OptionsButtonsWidget) declare multiple_values: TRUE.
But if we try to define a widget without it, as done in the scheduler_content_moderation_integration contrib module, we get the following deprecation:

Using null as an array offset is deprecated, use an empty string instead in /var/www/html/web/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/OptionsWidgetBase.php on line 190

In such case, WidgetBase::form() routes through formMultipleElements() instead of formSingleElement(). For a field with no stored value, formMultipleElements() calls $items->appendItem() to fill the first delta slot, producing an item with value = null. OptionsWidgetBase::getSelectedOptions() then iterates all items and evaluates isset($flat_options[null]);

Steps to reproduce

- Run Drupal (main branch) with PHP 8.5
- Define a FieldWidget plugin extending OptionsWidgetBase without declaring multiple_values: TRUE in the plugin attribute (see test in MR for example)
- Attach that widget to a list_* field on a content type
- Go to the node create form - /node/add/[content_type] > We see the PHP 8.5 deprecation warning

Proposed resolution

Guard OptionsWidgetBase::getSelectedOptions with a null check:

// line 190
- if (isset($flat_options[$value])) {
+ if ($value !== NULL && isset($flat_options[$value])) {

Remaining tasks

?

User interface changes

None

Introduced terminology

None

API changes

None

Data model changes

None

Release notes snippet

None

Issue fork drupal-3593223

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

herved created an issue. See original summary.

herved’s picture

Status: Active » Needs review
smustgrave’s picture

Status: Needs review » Needs work

Can we actually write out the steps please for a real world example

herved’s picture

Issue summary: View changes
Status: Needs work » Needs review
smustgrave’s picture

Out of curiosity (haven't checked) but does #2171395: OptionsWidgetBase should use WidgetInterface::massageFormValues() resolve it?

smustgrave’s picture

Not sure about this, doesn't seem like something someone can trigger via the UI? So seems to be developer error bug?

herved’s picture

Issue summary: View changes

The error can be seen in the test-only changes, see https://git.drupalcode.org/issue/drupal-3593223/-/jobs/10066292
Sorry I should have been more specific, it's not really when a node is being saved, but when accessing the node create/edit form (I updated IS) so #2171395: OptionsWidgetBase should use WidgetInterface::massageFormValues() is most probably unrelated.

smustgrave’s picture

Status: Needs review » Reviewed & tested by the community

Will see what committers think for this one.

alexpott’s picture

I've consider whether we should be using if (!$item->isEmpty()) { as it feels more semantically correct. But the $value = $item->{$this->column}; way of getting the value gives me pause because $this->column might not be about the main property on the field.

alexpott’s picture

Version: main » 11.4.x-dev
Status: Reviewed & tested by the community » Fixed

Committed and pushed 95b76594e9a to main and 1306415abb0 to 11.x and a09a2deee85 to 11.4.x. Thanks!

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

  • alexpott committed 7df1a889 on main
    fix: #3593223 [PHP 8.5] OptionsWidgetBase::getSelectedOptions tries to...

  • alexpott committed 50fc31d1 on 11.4.x
    fix: #3593223 [PHP 8.5] OptionsWidgetBase::getSelectedOptions tries to...

  • alexpott committed 946a8d1a on 11.x
    fix: #3593223 [PHP 8.5] OptionsWidgetBase::getSelectedOptions tries to...

Status: Fixed » Closed (fixed)

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