View source
<?php
namespace Drupal\cck_select_other\Plugin\Field\FieldWidget;
use Drupal\Component\Utility\NestedArray;
use Drupal\Component\Utility\Html;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\Core\Field\Plugin\Field\FieldWidget\OptionsWidgetBase;
class SelectOtherWidget extends OptionsWidgetBase {
public static function defaultSettings() {
return [
'other_label' => t('Other'),
] + parent::defaultSettings();
}
public function settingsSummary() {
$summary = [];
if ($this
->getSetting('other_label')) {
$summary[] = t('Other label is @label', [
'@label' => $this
->getSetting('other_label'),
]);
}
return $summary;
}
public function settingsForm(array $form, FormStateInterface $form_state) {
$element['other_label'] = [
'#type' => 'textfield',
'#title' => t('Other label'),
'#description' => t('Provide an alternate label for "Other".'),
'#default_value' => $this
->getSetting('other_label'),
];
return $element;
}
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
$element = parent::formElement($items, $delta, $element, $form, $form_state);
$defaults = $this
->getDefaultValue($items, $element['#delta']);
$field_item_name = str_replace('_', '-', $this->fieldDefinition
->getName() . '-' . $element['#delta']);
$element += [
'#attributes' => [
'class' => [
'form-select-other-wrapper',
'cck-select-other-wrapper',
],
],
'#attached' => [
'library' => [
'cck_select_other/widget',
],
'drupalSettings' => [
'CCKSelectOther' => [
$this->fieldDefinition
->getName() => [
$delta => $field_item_name,
],
],
],
],
];
$element['select_other_list'] = [
'#title' => $element['#title'],
'#description' => $element['#description'],
'#type' => 'select',
'#options' => $this
->getOptions($items
->getEntity()),
'#default_value' => $defaults['select'],
'#required' => $this->fieldDefinition
->isRequired(),
'#attributes' => [
'class' => [
'form-text form-select',
'form-select-other-list',
],
],
];
$element['select_other_text_input'] = [
'#type' => 'textfield',
'#title' => t('Provide other option'),
'#title_display' => 'invisible',
'#default_value' => $defaults['textfield'],
'#size' => 60,
'#attributes' => [
'class' => [
'form-text',
'form-select-other-text-input',
],
],
];
return $element;
}
public static function validateElement(array $element, FormStateInterface $form_state) {
$form_state_values = $form_state
->getValues();
$values = NestedArray::getValue($form_state_values, $element['#parents']);
if (!$element['select_other_list']['#required'] && $values['select_other_list'] == '_none') {
$form_state
->setValueForElement($element, [
'value' => NULL,
]);
}
elseif ($element['select_other_list']['#required'] && $values['select_other_list'] == '') {
$form_state
->setValueForElement($element, [
'value' => '',
])
->setError($element, t('You must select an option.'));
}
elseif ($element['select_other_list']['#required'] && $values['select_other_list'] == 'other' && !$values['select_other_text_input']) {
$form_state
->setValueForElement($element, [
'value' => NULL,
])
->setError($element['select_other_text_input'], t('You must provide a value for this option.'));
}
elseif ($values['select_other_list'] == 'other' && $values['select_other_text_input']) {
$form_state
->setValueForElement($element, [
'value' => $values['select_other_text_input'],
]);
}
elseif ($values['select_other_list'] == 'other' && !$values['select_other_text_input']) {
$form_state
->setValueForELement($element, [
'value' => NULL,
]);
}
elseif (!isset($element['select_other_list']['#options'][$values['select_other_list']])) {
$form_state
->setError($element['select_other_list'], t('The value you selected is not a valid choice.'));
}
else {
$form_state
->setValueForElement($element, [
'value' => $values['select_other_list'],
]);
}
}
protected function sanitizeLabel(&$label) {
$label = strip_tags($label);
}
protected function supportsGroups() {
return TRUE;
}
protected function getDefaultValue(FieldItemListInterface $items, $delta = 0) {
$item =& $items[$delta];
$option_keys = [];
$options = $this
->getOptions($items
->getEntity());
if (!empty($options)) {
$option_keys = array_keys($options);
}
if (!$item->{$this->column}) {
$values = [
'select' => $this->fieldDefinition
->isRequired() ? '' : '_none',
'textfield' => '',
];
}
elseif (in_array($item->{$this->column}, $option_keys)) {
$values = [
'select' => $item->{$this->column},
'textfield' => '',
];
}
else {
$values = [
'select' => 'other',
'textfield' => $item->{$this->column},
];
}
return $values;
}
protected function getOptions(FieldableEntityInterface $entity) {
if (!isset($this->options)) {
$options = $this->fieldDefinition
->getFieldStorageDefinition()
->getOptionsProvider($this->column, $entity)
->getSettableOptions(\Drupal::currentUser());
$options['other'] = Html::escape($this
->getSetting('other_label'));
if ($empty_option = $this
->getEmptyOption()) {
$options = [
'_none' => $empty_option,
] + $options;
}
$module_handler = \Drupal::moduleHandler();
$context = [
'fieldDefinition' => $this->fieldDefinition,
'entity' => $entity,
];
$module_handler
->alter('options_list', $options, $context);
array_walk_recursive($options, [
$this,
'sanitizeLabel',
]);
if (!$this
->supportsGroups()) {
$options = $this
->flattenOptions($options);
}
$this->options = $options;
}
return $this->options;
}
protected function getEmptyOption() {
if (!$this->required) {
return t('- None -');
}
if (!$this->has_value) {
return t('- Select a value -');
}
}
}