You are here

abstract class YamlFormOtherBase in YAML Form 8

Base class for form other element.

Hierarchy

Expanded class hierarchy of YamlFormOtherBase

File

src/Element/YamlFormOtherBase.php, line 13

Namespace

Drupal\yamlform\Element
View source
abstract class YamlFormOtherBase extends FormElement {

  /**
   * Other option value.
   */
  const OTHER_OPTION = '_other_';

  /**
   * The type of element.
   *
   * @var string
   */
  protected static $type;

  /**
   * The properties of the element.
   *
   * @var array
   */
  protected static $properties = [
    '#required',
    '#options',
    '#options_display',
    '#default_value',
    '#attributes',
  ];

  /**
   * {@inheritdoc}
   */
  public function getInfo() {
    $class = get_class($this);
    return [
      '#input' => TRUE,
      '#process' => [
        [
          $class,
          'processYamlFormOther',
        ],
        [
          $class,
          'processAjaxForm',
        ],
      ],
      '#theme_wrappers' => [
        'form_element',
      ],
      '#options' => [],
      '#other__option_delimiter' => ', ',
      '#states' => [],
    ];
  }

  /**
   * Determine if the form element contains multiple values.
   *
   * @param array $element
   *   A form element.
   *
   * @return bool
   *   TRUE if the form element contains multiple values.
   */
  public static function isMultiple(array $element) {
    return !empty($element['#multiple']) || static::$type == 'checkboxes' ? TRUE : FALSE;
  }

  /**
   * Processes an 'other' element.
   *
   * See select list form element for select list properties.
   *
   * @see \Drupal\Core\Render\Element\Select
   */
  public static function processYamlFormOther(&$element, FormStateInterface $form_state, &$complete_form) {

    // Remove 'yamlform_' prefix from type.
    $type = str_replace('yamlform_', '', static::$type);
    $properties = static::$properties;
    $element['#tree'] = TRUE;
    $element['#wrapper_attributes']['class'][] = "js-yamlform-{$type}-other";
    $element['#wrapper_attributes']['class'][] = "yamlform-{$type}-other";
    $element[$type]['#type'] = static::$type;
    $element[$type] += array_intersect_key($element, array_combine($properties, $properties));
    if (!isset($element[$type]['#options'][static::OTHER_OPTION])) {
      $element[$type]['#options'][static::OTHER_OPTION] = !empty($element['#other__option_label']) ? $element['#other__option_label'] : t('Other...');
    }
    $element[$type]['#error_no_message'] = TRUE;

    // Build other textfield.
    $element['other']['#error_no_message'] = TRUE;
    foreach ($element as $key => $value) {
      if (strpos($key, '#other__') === 0) {
        $other_key = str_replace('#other__', '#', $key);
        if (!isset($element['other'][$other_key])) {
          $element['other'][$other_key] = $value;
        }
      }
    }
    $element['other'] += [
      '#type' => 'textfield',
      '#placeholder' => t('Enter other...'),
    ];
    $element['other']['#wrapper_attributes']['class'][] = "js-yamlform-{$type}-other-input";
    $element['other']['#wrapper_attributes']['class'][] = "yamlform-{$type}-other-input";

    // Remove options.
    unset($element['#options']);

    // Set validation.
    if (isset($element['#element_validate'])) {
      $element['#element_validate'] = array_merge([
        [
          get_called_class(),
          'validateYamlFormOther',
        ],
      ], $element['#element_validate']);
    }
    else {
      $element['#element_validate'] = [
        [
          get_called_class(),
          'validateYamlFormOther',
        ],
      ];
    }

    // Attach library.
    $element['#attached']['library'][] = 'yamlform/yamlform.element.other';

    // Process states.
    yamlform_process_states($element, '#wrapper_attributes');
    return $element;
  }

  /**
   * {@inheritdoc}
   */
  public static function valueCallback(&$element, $input, FormStateInterface $form_state) {

    // Remove 'yamlform_' prefix from type.
    $type = str_replace('yamlform_', '', static::$type);
    if ($input === FALSE) {
      $default_value = isset($element['#default_value']) ? $element['#default_value'] : NULL;
      if (!$default_value) {
        return $element;
      }
      if (static::isMultiple($element)) {
        if (is_array($default_value)) {
          $flattened_options = OptGroup::flattenOptions($element['#options']);
          if ($other_options = array_diff_key(array_combine($default_value, $default_value), $flattened_options)) {
            $element[$type]['#default_value'] = $default_value + [
              static::OTHER_OPTION => static::OTHER_OPTION,
            ];
            $element['other']['#default_value'] = implode($element['#other__option_delimiter'], $other_options);
          }
          return $element;
        }
      }
      elseif (!YamlFormOptionsHelper::hasOption($default_value, $element['#options'])) {
        $element[$type]['#default_value'] = static::OTHER_OPTION;
        $element['other']['#default_value'] = $default_value;
        return $element;
      }
      else {
        return $element;
      }
    }
    return NULL;
  }

