annotate core/lib/Drupal/Core/Field/WidgetBase.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents 1fec387a4317
children
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 namespace Drupal\Core\Field;
Chris@0 4
Chris@0 5 use Drupal\Component\Utility\Html;
Chris@0 6 use Drupal\Component\Utility\NestedArray;
Chris@0 7 use Drupal\Component\Utility\SortArray;
Chris@0 8 use Drupal\Core\Form\FormStateInterface;
Chris@0 9 use Drupal\Core\Render\Element;
Chris@0 10 use Symfony\Component\Validator\ConstraintViolationInterface;
Chris@0 11 use Symfony\Component\Validator\ConstraintViolationListInterface;
Chris@0 12
Chris@0 13 /**
Chris@0 14 * Base class for 'Field widget' plugin implementations.
Chris@0 15 *
Chris@0 16 * @ingroup field_widget
Chris@0 17 */
Chris@0 18 abstract class WidgetBase extends PluginSettingsBase implements WidgetInterface {
Chris@0 19
Chris@0 20 use AllowedTagsXssTrait;
Chris@0 21
Chris@0 22 /**
Chris@0 23 * The field definition.
Chris@0 24 *
Chris@0 25 * @var \Drupal\Core\Field\FieldDefinitionInterface
Chris@0 26 */
Chris@0 27 protected $fieldDefinition;
Chris@0 28
Chris@0 29 /**
Chris@0 30 * The widget settings.
Chris@0 31 *
Chris@0 32 * @var array
Chris@0 33 */
Chris@0 34 protected $settings;
Chris@0 35
Chris@0 36 /**
Chris@0 37 * Constructs a WidgetBase object.
Chris@0 38 *
Chris@0 39 * @param string $plugin_id
Chris@0 40 * The plugin_id for the widget.
Chris@0 41 * @param mixed $plugin_definition
Chris@0 42 * The plugin implementation definition.
Chris@0 43 * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
Chris@0 44 * The definition of the field to which the widget is associated.
Chris@0 45 * @param array $settings
Chris@0 46 * The widget settings.
Chris@0 47 * @param array $third_party_settings
Chris@0 48 * Any third party settings.
Chris@0 49 */
Chris@0 50 public function __construct($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, array $third_party_settings) {
Chris@0 51 parent::__construct([], $plugin_id, $plugin_definition);
Chris@0 52 $this->fieldDefinition = $field_definition;
Chris@0 53 $this->settings = $settings;
Chris@0 54 $this->thirdPartySettings = $third_party_settings;
Chris@0 55 }
Chris@0 56
Chris@0 57 /**
Chris@0 58 * {@inheritdoc}
Chris@0 59 */
Chris@0 60 public function form(FieldItemListInterface $items, array &$form, FormStateInterface $form_state, $get_delta = NULL) {
Chris@0 61 $field_name = $this->fieldDefinition->getName();
Chris@0 62 $parents = $form['#parents'];
Chris@0 63
Chris@0 64 // Store field information in $form_state.
Chris@0 65 if (!static::getWidgetState($parents, $field_name, $form_state)) {
Chris@0 66 $field_state = [
Chris@0 67 'items_count' => count($items),
Chris@0 68 'array_parents' => [],
Chris@0 69 ];
Chris@0 70 static::setWidgetState($parents, $field_name, $form_state, $field_state);
Chris@0 71 }
Chris@0 72
Chris@0 73 // Collect widget elements.
Chris@0 74 $elements = [];
Chris@0 75
Chris@0 76 // If the widget is handling multiple values (e.g Options), or if we are
Chris@0 77 // displaying an individual element, just get a single form element and make
Chris@0 78 // it the $delta value.
Chris@0 79 if ($this->handlesMultipleValues() || isset($get_delta)) {
Chris@0 80 $delta = isset($get_delta) ? $get_delta : 0;
Chris@0 81 $element = [
Chris@0 82 '#title' => $this->fieldDefinition->getLabel(),
Chris@0 83 '#description' => FieldFilteredMarkup::create(\Drupal::token()->replace($this->fieldDefinition->getDescription())),
Chris@0 84 ];
Chris@0 85 $element = $this->formSingleElement($items, $delta, $element, $form, $form_state);
Chris@0 86
Chris@0 87 if ($element) {
Chris@0 88 if (isset($get_delta)) {
Chris@0 89 // If we are processing a specific delta value for a field where the
Chris@0 90 // field module handles multiples, set the delta in the result.
Chris@0 91 $elements[$delta] = $element;
Chris@0 92 }
Chris@0 93 else {
Chris@0 94 // For fields that handle their own processing, we cannot make
Chris@0 95 // assumptions about how the field is structured, just merge in the
Chris@0 96 // returned element.
Chris@0 97 $elements = $element;
Chris@0 98 }
Chris@0 99 }
Chris@0 100 }
Chris@0 101 // If the widget does not handle multiple values itself, (and we are not
Chris@0 102 // displaying an individual element), process the multiple value form.
Chris@0 103 else {
Chris@0 104 $elements = $this->formMultipleElements($items, $form, $form_state);
Chris@0 105 }
Chris@0 106
Chris@14 107 // Allow modules to alter the field multi-value widget form element.
Chris@14 108 // This hook can also be used for single-value fields.
Chris@14 109 $context = [
Chris@14 110 'form' => $form,
Chris@14 111 'widget' => $this,
Chris@14 112 'items' => $items,
Chris@14 113 'default' => $this->isDefaultValueWidget($form_state),
Chris@14 114 ];
Chris@14 115 \Drupal::moduleHandler()->alter([
Chris@14 116 'field_widget_multivalue_form',
Chris@14 117 'field_widget_multivalue_' . $this->getPluginId() . '_form',
Chris@14 118 ], $elements, $form_state, $context);
Chris@14 119
Chris@0 120 // Populate the 'array_parents' information in $form_state->get('field')
Chris@0 121 // after the form is built, so that we catch changes in the form structure
Chris@0 122 // performed in alter() hooks.
Chris@0 123 $elements['#after_build'][] = [get_class($this), 'afterBuild'];
Chris@0 124 $elements['#field_name'] = $field_name;
Chris@0 125 $elements['#field_parents'] = $parents;
Chris@0 126 // Enforce the structure of submitted values.
Chris@0 127 $elements['#parents'] = array_merge($parents, [$field_name]);
Chris@0 128 // Most widgets need their internal structure preserved in submitted values.
Chris@0 129 $elements += ['#tree' => TRUE];
Chris@0 130
Chris@0 131 return [
Chris@0 132 // Aid in theming of widgets by rendering a classified container.
Chris@0 133 '#type' => 'container',
Chris@0 134 // Assign a different parent, to keep the main id for the widget itself.
Chris@0 135 '#parents' => array_merge($parents, [$field_name . '_wrapper']),
Chris@0 136 '#attributes' => [
Chris@0 137 'class' => [
Chris@0 138 'field--type-' . Html::getClass($this->fieldDefinition->getType()),
Chris@0 139 'field--name-' . Html::getClass($field_name),
Chris@0 140 'field--widget-' . Html::getClass($this->getPluginId()),
Chris@0 141 ],
Chris@0 142 ],
Chris@0 143 'widget' => $elements,
Chris@0 144 ];
Chris@0 145 }
Chris@0 146
Chris@0 147 /**
Chris@0 148 * Special handling to create form elements for multiple values.
Chris@0 149 *
Chris@0 150 * Handles generic features for multiple fields:
Chris@0 151 * - number of widgets
Chris@0 152 * - AHAH-'add more' button
Chris@0 153 * - table display and drag-n-drop value reordering
Chris@0 154 */
Chris@0 155 protected function formMultipleElements(FieldItemListInterface $items, array &$form, FormStateInterface $form_state) {
Chris@0 156 $field_name = $this->fieldDefinition->getName();
Chris@0 157 $cardinality = $this->fieldDefinition->getFieldStorageDefinition()->getCardinality();
Chris@0 158 $parents = $form['#parents'];
Chris@0 159
Chris@0 160 // Determine the number of widgets to display.
Chris@0 161 switch ($cardinality) {
Chris@0 162 case FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED:
Chris@0 163 $field_state = static::getWidgetState($parents, $field_name, $form_state);
Chris@0 164 $max = $field_state['items_count'];
Chris@0 165 $is_multiple = TRUE;
Chris@0 166 break;
Chris@0 167
Chris@0 168 default:
Chris@0 169 $max = $cardinality - 1;
Chris@0 170 $is_multiple = ($cardinality > 1);
Chris@0 171 break;
Chris@0 172 }
Chris@0 173
Chris@0 174 $title = $this->fieldDefinition->getLabel();
Chris@0 175 $description = FieldFilteredMarkup::create(\Drupal::token()->replace($this->fieldDefinition->getDescription()));
Chris@0 176
Chris@0 177 $elements = [];
Chris@0 178
Chris@0 179 for ($delta = 0; $delta <= $max; $delta++) {
Chris@0 180 // Add a new empty item if it doesn't exist yet at this delta.
Chris@0 181 if (!isset($items[$delta])) {
Chris@0 182 $items->appendItem();
Chris@0 183 }
Chris@0 184
Chris@0 185 // For multiple fields, title and description are handled by the wrapping
Chris@0 186 // table.
Chris@0 187 if ($is_multiple) {
Chris@0 188 $element = [
Chris@0 189 '#title' => $this->t('@title (value @number)', ['@title' => $title, '@number' => $delta + 1]),
Chris@0 190 '#title_display' => 'invisible',
Chris@0 191 '#description' => '',
Chris@0 192 ];
Chris@0 193 }
Chris@0 194 else {
Chris@0 195 $element = [
Chris@0 196 '#title' => $title,
Chris@0 197 '#title_display' => 'before',
Chris@0 198 '#description' => $description,
Chris@0 199 ];
Chris@0 200 }
Chris@0 201
Chris@0 202 $element = $this->formSingleElement($items, $delta, $element, $form, $form_state);
Chris@0 203
Chris@0 204 if ($element) {
Chris@0 205 // Input field for the delta (drag-n-drop reordering).
Chris@0 206 if ($is_multiple) {
Chris@0 207 // We name the element '_weight' to avoid clashing with elements
Chris@0 208 // defined by widget.
Chris@0 209 $element['_weight'] = [
Chris@0 210 '#type' => 'weight',
Chris@0 211 '#title' => $this->t('Weight for row @number', ['@number' => $delta + 1]),
Chris@0 212 '#title_display' => 'invisible',
Chris@0 213 // Note: this 'delta' is the FAPI #type 'weight' element's property.
Chris@0 214 '#delta' => $max,
Chris@0 215 '#default_value' => $items[$delta]->_weight ?: $delta,
Chris@0 216 '#weight' => 100,
Chris@0 217 ];
Chris@0 218 }
Chris@0 219
Chris@0 220 $elements[$delta] = $element;
Chris@0 221 }
Chris@0 222 }
Chris@0 223
Chris@0 224 if ($elements) {
Chris@0 225 $elements += [
Chris@0 226 '#theme' => 'field_multiple_value_form',
Chris@0 227 '#field_name' => $field_name,
Chris@0 228 '#cardinality' => $cardinality,
Chris@0 229 '#cardinality_multiple' => $this->fieldDefinition->getFieldStorageDefinition()->isMultiple(),
Chris@0 230 '#required' => $this->fieldDefinition->isRequired(),
Chris@0 231 '#title' => $title,
Chris@0 232 '#description' => $description,
Chris@0 233 '#max_delta' => $max,
Chris@0 234 ];
Chris@0 235
Chris@0 236 // Add 'add more' button, if not working with a programmed form.
Chris@0 237 if ($cardinality == FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED && !$form_state->isProgrammed()) {
Chris@0 238 $id_prefix = implode('-', array_merge($parents, [$field_name]));
Chris@0 239 $wrapper_id = Html::getUniqueId($id_prefix . '-add-more-wrapper');
Chris@0 240 $elements['#prefix'] = '<div id="' . $wrapper_id . '">';
Chris@0 241 $elements['#suffix'] = '</div>';
Chris@0 242
Chris@0 243 $elements['add_more'] = [
Chris@0 244 '#type' => 'submit',
Chris@0 245 '#name' => strtr($id_prefix, '-', '_') . '_add_more',
Chris@0 246 '#value' => t('Add another item'),
Chris@0 247 '#attributes' => ['class' => ['field-add-more-submit']],
Chris@0 248 '#limit_validation_errors' => [array_merge($parents, [$field_name])],
Chris@0 249 '#submit' => [[get_class($this), 'addMoreSubmit']],
Chris@0 250 '#ajax' => [
Chris@0 251 'callback' => [get_class($this), 'addMoreAjax'],
Chris@0 252 'wrapper' => $wrapper_id,
Chris@0 253 'effect' => 'fade',
Chris@0 254 ],
Chris@0 255 ];
Chris@0 256 }
Chris@0 257 }
Chris@0 258
Chris@0 259 return $elements;
Chris@0 260 }
Chris@0 261
Chris@0 262 /**
Chris@0 263 * After-build handler for field elements in a form.
Chris@0 264 *
Chris@0 265 * This stores the final location of the field within the form structure so
Chris@0 266 * that flagErrors() can assign validation errors to the right form element.
Chris@0 267 */
Chris@0 268 public static function afterBuild(array $element, FormStateInterface $form_state) {
Chris@0 269 $parents = $element['#field_parents'];
Chris@0 270 $field_name = $element['#field_name'];
Chris@0 271
Chris@0 272 $field_state = static::getWidgetState($parents, $field_name, $form_state);
Chris@0 273 $field_state['array_parents'] = $element['#array_parents'];
Chris@0 274 static::setWidgetState($parents, $field_name, $form_state, $field_state);
Chris@0 275
Chris@0 276 return $element;
Chris@0 277 }
Chris@0 278
Chris@0 279 /**
Chris@0 280 * Submission handler for the "Add another item" button.
Chris@0 281 */
Chris@0 282 public static function addMoreSubmit(array $form, FormStateInterface $form_state) {
Chris@0 283 $button = $form_state->getTriggeringElement();
Chris@0 284
Chris@0 285 // Go one level up in the form, to the widgets container.
Chris@0 286 $element = NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -1));
Chris@0 287 $field_name = $element['#field_name'];
Chris@0 288 $parents = $element['#field_parents'];
Chris@0 289
Chris@0 290 // Increment the items count.
Chris@0 291 $field_state = static::getWidgetState($parents, $field_name, $form_state);
Chris@0 292 $field_state['items_count']++;
Chris@0 293 static::setWidgetState($parents, $field_name, $form_state, $field_state);
Chris@0 294
Chris@0 295 $form_state->setRebuild();
Chris@0 296 }
Chris@0 297
Chris@0 298 /**
Chris@0 299 * Ajax callback for the "Add another item" button.
Chris@0 300 *
Chris@0 301 * This returns the new page content to replace the page content made obsolete
Chris@0 302 * by the form submission.
Chris@0 303 */
Chris@0 304 public static function addMoreAjax(array $form, FormStateInterface $form_state) {
Chris@0 305 $button = $form_state->getTriggeringElement();
Chris@0 306
Chris@0 307 // Go one level up in the form, to the widgets container.
Chris@0 308 $element = NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -1));
Chris@0 309
Chris@0 310 // Ensure the widget allows adding additional items.
Chris@0 311 if ($element['#cardinality'] != FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED) {
Chris@0 312 return;
Chris@0 313 }
Chris@0 314
Chris@0 315 // Add a DIV around the delta receiving the Ajax effect.
Chris@0 316 $delta = $element['#max_delta'];
Chris@0 317 $element[$delta]['#prefix'] = '<div class="ajax-new-content">' . (isset($element[$delta]['#prefix']) ? $element[$delta]['#prefix'] : '');
Chris@0 318 $element[$delta]['#suffix'] = (isset($element[$delta]['#suffix']) ? $element[$delta]['#suffix'] : '') . '</div>';
Chris@0 319
Chris@0 320 return $element;
Chris@0 321 }
Chris@0 322
Chris@0 323 /**
Chris@0 324 * Generates the form element for a single copy of the widget.
Chris@0 325 */
Chris@0 326 protected function formSingleElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
Chris@0 327 $element += [
Chris@0 328 '#field_parents' => $form['#parents'],
Chris@0 329 // Only the first widget should be required.
Chris@0 330 '#required' => $delta == 0 && $this->fieldDefinition->isRequired(),
Chris@0 331 '#delta' => $delta,
Chris@0 332 '#weight' => $delta,
Chris@0 333 ];
Chris@0 334
Chris@0 335 $element = $this->formElement($items, $delta, $element, $form, $form_state);
Chris@0 336
Chris@0 337 if ($element) {
Chris@0 338 // Allow modules to alter the field widget form element.
Chris@0 339 $context = [
Chris@0 340 'form' => $form,
Chris@0 341 'widget' => $this,
Chris@0 342 'items' => $items,
Chris@0 343 'delta' => $delta,
Chris@0 344 'default' => $this->isDefaultValueWidget($form_state),
Chris@0 345 ];
Chris@0 346 \Drupal::moduleHandler()->alter(['field_widget_form', 'field_widget_' . $this->getPluginId() . '_form'], $element, $form_state, $context);
Chris@0 347 }
Chris@0 348
Chris@0 349 return $element;
Chris@0 350 }
Chris@0 351
Chris@0 352 /**
Chris@0 353 * {@inheritdoc}
Chris@0 354 */
Chris@0 355 public function extractFormValues(FieldItemListInterface $items, array $form, FormStateInterface $form_state) {
Chris@0 356 $field_name = $this->fieldDefinition->getName();
Chris@0 357
Chris@0 358 // Extract the values from $form_state->getValues().
Chris@0 359 $path = array_merge($form['#parents'], [$field_name]);
Chris@0 360 $key_exists = NULL;
Chris@0 361 $values = NestedArray::getValue($form_state->getValues(), $path, $key_exists);
Chris@0 362
Chris@0 363 if ($key_exists) {
Chris@0 364 // Account for drag-and-drop reordering if needed.
Chris@0 365 if (!$this->handlesMultipleValues()) {
Chris@0 366 // Remove the 'value' of the 'add more' button.
Chris@0 367 unset($values['add_more']);
Chris@0 368
Chris@0 369 // The original delta, before drag-and-drop reordering, is needed to
Chris@0 370 // route errors to the correct form element.
Chris@0 371 foreach ($values as $delta => &$value) {
Chris@0 372 $value['_original_delta'] = $delta;
Chris@0 373 }
Chris@0 374
Chris@0 375 usort($values, function ($a, $b) {
Chris@0 376 return SortArray::sortByKeyInt($a, $b, '_weight');
Chris@0 377 });
Chris@0 378 }
Chris@0 379
Chris@0 380 // Let the widget massage the submitted values.
Chris@0 381 $values = $this->massageFormValues($values, $form, $form_state);
Chris@0 382
Chris@0 383 // Assign the values and remove the empty ones.
Chris@0 384 $items->setValue($values);
Chris@0 385 $items->filterEmptyItems();
Chris@0 386
Chris@0 387 // Put delta mapping in $form_state, so that flagErrors() can use it.
Chris@0 388 $field_state = static::getWidgetState($form['#parents'], $field_name, $form_state);
Chris@0 389 foreach ($items as $delta => $item) {
Chris@0 390 $field_state['original_deltas'][$delta] = isset($item->_original_delta) ? $item->_original_delta : $delta;
Chris@0 391 unset($item->_original_delta, $item->_weight);
Chris@0 392 }
Chris@0 393 static::setWidgetState($form['#parents'], $field_name, $form_state, $field_state);
Chris@0 394 }
Chris@0 395 }
Chris@0 396
Chris@0 397 /**
Chris@0 398 * {@inheritdoc}
Chris@0 399 */
Chris@0 400 public function flagErrors(FieldItemListInterface $items, ConstraintViolationListInterface $violations, array $form, FormStateInterface $form_state) {
Chris@0 401 $field_name = $this->fieldDefinition->getName();
Chris@0 402
Chris@0 403 $field_state = static::getWidgetState($form['#parents'], $field_name, $form_state);
Chris@0 404
Chris@0 405 if ($violations->count()) {
Chris@0 406 // Locate the correct element in the form.
Chris@0 407 $element = NestedArray::getValue($form_state->getCompleteForm(), $field_state['array_parents']);
Chris@0 408
Chris@0 409 // Do not report entity-level validation errors if Form API errors have
Chris@0 410 // already been reported for the field.
Chris@0 411 // @todo Field validation should not be run on fields with FAPI errors to
Chris@0 412 // begin with. See https://www.drupal.org/node/2070429.
Chris@0 413 $element_path = implode('][', $element['#parents']);
Chris@0 414 if ($reported_errors = $form_state->getErrors()) {
Chris@0 415 foreach (array_keys($reported_errors) as $error_path) {
Chris@0 416 if (strpos($error_path, $element_path) === 0) {
Chris@0 417 return;
Chris@0 418 }
Chris@0 419 }
Chris@0 420 }
Chris@0 421
Chris@0 422 // Only set errors if the element is visible.
Chris@0 423 if (Element::isVisibleElement($element)) {
Chris@0 424 $handles_multiple = $this->handlesMultipleValues();
Chris@0 425
Chris@14 426 $violations_by_delta = $item_list_violations = [];
Chris@0 427 foreach ($violations as $violation) {
Chris@0 428 // Separate violations by delta.
Chris@0 429 $property_path = explode('.', $violation->getPropertyPath());
Chris@0 430 $delta = array_shift($property_path);
Chris@14 431 if (is_numeric($delta)) {
Chris@14 432 $violations_by_delta[$delta][] = $violation;
Chris@14 433 }
Chris@14 434 // Violations at the ItemList level are not associated to any delta.
Chris@14 435 else {
Chris@14 436 $item_list_violations[] = $violation;
Chris@14 437 }
Chris@0 438 $violation->arrayPropertyPath = $property_path;
Chris@0 439 }
Chris@0 440
Chris@0 441 /** @var \Symfony\Component\Validator\ConstraintViolationInterface[] $delta_violations */
Chris@0 442 foreach ($violations_by_delta as $delta => $delta_violations) {
Chris@14 443 // Pass violations to the main element if this is a multiple-value
Chris@14 444 // widget.
Chris@14 445 if ($handles_multiple) {
Chris@0 446 $delta_element = $element;
Chris@0 447 }
Chris@0 448 // Otherwise, pass errors by delta to the corresponding sub-element.
Chris@0 449 else {
Chris@0 450 $original_delta = $field_state['original_deltas'][$delta];
Chris@0 451 $delta_element = $element[$original_delta];
Chris@0 452 }
Chris@0 453 foreach ($delta_violations as $violation) {
Chris@0 454 // @todo: Pass $violation->arrayPropertyPath as property path.
Chris@0 455 $error_element = $this->errorElement($delta_element, $violation, $form, $form_state);
Chris@0 456 if ($error_element !== FALSE) {
Chris@0 457 $form_state->setError($error_element, $violation->getMessage());
Chris@0 458 }
Chris@0 459 }
Chris@0 460 }
Chris@14 461
Chris@14 462 /** @var \Symfony\Component\Validator\ConstraintViolationInterface[] $item_list_violations */
Chris@14 463 // Pass violations to the main element without going through
Chris@14 464 // errorElement() if the violations are at the ItemList level.
Chris@14 465 foreach ($item_list_violations as $violation) {
Chris@14 466 $form_state->setError($element, $violation->getMessage());
Chris@14 467 }
Chris@0 468 }
Chris@0 469 }
Chris@0 470 }
Chris@0 471
Chris@0 472 /**
Chris@0 473 * {@inheritdoc}
Chris@0 474 */
Chris@0 475 public static function getWidgetState(array $parents, $field_name, FormStateInterface $form_state) {
Chris@0 476 return NestedArray::getValue($form_state->getStorage(), static::getWidgetStateParents($parents, $field_name));
Chris@0 477 }
Chris@0 478
Chris@0 479 /**
Chris@0 480 * {@inheritdoc}
Chris@0 481 */
Chris@0 482 public static function setWidgetState(array $parents, $field_name, FormStateInterface $form_state, array $field_state) {
Chris@0 483 NestedArray::setValue($form_state->getStorage(), static::getWidgetStateParents($parents, $field_name), $field_state);
Chris@0 484 }
Chris@0 485
Chris@0 486 /**
Chris@0 487 * Returns the location of processing information within $form_state.
Chris@0 488 *
Chris@0 489 * @param array $parents
Chris@0 490 * The array of #parents where the widget lives in the form.
Chris@0 491 * @param string $field_name
Chris@0 492 * The field name.
Chris@0 493 *
Chris@0 494 * @return array
Chris@0 495 * The location of processing information within $form_state.
Chris@0 496 */
Chris@0 497 protected static function getWidgetStateParents(array $parents, $field_name) {
Chris@0 498 // Field processing data is placed at
Chris@0 499 // $form_state->get(['field_storage', '#parents', ...$parents..., '#fields', $field_name]),
Chris@0 500 // to avoid clashes between field names and $parents parts.
Chris@0 501 return array_merge(['field_storage', '#parents'], $parents, ['#fields', $field_name]);
Chris@0 502 }
Chris@0 503
Chris@0 504 /**
Chris@0 505 * {@inheritdoc}
Chris@0 506 */
Chris@0 507 public function settingsForm(array $form, FormStateInterface $form_state) {
Chris@0 508 return [];
Chris@0 509 }
Chris@0 510
Chris@0 511 /**
Chris@0 512 * {@inheritdoc}
Chris@0 513 */
Chris@0 514 public function settingsSummary() {
Chris@0 515 return [];
Chris@0 516 }
Chris@0 517
Chris@0 518 /**
Chris@0 519 * {@inheritdoc}
Chris@0 520 */
Chris@0 521 public function errorElement(array $element, ConstraintViolationInterface $error, array $form, FormStateInterface $form_state) {
Chris@0 522 return $element;
Chris@0 523 }
Chris@0 524
Chris@0 525 /**
Chris@0 526 * {@inheritdoc}
Chris@0 527 */
Chris@0 528 public function massageFormValues(array $values, array $form, FormStateInterface $form_state) {
Chris@0 529 return $values;
Chris@0 530 }
Chris@0 531
Chris@0 532 /**
Chris@0 533 * Returns the array of field settings.
Chris@0 534 *
Chris@0 535 * @return array
Chris@0 536 * The array of settings.
Chris@0 537 */
Chris@0 538 protected function getFieldSettings() {
Chris@0 539 return $this->fieldDefinition->getSettings();
Chris@0 540 }
Chris@0 541
Chris@0 542 /**
Chris@0 543 * Returns the value of a field setting.
Chris@0 544 *
Chris@0 545 * @param string $setting_name
Chris@0 546 * The setting name.
Chris@0 547 *
Chris@0 548 * @return mixed
Chris@0 549 * The setting value.
Chris@0 550 */
Chris@0 551 protected function getFieldSetting($setting_name) {
Chris@0 552 return $this->fieldDefinition->getSetting($setting_name);
Chris@0 553 }
Chris@0 554
Chris@0 555 /**
Chris@0 556 * Returns whether the widget handles multiple values.
Chris@0 557 *
Chris@0 558 * @return bool
Chris@0 559 * TRUE if a single copy of formElement() can handle multiple field values,
Chris@0 560 * FALSE if multiple values require separate copies of formElement().
Chris@0 561 */
Chris@0 562 protected function handlesMultipleValues() {
Chris@0 563 $definition = $this->getPluginDefinition();
Chris@0 564 return $definition['multiple_values'];
Chris@0 565 }
Chris@0 566
Chris@0 567 /**
Chris@0 568 * {@inheritdoc}
Chris@0 569 */
Chris@0 570 public static function isApplicable(FieldDefinitionInterface $field_definition) {
Chris@0 571 // By default, widgets are available for all fields.
Chris@0 572 return TRUE;
Chris@0 573 }
Chris@0 574
Chris@0 575 /**
Chris@0 576 * Returns whether the widget used for default value form.
Chris@0 577 *
Chris@0 578 * @param \Drupal\Core\Form\FormStateInterface $form_state
Chris@0 579 * The current state of the form.
Chris@0 580 *
Chris@0 581 * @return bool
Chris@0 582 * TRUE if a widget used to input default value, FALSE otherwise.
Chris@0 583 */
Chris@0 584 protected function isDefaultValueWidget(FormStateInterface $form_state) {
Chris@0 585 return (bool) $form_state->get('default_value_widget');
Chris@0 586 }
Chris@0 587
Chris@0 588 /**
Chris@0 589 * Returns the filtered field description.
Chris@0 590 *
Chris@0 591 * @return \Drupal\Core\Field\FieldFilteredMarkup
Chris@0 592 * The filtered field description, with tokens replaced.
Chris@0 593 */
Chris@0 594 protected function getFilteredDescription() {
Chris@0 595 return FieldFilteredMarkup::create(\Drupal::token()->replace($this->fieldDefinition->getDescription()));
Chris@0 596 }
Chris@0 597
Chris@0 598 }