class OptionsWidgetBase

Same name in other branches
  1. 9 core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/OptionsWidgetBase.php \Drupal\Core\Field\Plugin\Field\FieldWidget\OptionsWidgetBase
  2. 8.9.x core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/OptionsWidgetBase.php \Drupal\Core\Field\Plugin\Field\FieldWidget\OptionsWidgetBase
  3. 11.x core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/OptionsWidgetBase.php \Drupal\Core\Field\Plugin\Field\FieldWidget\OptionsWidgetBase

Base class for the 'options_*' widgets.

Field types willing to enable one or several of the widgets defined in options.module (select, radios/checkboxes, on/off checkbox) need to implement the OptionsProviderInterface to specify the list of options to display in the widgets.

Hierarchy

Expanded class hierarchy of OptionsWidgetBase

See also

\Drupal\Core\TypedData\OptionsProviderInterface

File

core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/OptionsWidgetBase.php, line 24

Namespace

Drupal\Core\Field\Plugin\Field\FieldWidget
View source
abstract class OptionsWidgetBase extends WidgetBase {
    
    /**
     * Abstract over the actual field columns.
     *
     * Allows different field types to reuse those widgets.
     *
     * @var string
     */
    protected $column;
    
    /**
     * Tracks whether the field is required.
     */
    protected bool $required;
    
    /**
     * Tracks whether the data is multi-valued.
     */
    protected bool $multiple;
    
    /**
     * Tracks whether the field has a value.
     */
    // phpcs:ignore Drupal.NamingConventions.ValidVariableName.LowerCamelName
    protected bool $has_value;
    
    /**
     * The array of options for the widget.
     */
    protected array $options;
    
