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