ListItemBase.php

Same filename in other branches
  1. 9 core/modules/options/src/Plugin/Field/FieldType/ListItemBase.php
  2. 10 core/modules/options/src/Plugin/Field/FieldType/ListItemBase.php
  3. 11.x core/modules/options/src/Plugin/Field/FieldType/ListItemBase.php

Namespace

Drupal\options\Plugin\Field\FieldType

File

core/modules/options/src/Plugin/Field/FieldType/ListItemBase.php

View source
<?php

namespace Drupal\options\Plugin\Field\FieldType;

use Drupal\Core\Field\AllowedTagsXssTrait;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Form\OptGroup;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\TypedData\OptionsProviderInterface;

/**
 * Plugin base class inherited by the options field types.
 */
abstract class ListItemBase extends FieldItemBase implements OptionsProviderInterface {
    use AllowedTagsXssTrait;
    
    /**
     * {@inheritdoc}
     */
    public static function defaultStorageSettings() {
        return [
            'allowed_values' => [],
            'allowed_values_function' => '',
        ] + parent::defaultStorageSettings();
    }
    
    /**
     * {@inheritdoc}
     */
    public function getPossibleValues(AccountInterface $account = NULL) {
        // Flatten options firstly, because Possible Options may contain group
        // arrays.
        $flatten_options = OptGroup::flattenOptions($this->getPossibleOptions($account));
        return array_keys($flatten_options);
    }
    
    /**
     * {@inheritdoc}
     */
    public function getPossibleOptions(AccountInterface $account = NULL) {
        return $this->getSettableOptions($account);
    }
    
    /**
     * {@inheritdoc}
     */
    public function getSettableValues(AccountInterface $account = NULL) {
        // Flatten options firstly, because Settable Options may contain group
        // arrays.
        $flatten_options = OptGroup::flattenOptions($this->getSettableOptions($account));
        return array_keys($flatten_options);
    }
    
    /**
     * {@inheritdoc}
     */
    public function getSettableOptions(AccountInterface $account = NULL) {
        $allowed_options = options_allowed_values($this->getFieldDefinition()
            ->getFieldStorageDefinition(), $this->getEntity());
        return $allowed_options;
    }
    
    /**
     * {@inheritdoc}
     */
    public static function generateSampleValue(FieldDefinitionInterface $field_definition) {
        $allowed_options = options_allowed_values($field_definition->getFieldStorageDefinition());
        $values['value'] = array_rand($allowed_options);
        return $values;
    }
    
    /**
     * {@inheritdoc}
     */
    public function isEmpty() {
        return empty($this->value) && (string) $this->value !== '0';
    }
    
    /**
     * {@inheritdoc}
     */
    public function storageSettingsForm(array &$form, FormStateInterface $form_state, $has_data) {
        $allowed_values = $this->getSetting('allowed_values');
        $allowed_values_function = $this->getSetting('allowed_values_function');
        $element['allowed_values'] = [
            '#type' => 'textarea',
            '#title' => t('Allowed values list'),
            '#default_value' => $this->allowedValuesString($allowed_values),
            '#rows' => 10,
            '#access' => empty($allowed_values_function),
            '#element_validate' => [
                [
                    get_class($this),
                    'validateAllowedValues',
                ],
            ],
            '#field_has_data' => $has_data,
            '#field_name' => $this->getFieldDefinition()
                ->getName(),
            '#entity_type' => $this->getEntity()
                ->getEntityTypeId(),
            '#allowed_values' => $allowed_values,
        ];
        $element['allowed_values']['#description'] = $this->allowedValuesDescription();
        $element['allowed_values_function'] = [
            '#type' => 'item',
            '#title' => t('Allowed values list'),
            '#markup' => t('The value of this field is being determined by the %function function and may not be changed.', [
                '%function' => $allowed_values_function,
            ]),
            '#access' => !empty($allowed_values_function),
            '#value' => $allowed_values_function,
        ];
        return $element;
    }
    
    /**
     * Provides the field type specific allowed values form element #description.
     *
     * @return string
     *   The field type allowed values form specific description.
     */
    protected abstract function allowedValuesDescription();
    
    /**
     * #element_validate callback for options field allowed values.
     *
     * @param $element
     *   An associative array containing the properties and children of the
     *   generic form element.
     * @param $form_state
     *   The current state of the form for the form this element belongs to.
     *
     * @see \Drupal\Core\Render\Element\FormElement::processPattern()
     */
    public static function validateAllowedValues($element, FormStateInterface $form_state) {
        $values = static::extractAllowedValues($element['#value'], $element['#field_has_data']);
        if (!is_array($values)) {
            $form_state->setError($element, t('Allowed values list: invalid input.'));
        }
        else {
            // Check that keys are valid for the field type.
            foreach ($values as $key => $value) {
                if ($error = static::validateAllowedValue($key)) {
                    $form_state->setError($element, $error);
                    break;
                }
            }
            // Prevent removing values currently in use.
            if ($element['#field_has_data']) {
                $lost_keys = array_keys(array_diff_key($element['#allowed_values'], $values));
                if (_options_values_in_use($element['#entity_type'], $element['#field_name'], $lost_keys)) {
                    $form_state->setError($element, t('Allowed values list: some values are being removed while currently in use.'));
                }
            }
            $form_state->setValueForElement($element, $values);
        }
    }
    