    /**
     * {@inheritdoc}
     */
    public function __construct($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, array $third_party_settings) {
        parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $third_party_settings);
        $property_names = $this->fieldDefinition
            ->getFieldStorageDefinition()
            ->getPropertyNames();
        $this->column = $property_names[0];
    }
    
    /**
     * {@inheritdoc}
     */
    public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
        // Prepare some properties for the child methods to build the actual form
        // element.
        $this->required = $element['#required'];
        $this->multiple = $this->fieldDefinition
            ->getFieldStorageDefinition()
            ->isMultiple();
        $this->has_value = isset($items[0]->{$this->column});
        // Add our custom validator.
        $element['#element_validate'][] = [
            static::class,
            'validateElement',
        ];
        $element['#key_column'] = $this->column;
        // The rest of the $element is built by child method implementations.
        return $element;
    }
    
    /**
     * Form validation handler for widget elements.
     *
     * @param array $element
     *   The form element.
     * @param \Drupal\Core\Form\FormStateInterface $form_state
     *   The form state.
     */
    public static function validateElement(array $element, FormStateInterface $form_state) {
        if ($element['#required'] && $element['#value'] == '_none') {
            if (isset($element['#required_error'])) {
                $form_state->setError($element, $element['#required_error']);
            }
            else {
                $form_state->setError($element, new TranslatableMarkup('@name field is required.', [
                    '@name' => $element['#title'],
                ]));
            }
        }
        // Massage submitted form values.
        // Drupal\Core\Field\WidgetBase::submit() expects values as
        // an array of values keyed by delta first, then by column, while our
        // widgets return the opposite.
        if (is_array($element['#value'])) {
            $values = array_values($element['#value']);
        }
        else {
            $values = [
                $element['#value'],
            ];
        }
        // Filter out the 'none' option. Use a strict comparison, because
        // 0 == 'any string'.
        $index = array_search('_none', $values, TRUE);
        if ($index !== FALSE) {
            unset($values[$index]);
        }
        // Transpose selections from field => delta to delta => field.
        $items = [];
        foreach ($values as $value) {
            $items[] = [
                $element['#key_column'] => $value,
            ];
        }
        $form_state->setValueForElement($element, $items);
    }
    
    /**
     * Returns the array of options for the widget.
     *
     * @param \Drupal\Core\Entity\FieldableEntityInterface $entity
     *   The entity for which to return options.
     *
     * @return array
     *   The array of options for the widget.
     */
    protected function getOptions(FieldableEntityInterface $entity) {
        if (!isset($this->options)) {
            // Limit the settable options for the current user account.
            $options = $this->fieldDefinition
                ->getFieldStorageDefinition()
                ->getOptionsProvider($this->column, $entity)
                ->getSettableOptions(\Drupal::currentUser());
            // Add an empty option if the widget needs one.
            if ($empty_label = $this->getEmptyLabel()) {
                $options = [
                    '_none' => $empty_label,
                ] + $options;
            }
            $module_handler = \Drupal::moduleHandler();
            $context = [
                'fieldDefinition' => $this->fieldDefinition,
                'entity' => $entity,
                'widget' => $this,
            ];
            $module_handler->alter('options_list', $options, $context);
            array_walk_recursive($options, [
                $this,
                'sanitizeLabel',
            ]);
            // Options might be nested ("optgroups"). If the widget does not support
            // nested options, flatten the list.
            if (!$this->supportsGroups()) {
                $options = OptGroup::flattenOptions($options);
            }
            $this->options = $options;
        }
        return $this->options;
    }
    
    /**
     * Determines selected options from the incoming field values.
     *
     * @param \Drupal\Core\Field\FieldItemListInterface $items
     *   The field values.
     *
     * @return array
     *   The array of corresponding selected options.
     */
    protected function getSelectedOptions(FieldItemListInterface $items) {
        // We need to check against a flat list of options.
        $flat_options = OptGroup::flattenOptions($this->getOptions($items->getEntity()));
        $selected_options = [];
        foreach ($items as $item) {
            $value = $item->{$this->column};
            // Keep the value if it actually is in the list of options (needs to be
            // checked against the flat list).
            if (isset($flat_options[$value])) {
                $selected_options[] = $value;
            }
        }
        return $selected_options;
    }
    
    /**
     * Indicates whether the widgets support optgroups.
     *
     * @return bool
     *   TRUE if the widget supports optgroups, FALSE otherwise.
     */
    protected function supportsGroups() {
        return FALSE;
    }
    
    /**
     * Sanitizes a string label to display as an option.
     *
     * @param string $label
     *   The label to sanitize.
     */
    protected function sanitizeLabel(&$label) {
        // Allow a limited set of HTML tags.
        $label = FieldFilteredMarkup::create($label);
    }
    
    /**
     * Returns the empty option label to add to the list of options, if any.
     *
     * @return string|null
     *   Either a label of the empty option, or NULL.
     */
    protected function getEmptyLabel() {
    }

}

Members

