Problem/Motivation
On the response time sensor edit form (/admin/config/system/monitoring/sensors/response_time), changing the Threshold type dropdown — or any other Ajax-triggering select on the form (Sensor Plugin, Value type) — fails silently: the thresholds section is not refreshed with the new warning/critical fields, and subsequent form interactions are broken.
Under the hood it is a PHP 8 TypeError:
TypeError: implode(): Argument #2 ($array) must be of type ?array, string given in ResponseTimeSensorPlugin.php:79
…raised during the Ajax rebuild of the sensor form.
Steps to reproduce
- Edit the
response_timesensor. - Type any path into the Paths to exclude textarea (for example
/admin/foo/*). - Change the Threshold type dropdown (for example Exceeds → Falls).
- Observe that the threshold fields do not refresh. The watchdog shows the TypeError.
Same failure path on the Sensor Plugin and Value type Ajax dropdowns when the sensor has text in the excluded-paths field.
Root cause
This was introduced in #3562444. ResponseTimeSensorPlugin::buildConfigurationForm() assumes excluded_paths is always an array:
'#default_value' => ($this->sensorConfig->getSetting('excluded_paths'))
? implode(PHP_EOL, $this->sensorConfig->getSetting('excluded_paths'))
: '',
On a form rebuild the entity form's copyFormValuesToEntity() has already written the raw textarea string onto $entity->settings['excluded_paths']. The plugin's own submitConfigurationForm() splits that string into an array, but submit handlers don't run on rebuilds. So the next build sees a string, PHP 8's strict-typed implode() raises, the Ajax callback dies, and the thresholds wrapper is never replaced.
Proposed resolution
Split the textarea into an array during form validation via #element_validate, so the value stored in form state is an array by the time copyFormValuesToEntity() writes it back to the entity. This keeps the stored type invariant across rebuilds and lets the custom submitConfigurationForm() splitting be removed entirely.
$excluded = $this->sensorConfig->getSetting('excluded_paths') ?: [];
$form['excluded_paths'] = [
'#type' => 'textarea',
'#title' => $this->t('Paths to exclude'),
'#default_value' => is_array($excluded) ? implode(PHP_EOL, $excluded) : (string) $excluded,
'#description' => $this->t('Supports wildcards. One path per line. Include starting slash. I.e. /foo/bar'),
'#element_validate' => [[static::class, 'splitExcludedPaths']],
];
public static function splitExcludedPaths(array &$element, FormStateInterface $form_state): void {
$paths = array_values(array_filter(
array_map('trim', preg_split('/\R+/', (string) $element['#value'])),
'strlen'
));
$form_state->setValueForElement($element, $paths);
}
The is_array(...) fallback on the default value handles one-time migration of configs mis-saved as strings by the current buggy code path.
Remaining tasks
- Apply the
#element_validatefix. - Remove the now-redundant
submitConfigurationForm()splitting.
User interface changes
None, other than Ajax interactions on the sensor form actually working.
API changes
None. excluded_paths remains a sequence of strings in config schema.
Data model changes
None.
Issue fork monitoring-3586658
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
mably commentedComment #5
berdirMerged.