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
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
Comment #3
herved commentedComment #4
smustgrave commentedCan we actually write out the steps please for a real world example
Comment #5
herved commentedComment #6
smustgrave commentedOut of curiosity (haven't checked) but does #2171395: OptionsWidgetBase should use WidgetInterface::massageFormValues() resolve it?
Comment #7
smustgrave commentedNot sure about this, doesn't seem like something someone can trigger via the UI? So seems to be developer error bug?
Comment #8
herved commentedThe 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.
Comment #9
smustgrave commentedWill see what committers think for this one.
Comment #10
alexpottI'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.Comment #11
alexpottCommitted and pushed 95b76594e9a to main and 1306415abb0 to 11.x and a09a2deee85 to 11.4.x. Thanks!