    /**
     * Extracts the allowed values array from the allowed_values element.
     *
     * @param string $string
     *   The raw string to extract values from.
     * @param bool $has_data
     *   The current field already has data inserted or not.
     *
     * @return array|null
     *   The array of extracted key/value pairs, or NULL if the string is invalid.
     *
     * @see \Drupal\options\Plugin\Field\FieldType\ListItemBase::allowedValuesString()
     */
    protected static function extractAllowedValues($string, $has_data) {
        $values = [];
        $list = explode("\n", $string);
        $list = array_map('trim', $list);
        $list = array_filter($list, 'strlen');
        $generated_keys = $explicit_keys = FALSE;
        foreach ($list as $position => $text) {
            // Check for an explicit key.
            $matches = [];
            if (preg_match('/(.*)\\|(.*)/', $text, $matches)) {
                // Trim key and value to avoid unwanted spaces issues.
                $key = trim($matches[1]);
                $value = trim($matches[2]);
                $explicit_keys = TRUE;
            }
            elseif (!static::validateAllowedValue($text)) {
                $key = $value = $text;
                $explicit_keys = TRUE;
            }
            elseif (!$has_data) {
                $key = (string) $position;
                $value = $text;
                $generated_keys = TRUE;
            }
            else {
                return;
            }
            $values[$key] = $value;
        }
        // We generate keys only if the list contains no explicit key at all.
        if ($explicit_keys && $generated_keys) {
            return;
        }
        return $values;
    }
    
    /**
     * Checks whether a candidate allowed value is valid.
     *
     * @param string $option
     *   The option value entered by the user.
     *
     * @return string
     *   The error message if the specified value is invalid, NULL otherwise.
     */
    protected static function validateAllowedValue($option) {
    }
    
    /**
     * Generates a string representation of an array of 'allowed values'.
     *
     * This string format is suitable for edition in a textarea.
     *
     * @param array $values
     *   An array of values, where array keys are values and array values are
     *   labels.
     *
     * @return string
     *   The string representation of the $values array:
     *    - Values are separated by a carriage return.
     *    - Each value is in the format "value|label" or "value".
     */
    protected function allowedValuesString($values) {
        $lines = [];
        foreach ($values as $key => $value) {
            $lines[] = "{$key}|{$value}";
        }
        return implode("\n", $lines);
    }
    
    /**
     * {@inheritdoc}
     */
    public static function storageSettingsToConfigData(array $settings) {
        if (isset($settings['allowed_values'])) {
            $settings['allowed_values'] = static::structureAllowedValues($settings['allowed_values']);
        }
        return $settings;
    }
    
    /**
     * {@inheritdoc}
     */
    public static function storageSettingsFromConfigData(array $settings) {
        if (isset($settings['allowed_values'])) {
            $settings['allowed_values'] = static::simplifyAllowedValues($settings['allowed_values']);
        }
        return $settings;
    }
    
    /**
     * Simplifies allowed values to a key-value array from the structured array.
     *
     * @param array $structured_values
     *   Array of items with a 'value' and 'label' key each for the allowed
     *   values.
     *
     * @return array
     *   Allowed values were the array key is the 'value' value, the value is
     *   the 'label' value.
     *
     * @see \Drupal\options\Plugin\Field\FieldType\ListItemBase::structureAllowedValues()
     */
    protected static function simplifyAllowedValues(array $structured_values) {
        $values = [];
        foreach ($structured_values as $item) {
            if (is_array($item['label'])) {
                // Nested elements are embedded in the label.
                $item['label'] = static::simplifyAllowedValues($item['label']);
            }
            $values[$item['value']] = $item['label'];
        }
        return $values;
    }
    
    /**
     * Creates a structured array of allowed values from a key-value array.
     *
     * @param array $values
     *   Allowed values were the array key is the 'value' value, the value is
     *   the 'label' value.
     *
     * @return array
     *   Array of items with a 'value' and 'label' key each for the allowed
     *   values.
     *
     * @see \Drupal\options\Plugin\Field\FieldType\ListItemBase::simplifyAllowedValues()
     */
    protected static function structureAllowedValues(array $values) {
        $structured_values = [];
        foreach ($values as $value => $label) {
            if (is_array($label)) {
                $label = static::structureAllowedValues($label);
            }
            $structured_values[] = [
                'value' => static::castAllowedValue($value),
                'label' => $label,
            ];
        }
        return $structured_values;
    }
    
    /**
     * Converts a value to the correct type.
     *
     * @param mixed $value
     *   The value to cast.
     *
     * @return mixed
     *   The casted value.
     */
    protected static function castAllowedValue($value) {
        return $value;
    }

}

Classes

Title Deprecated Summary
ListItemBase Plugin base class inherited by the options field types.

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