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