Title Sort descending Modifiers Object type Summary Overriden Title Overrides
OptionsWidgetBase::$column protected property Abstract over the actual field columns.
OptionsWidgetBase::$has_value protected property
OptionsWidgetBase::$multiple protected property Tracks whether the data is multi-valued.
OptionsWidgetBase::$options protected property The array of options for the widget.
OptionsWidgetBase::$required protected property Tracks whether the field is required.
OptionsWidgetBase::formElement public function Overrides WidgetInterface::formElement 2
OptionsWidgetBase::getEmptyLabel protected function Returns the empty option label to add to the list of options, if any. 2
OptionsWidgetBase::getOptions protected function Returns the array of options for the widget.
OptionsWidgetBase::getSelectedOptions protected function Determines selected options from the incoming field values.
OptionsWidgetBase::sanitizeLabel protected function Sanitizes a string label to display as an option. 1
OptionsWidgetBase::supportsGroups protected function Indicates whether the widgets support optgroups. 1
OptionsWidgetBase::validateElement public static function Form validation handler for widget elements. 1
OptionsWidgetBase::__construct public function Overrides WidgetBase::__construct 1
PluginInspectionInterface::getPluginDefinition public function Gets the definition of the plugin implementation. 6
PluginInspectionInterface::getPluginId public function Gets the plugin ID of the plugin instance. 2
PluginSettingsBase::$defaultSettingsMerged protected property Whether default settings have been merged into the current $settings.
PluginSettingsBase::$thirdPartySettings protected property The plugin settings injected by third party modules.
PluginSettingsBase::calculateDependencies public function Overrides DependentPluginInterface::calculateDependencies 6
PluginSettingsBase::defaultSettings public static function Overrides PluginSettingsInterface::defaultSettings 42
PluginSettingsBase::getSetting public function Overrides PluginSettingsInterface::getSetting
PluginSettingsBase::getSettings public function Overrides PluginSettingsInterface::getSettings
PluginSettingsBase::getThirdPartyProviders public function Overrides ThirdPartySettingsInterface::getThirdPartyProviders
PluginSettingsBase::getThirdPartySetting public function Overrides ThirdPartySettingsInterface::getThirdPartySetting
PluginSettingsBase::getThirdPartySettings public function Overrides ThirdPartySettingsInterface::getThirdPartySettings
PluginSettingsBase::mergeDefaults protected function Merges default settings values into $settings.
PluginSettingsBase::onDependencyRemoval public function Overrides PluginSettingsInterface::onDependencyRemoval 3
PluginSettingsBase::setSetting public function Overrides PluginSettingsInterface::setSetting
PluginSettingsBase::setSettings public function Overrides PluginSettingsInterface::setSettings
PluginSettingsBase::setThirdPartySetting public function Overrides ThirdPartySettingsInterface::setThirdPartySetting
PluginSettingsBase::unsetThirdPartySetting public function Overrides ThirdPartySettingsInterface::unsetThirdPartySetting
WidgetBase::$fieldDefinition protected property The field definition.
WidgetBase::$settings protected property The widget settings. Overrides PluginSettingsBase::$settings
WidgetBase::addMoreAjax public static function Ajax callback for the "Add another item" button.
WidgetBase::addMoreSubmit public static function Submission handler for the "Add another item" button.
WidgetBase::afterBuild public static function After-build handler for field elements in a form.
WidgetBase::create public static function Overrides ContainerFactoryPluginInterface::create 5
WidgetBase::deleteAjax public static function Ajax refresh callback for the "Remove" button.
WidgetBase::deleteSubmit public static function Ajax submit callback for the "Remove" button.
WidgetBase::errorElement public function Overrides WidgetInterface::errorElement 8
WidgetBase::extractFormValues public function Overrides WidgetBaseInterface::extractFormValues 3
WidgetBase::flagErrors public function Overrides WidgetBaseInterface::flagErrors 2
WidgetBase::form public function Overrides WidgetBaseInterface::form 3
WidgetBase::formMultipleElements protected function Special handling to create form elements for multiple values. 1
WidgetBase::formSingleElement protected function Generates the form element for a single copy of the widget.
WidgetBase::getFieldSetting protected function Returns the value of a field setting.
WidgetBase::getFieldSettings protected function Returns the array of field settings.
WidgetBase::getFilteredDescription protected function Returns the filtered field description.
WidgetBase::getWidgetState public static function Overrides WidgetBaseInterface::getWidgetState
WidgetBase::getWidgetStateParents protected static function Returns the location of processing information within $form_state.
WidgetBase::handlesMultipleValues protected function Returns whether the widget handles multiple values.
WidgetBase::isApplicable public static function Overrides WidgetInterface::isApplicable 4
WidgetBase::isDefaultValueWidget protected function Returns whether the widget used for default value form.
WidgetBase::massageFormValues public function Overrides WidgetInterface::massageFormValues 7
WidgetBase::settingsForm public function Overrides WidgetInterface::settingsForm 16
WidgetBase::settingsSummary public function Overrides WidgetInterface::settingsSummary 15
WidgetBase::setWidgetState public static function Overrides WidgetBaseInterface::setWidgetState

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.