  /**
   * Validates an other element.
   */
  public static function validateYamlFormOther(&$element, FormStateInterface $form_state, &$complete_form) {

    // Remove 'yamlform_' prefix from type.
    $type = str_replace('yamlform_', '', static::$type);
    $element_value = $element[$type]['#value'];
    $other_value = $element['other']['#value'];
    if (static::isMultiple($element)) {
      $value = $element_value;
      if (isset($element_value[static::OTHER_OPTION])) {
        unset($value[static::OTHER_OPTION]);
        if ($other_value === '') {
          static::setOtherError($element, $form_state);
          return;
        }
        else {
          $value[$other_value] = $other_value;
        }
      }
      $is_empty = empty($value) ? TRUE : FALSE;
    }
    else {
      $value = $element_value;
      if ($element_value == static::OTHER_OPTION) {
        if ($other_value === '') {
          static::setOtherError($element, $form_state);
          return;
        }
        else {
          $value = $other_value;
        }
      }
      $is_empty = $value === '' || $value === NULL ? TRUE : FALSE;
    }
    $has_access = !isset($element['#access']) || $element['#access'] === TRUE;
    if ($element['#required'] && $is_empty && $has_access) {
      static::setElementError($element, $form_state);
    }
    $form_state
      ->setValueForElement($element[$type], NULL);
    $form_state
      ->setValueForElement($element['other'], NULL);
    $form_state
      ->setValueForElement($element, $value);
  }

  /**
   * Set element required error.
   *
   * @param array $element
   *   The form element.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   */
  public static function setElementError(&$element, FormStateInterface $form_state) {
    if (isset($element['#required_error'])) {
      $form_state
        ->setError($element, $element['#required_error']);
    }
    elseif (isset($element['#title'])) {
      $form_state
        ->setError($element, t('@name field is required.', [
        '@name' => $element['#title'],
      ]));
    }
    else {
      $form_state
        ->setError($element);
    }
  }

  /**
   * Set element required error.
   *
   * @param array $element
   *   The form element.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   */
  public static function setOtherError(&$element, FormStateInterface $form_state) {
    if (isset($element['#required_error'])) {
      $form_state
        ->setError($element['other'], $element['#required_error']);
    }
    elseif (isset($element['#title'])) {
      $form_state
        ->setError($element['other'], t('@name field is required.', [
        '@name' => $element['#title'],
      ]));
    }
    else {
      $form_state
        ->setError($element['other']);
    }
  }

}

Members

Namesort descending Modifiers Type Description Overrides
DependencySerializationTrait::$_entityStorages protected property An array of entity type IDs keyed by the property name of their storages.
DependencySerializationTrait::$_serviceIds protected property An array of service IDs keyed by property name used for serialization.
DependencySerializationTrait::__sleep public function 1
DependencySerializationTrait::__wakeup public function 2
FormElement::processAutocomplete public static function Adds autocomplete functionality to elements.
FormElement::processPattern public static function #process callback for #pattern form element property.
FormElement::validatePattern public static function #element_validate callback for #pattern form element property.
MessengerTrait::$messenger protected property The messenger. 29
MessengerTrait::messenger public function Gets the messenger. 29
MessengerTrait::setMessenger public function Sets the messenger.
PluginBase::$configuration protected property Configuration information passed into the plugin. 1
PluginBase::$pluginDefinition protected property The plugin implementation definition. 1
PluginBase::$pluginId protected property The plugin_id.
PluginBase::DERIVATIVE_SEPARATOR constant A string which is used to separate base plugin IDs from the derivative ID.
PluginBase::getBaseId public function Gets the base_plugin_id of the plugin instance. Overrides DerivativeInspectionInterface::getBaseId
PluginBase::getDerivativeId public function Gets the derivative_id of the plugin instance. Overrides DerivativeInspectionInterface::getDerivativeId
PluginBase::getPluginDefinition public function Gets the definition of the plugin implementation. Overrides PluginInspectionInterface::getPluginDefinition 3
PluginBase::getPluginId public function Gets the plugin_id of the plugin instance. Overrides PluginInspectionInterface::getPluginId
PluginBase::isConfigurable public function Determines if the plugin is configurable.
PluginBase::__construct public function Constructs a \Drupal\Component\Plugin\PluginBase object. 92
RenderElement::preRenderAjaxForm public static function Adds Ajax information about an element to communicate with JavaScript.
RenderElement::preRenderGroup public static function Adds members of this group as actual elements for rendering.
RenderElement::processAjaxForm public static function Form element processing handler for the #ajax form property. 1
RenderElement::processGroup public static function Arranges elements into groups.
RenderElement::setAttributes public static function Sets a form element's class attribute. Overrides ElementInterface::setAttributes
StringTranslationTrait::$stringTranslation protected property The string translation service. 1
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.
YamlFormOtherBase::$properties protected static property The properties of the element. 1
YamlFormOtherBase::$type protected static property The type of element. 4
YamlFormOtherBase::getInfo public function Returns the element properties for this element. Overrides ElementInterface::getInfo
YamlFormOtherBase::isMultiple public static function Determine if the form element contains multiple values.
YamlFormOtherBase::OTHER_OPTION constant Other option value.
YamlFormOtherBase::processYamlFormOther public static function Processes an 'other' element. 1
YamlFormOtherBase::setElementError public static function Set element required error.
YamlFormOtherBase::setOtherError public static function Set element required error.
YamlFormOtherBase::validateYamlFormOther public static function Validates an other element.
YamlFormOtherBase::valueCallback public static function Determines how user input is mapped to an element's #value property. Overrides FormElement::valueCallback