Updated all the contrib modules to their latest versions.
[yaffs-website] / web / modules / contrib / entity_browser / src / WidgetBase.php
1 <?php
2
3 namespace Drupal\entity_browser;
4
5 use Drupal\Component\Utility\NestedArray;
6 use Drupal\Core\Access\AccessResult;
7 use Drupal\Core\Entity\EntityTypeManagerInterface;
8 use Drupal\Core\Plugin\PluginBase;
9 use Drupal\Core\Form\FormStateInterface;
10 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
11 use Drupal\entity_browser\Events\EntitySelectionEvent;
12 use Drupal\entity_browser\Events\Events;
13 use Symfony\Component\DependencyInjection\ContainerInterface;
14 use Symfony\Component\EventDispatcher\EventDispatcherInterface;
15 use Symfony\Component\Validator\ConstraintViolationList;
16
17 /**
18  * Base class for widget plugins.
19  */
20 abstract class WidgetBase extends PluginBase implements WidgetInterface, ContainerFactoryPluginInterface {
21
22   use PluginConfigurationFormTrait;
23
24   /**
25    * Plugin id.
26    *
27    * @var string
28    */
29   protected $id;
30
31   /**
32    * Plugin uuid.
33    *
34    * @var string
35    */
36   protected $uuid;
37   /**
38    * Plugin label.
39    *
40    * @var string
41    */
42   protected $label;
43
44   /**
45    * Plugin weight.
46    *
47    * @var int
48    */
49   protected $weight;
50
51   /**
52    * Event dispatcher service.
53    *
54    * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
55    */
56   protected $eventDispatcher;
57
58   /**
59    * Entity type manager service.
60    *
61    * @var \Drupal\Core\Entity\EntityTypeManagerInterface
62    */
63   protected $entityTypeManager;
64
65   /**
66    * The Widget Validation Manager service.
67    *
68    * @var \Drupal\entity_browser\WidgetValidationManager
69    */
70   protected $validationManager;
71
72   /**
73    * WidgetBase constructor.
74    *
75    * @param array $configuration
76    *   A configuration array containing information about the plugin instance.
77    * @param string $plugin_id
78    *   The plugin_id for the plugin instance.
79    * @param mixed $plugin_definition
80    *   The plugin implementation definition.
81    * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
82    *   Event dispatcher service.
83    * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
84    *   The entity type manager service.
85    * @param \Drupal\entity_browser\WidgetValidationManager $validation_manager
86    *   The Widget Validation Manager service.
87    */
88   public function __construct(array $configuration, $plugin_id, $plugin_definition, EventDispatcherInterface $event_dispatcher, EntityTypeManagerInterface $entity_type_manager, WidgetValidationManager $validation_manager) {
89     parent::__construct($configuration, $plugin_id, $plugin_definition);
90     $this->eventDispatcher = $event_dispatcher;
91     $this->entityTypeManager = $entity_type_manager;
92     $this->validationManager = $validation_manager;
93     $this->setConfiguration($configuration);
94   }
95
96   /**
97    * {@inheritdoc}
98    */
99   public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
100     return new static(
101       $configuration,
102       $plugin_id,
103       $plugin_definition,
104       $container->get('event_dispatcher'),
105       $container->get('entity_type.manager'),
106       $container->get('plugin.manager.entity_browser.widget_validation')
107     );
108   }
109
110   /**
111    * {@inheritdoc}
112    */
113   public function getForm(array &$original_form, FormStateInterface $form_state, array $additional_widget_parameters) {
114     $form = [];
115
116     if ($form_state->has(['entity_browser', 'widget_context'])) {
117       $this->handleWidgetContext($form_state->get(['entity_browser', 'widget_context']));
118     }
119
120     // Check if widget supports auto select functionality and expose config to
121     // front-end javascript.
122     $autoSelect = FALSE;
123     if ($this->getPluginDefinition()['auto_select']) {
124       $autoSelect = $this->configuration['auto_select'];
125       $form['#attached']['drupalSettings']['entity_browser_widget']['auto_select'] = $autoSelect;
126     }
127
128     // In case of auto select, widget will handle adding entities in JS.
129     if (!$autoSelect) {
130       $form['actions'] = [
131         '#type' => 'actions',
132         'submit' => [
133           '#type' => 'submit',
134           '#value' => $this->configuration['submit_text'],
135           '#eb_widget_main_submit' => TRUE,
136           '#attributes' => ['class' => ['is-entity-browser-submit']],
137           '#button_type' => 'primary',
138         ],
139       ];
140     }
141
142     return $form;
143   }
144
145   /**
146    * {@inheritdoc}
147    */
148   public function defaultConfiguration() {
149     $defaultConfig = [
150       'submit_text' => $this->t('Select entities'),
151     ];
152
153     // If auto select is supported by Widget, append default configuration.
154     if ($this->getPluginDefinition()['auto_select']) {
155       $defaultConfig['auto_select'] = FALSE;
156     }
157
158     return $defaultConfig;
159   }
160
161   /**
162    * {@inheritdoc}
163    */
164   public function getConfiguration() {
165     return [
166       'settings' => array_diff_key(
167         $this->configuration,
168         ['entity_browser_id' => 0]
169       ),
170       'uuid' => $this->uuid(),
171       'weight' => $this->getWeight(),
172       'label' => $this->label(),
173       'id' => $this->id(),
174     ];
175   }
176
177   /**
178    * {@inheritdoc}
179    */
180   public function setConfiguration(array $configuration) {
181     $configuration += [
182       'settings' => [],
183       'uuid' => '',
184       'weight' => '',
185       'label' => '',
186       'id' => '',
187     ];
188
189     $this->configuration = NestedArray::mergeDeep(
190       $this->defaultConfiguration(),
191       $configuration['settings']
192     );
193     $this->label = $configuration['label'];
194     $this->weight = $configuration['weight'];
195     $this->uuid = $configuration['uuid'];
196     $this->id = $configuration['id'];
197   }
198
199   /**
200    * {@inheritdoc}
201    */
202   public function calculateDependencies() {
203     return [];
204   }
205
206   /**
207    * {@inheritdoc}
208    */
209   public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
210     $form['submit_text'] = [
211       '#type' => 'textfield',
212       '#title' => $this->t('Submit button text'),
213       '#default_value' => $this->configuration['submit_text'],
214     ];
215
216     // Allow "auto_select" setting when auto_select is supported by widget.
217     if ($this->getPluginDefinition()['auto_select']) {
218       $form['auto_select'] = [
219         '#type' => 'checkbox',
220         '#title' => $this->t('Automatically submit selection'),
221         '#default_value' => $this->configuration['auto_select'],
222       ];
223     }
224
225     return $form;
226   }
227
228   /**
229    * {@inheritdoc}
230    */
231   public function id() {
232     return $this->id;
233   }
234
235   /**
236    * {@inheritdoc}
237    */
238   public function uuid() {
239     return $this->uuid;
240   }
241
242   /**
243    * {@inheritdoc}
244    */
245   public function label() {
246     return $this->label;
247   }
248
249   /**
250    * {@inheritdoc}
251    */
252   public function setLabel($label) {
253     $this->label = $label;
254     return $this;
255   }
256
257   /**
258    * {@inheritdoc}
259    */
260   public function getWeight() {
261     return $this->weight;
262   }
263
264   /**
265    * {@inheritdoc}
266    */
267   public function setWeight($weight) {
268     $this->weight = $weight;
269     return $this;
270   }
271
272   /**
273    * Prepares the entities without saving them.
274    *
275    * We need this method when we want to validate or perform other operations
276    * before submit.
277    *
278    * @param array $form
279    *   Complete form.
280    * @param \Drupal\Core\Form\FormStateInterface $form_state
281    *   The form state object.
282    *
283    * @return \Drupal\Core\Entity\EntityInterface[]
284    *   Array of entities.
285    */
286   abstract protected function prepareEntities(array $form, FormStateInterface $form_state);
287
288   /**
289    * {@inheritdoc}
290    */
291   public function validate(array &$form, FormStateInterface $form_state) {
292     $entities = $this->prepareEntities($form, $form_state);
293     $validators = $form_state->get(['entity_browser', 'validators']);
294     if ($validators) {
295       $violations = $this->runWidgetValidators($entities, $validators);
296       foreach ($violations as $violation) {
297         $form_state->setError($form['widget'], $violation->getMessage());
298       }
299     }
300   }
301
302   /**
303    * Run widget validators.
304    *
305    * @param array $entities
306    *   Array of entity ids to validate.
307    * @param array $validators
308    *   Array of widget validator ids.
309    *
310    * @return \Symfony\Component\Validator\ConstraintViolationListInterface
311    *   A list of constraint violations. If the list is empty, validation
312    *   succeeded.
313    */
314   protected function runWidgetValidators(array $entities, $validators = []) {
315     $violations = new ConstraintViolationList();
316     foreach ($validators as $validator_id => $options) {
317       /** @var \Drupal\entity_browser\WidgetValidationInterface $widget_validator */
318       $widget_validator = $this->validationManager->createInstance($validator_id, []);
319       if ($widget_validator) {
320         $violations->addAll($widget_validator->validate($entities, $options));
321       }
322     }
323
324     return $violations;
325   }
326
327   /**
328    * {@inheritdoc}
329    */
330   public function submit(array &$element, array &$form, FormStateInterface $form_state) {}
331
332   /**
333    * Dispatches event that informs all subscribers about new selected entities.
334    *
335    * @param array $entities
336    *   Array of entities.
337    */
338   protected function selectEntities(array $entities, FormStateInterface $form_state) {
339     $selected_entities = &$form_state->get(['entity_browser', 'selected_entities']);
340     $selected_entities = array_merge($selected_entities, $entities);
341
342     $this->eventDispatcher->dispatch(
343       Events::SELECTED,
344       new EntitySelectionEvent(
345         $this->configuration['entity_browser_id'],
346         $form_state->get(['entity_browser', 'instance_uuid']),
347         $entities
348       ));
349   }
350
351   /**
352    * {@inheritdoc}
353    */
354   public function requiresJsCommands() {
355     return $this->getPluginDefinition()['auto_select'] && $this->getConfiguration()['settings']['auto_select'];
356   }
357
358   /**
359    * Allow configuration overrides at runtime based on widget context passed to
360    * this widget from the Entity Browser element.
361    *
362    * Widgets can override this method to replace the default behavior of
363    * replacing configuration with widget context if array keys match.
364    *
365    * @param array $widget_context
366    *   The widget context.
367    */
368   protected function handleWidgetContext($widget_context) {
369     foreach ($this->defaultConfiguration() as $key => $value) {
370       if (isset($widget_context[$key]) && isset($this->configuration[$key])) {
371         $this->configuration[$key] = $widget_context[$key];
372       }
373     }
374   }
375
376   /**
377    * {@inheritdoc}
378    */
379   public function access() {
380     return AccessResult::allowed();
381   }
382
383 }