PageRenderTime 41ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/EntityReferenceAutocompleteWidget.php

https://gitlab.com/guillaumev/alkarama
PHP | 195 lines | 133 code | 17 blank | 45 comment | 9 complexity | 9cf22ade35099b7efb0c52692557b83d MD5 | raw file
  1. <?php
  2. namespace Drupal\Core\Field\Plugin\Field\FieldWidget;
  3. use Drupal\Core\Field\FieldItemListInterface;
  4. use Drupal\Core\Field\WidgetBase;
  5. use Drupal\Core\Form\FormStateInterface;
  6. use Drupal\user\EntityOwnerInterface;
  7. use Symfony\Component\Validator\ConstraintViolationInterface;
  8. /**
  9. * Plugin implementation of the 'entity_reference_autocomplete' widget.
  10. *
  11. * @FieldWidget(
  12. * id = "entity_reference_autocomplete",
  13. * label = @Translation("Autocomplete"),
  14. * description = @Translation("An autocomplete text field."),
  15. * field_types = {
  16. * "entity_reference"
  17. * }
  18. * )
  19. */
  20. class EntityReferenceAutocompleteWidget extends WidgetBase {
  21. /**
  22. * {@inheritdoc}
  23. */
  24. public static function defaultSettings() {
  25. return array(
  26. 'match_operator' => 'CONTAINS',
  27. 'size' => '60',
  28. 'placeholder' => '',
  29. ) + parent::defaultSettings();
  30. }
  31. /**
  32. * {@inheritdoc}
  33. */
  34. public function settingsForm(array $form, FormStateInterface $form_state) {
  35. $element['match_operator'] = array(
  36. '#type' => 'radios',
  37. '#title' => t('Autocomplete matching'),
  38. '#default_value' => $this->getSetting('match_operator'),
  39. '#options' => $this->getMatchOperatorOptions(),
  40. '#description' => t('Select the method used to collect autocomplete suggestions. Note that <em>Contains</em> can cause performance issues on sites with thousands of entities.'),
  41. );
  42. $element['size'] = array(
  43. '#type' => 'number',
  44. '#title' => t('Size of textfield'),
  45. '#default_value' => $this->getSetting('size'),
  46. '#min' => 1,
  47. '#required' => TRUE,
  48. );
  49. $element['placeholder'] = array(
  50. '#type' => 'textfield',
  51. '#title' => t('Placeholder'),
  52. '#default_value' => $this->getSetting('placeholder'),
  53. '#description' => t('Text that will be shown inside the field until a value is entered. This hint is usually a sample value or a brief description of the expected format.'),
  54. );
  55. return $element;
  56. }
  57. /**
  58. * {@inheritdoc}
  59. */
  60. public function settingsSummary() {
  61. $summary = array();
  62. $operators = $this->getMatchOperatorOptions();
  63. $summary[] = t('Autocomplete matching: @match_operator', array('@match_operator' => $operators[$this->getSetting('match_operator')]));
  64. $summary[] = t('Textfield size: @size', array('@size' => $this->getSetting('size')));
  65. $placeholder = $this->getSetting('placeholder');
  66. if (!empty($placeholder)) {
  67. $summary[] = t('Placeholder: @placeholder', array('@placeholder' => $placeholder));
  68. }
  69. else {
  70. $summary[] = t('No placeholder');
  71. }
  72. return $summary;
  73. }
  74. /**
  75. * {@inheritdoc}
  76. */
  77. public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
  78. $entity = $items->getEntity();
  79. $referenced_entities = $items->referencedEntities();
  80. // Append the match operation to the selection settings.
  81. $selection_settings = $this->getFieldSetting('handler_settings') + ['match_operator' => $this->getSetting('match_operator')];
  82. $element += array(
  83. '#type' => 'entity_autocomplete',
  84. '#target_type' => $this->getFieldSetting('target_type'),
  85. '#selection_handler' => $this->getFieldSetting('handler'),
  86. '#selection_settings' => $selection_settings,
  87. // Entity reference field items are handling validation themselves via
  88. // the 'ValidReference' constraint.
  89. '#validate_reference' => FALSE,
  90. '#maxlength' => 1024,
  91. '#default_value' => isset($referenced_entities[$delta]) ? $referenced_entities[$delta] : NULL,
  92. '#size' => $this->getSetting('size'),
  93. '#placeholder' => $this->getSetting('placeholder'),
  94. );
  95. if ($this->getSelectionHandlerSetting('auto_create') && ($bundle = $this->getAutocreateBundle())) {
  96. $element['#autocreate'] = array(
  97. 'bundle' => $bundle,
  98. 'uid' => ($entity instanceof EntityOwnerInterface) ? $entity->getOwnerId() : \Drupal::currentUser()->id()
  99. );
  100. }
  101. return array('target_id' => $element);
  102. }
  103. /**
  104. * {@inheritdoc}
  105. */
  106. public function errorElement(array $element, ConstraintViolationInterface $error, array $form, FormStateInterface $form_state) {
  107. return isset($element['target_id']) ? $element['target_id'] : FALSE;
  108. }
  109. /**
  110. * {@inheritdoc}
  111. */
  112. public function massageFormValues(array $values, array $form, FormStateInterface $form_state) {
  113. foreach ($values as $key => $value) {
  114. // The entity_autocomplete form element returns an array when an entity
  115. // was "autocreated", so we need to move it up a level.
  116. if (is_array($value['target_id'])) {
  117. unset($values[$key]['target_id']);
  118. $values[$key] += $value['target_id'];
  119. }
  120. }
  121. return $values;
  122. }
  123. /**
  124. * Returns the name of the bundle which will be used for autocreated entities.
  125. *
  126. * @return string
  127. * The bundle name.
  128. */
  129. protected function getAutocreateBundle() {
  130. $bundle = NULL;
  131. if ($this->getSelectionHandlerSetting('auto_create') && $target_bundles = $this->getSelectionHandlerSetting('target_bundles')) {
  132. // If there's only one target bundle, use it.
  133. if (count($target_bundles) == 1) {
  134. $bundle = reset($target_bundles);
  135. }
  136. // Otherwise use the target bundle stored in selection handler settings.
  137. elseif (!$bundle = $this->getSelectionHandlerSetting('auto_create_bundle')) {
  138. // If no bundle has been set as auto create target means that there is
  139. // an inconsistency in entity reference field settings.
  140. trigger_error(sprintf(
  141. "The 'Create referenced entities if they don't already exist' option is enabled but a specific destination bundle is not set. You should re-visit and fix the settings of the '%s' (%s) field.",
  142. $this->fieldDefinition->getLabel(),
  143. $this->fieldDefinition->getName()
  144. ), E_USER_WARNING);
  145. }
  146. }
  147. return $bundle;
  148. }
  149. /**
  150. * Returns the value of a setting for the entity reference selection handler.
  151. *
  152. * @param string $setting_name
  153. * The setting name.
  154. *
  155. * @return mixed
  156. * The setting value.
  157. */
  158. protected function getSelectionHandlerSetting($setting_name) {
  159. $settings = $this->getFieldSetting('handler_settings');
  160. return isset($settings[$setting_name]) ? $settings[$setting_name] : NULL;
  161. }
  162. /**
  163. * Returns the options for the match operator.
  164. *
  165. * @return array
  166. * List of options.
  167. */
  168. protected function getMatchOperatorOptions() {
  169. return [
  170. 'STARTS_WITH' => t('Starts with'),
  171. 'CONTAINS' => t('Contains'),
  172. ];
  173. }
  174. }