Version 1
[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     // Allow configuration overrides at runtime based on form state to enable
116     // use cases where the instance of a widget may have contextual
117     // configuration like field settings. "widget_context" doesn't have to be
118     // used in this way, if a widget doesn't want its default configuration
119     // overwritten it can not call this method and implement its own logic.
120     foreach ($this->defaultConfiguration() as $key => $value) {
121       if ($form_state->has(['entity_browser', 'widget_context', $key]) && isset($this->configuration[$key])) {
122         $this->configuration[$key] = $form_state->get(['entity_browser', 'widget_context', $key]);
123       }
124     }
125
126     // Check if widget supports auto select functionality and expose config to
127     // front-end javascript.
128     $autoSelect = FALSE;
129     if ($this->getPluginDefinition()['auto_select']) {
130       $autoSelect = $this->configuration['auto_select'];
131       $form['#attached']['drupalSettings']['entity_browser_widget']['auto_select'] = $autoSelect;
132     }
133
134     // In case of auto select, widget will handle adding entities in JS.
135     if (!$autoSelect) {
136       $form['actions'] = [
137         '#type' => 'actions',
138         'submit' => [
139           '#type' => 'submit',
140           '#value' => $this->configuration['submit_text'],
141           '#eb_widget_main_submit' => TRUE,
142           '#attributes' => ['class' => ['is-entity-browser-submit']],
143           '#button_type' => 'primary',
144         ],
145       ];
146     }
147
148     return $form;
149   }
150
151   /**
152    * {@inheritdoc}
153    */
154   public function defaultConfiguration() {
155     $defaultConfig = [
156       'submit_text' => $this->t('Select entities'),
157     ];
158
159     // If auto select is supported by Widget, append default configuration.
160     if ($this->getPluginDefinition()['auto_select']) {
161       $defaultConfig['auto_select'] = FALSE;
162     }
163
164     return $defaultConfig;
165   }
166
167   /**
168    * {@inheritdoc}
169    */
170   public function getConfiguration() {
171     return [
172       'settings' => array_diff_key(
173         $this->configuration,
174         ['entity_browser_id' => 0]
175       ),
176       'uuid' => $this->uuid(),
177       'weight' => $this->getWeight(),
178       'label' => $this->label(),
179       'id' => $this->id(),
180     ];
181   }
182
183   /**
184    * {@inheritdoc}
185    */
186   public function setConfiguration(array $configuration) {
187     $configuration += [
188       'settings' => [],
189       'uuid' => '',
190       'weight' => '',
191       'label' => '',
192       'id' => '',
193     ];
194
195     $this->configuration = NestedArray::mergeDeep(
196       $this->defaultConfiguration(),
197       $configuration['settings']
198     );
199     $this->label = $configuration['label'];
200     $this->weight = $configuration['weight'];
201     $this->uuid = $configuration['uuid'];
202     $this->id = $configuration['id'];
203   }
204
205   /**
206    * {@inheritdoc}
207    */
208   public function calculateDependencies() {
209     return [];
210   }
211
212   /**
213    * {@inheritdoc}
214    */
215   public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
216     $form['submit_text'] = [
217       '#type' => 'textfield',
218       '#title' => $this->t('Submit button text'),
219       '#default_value' => $this->configuration['submit_text'],
220     ];
221
222     // Allow "auto_select" setting when auto_select is supported by widget.
223     if ($this->getPluginDefinition()['auto_select']) {
224       $form['auto_select'] = [
225         '#type' => 'checkbox',
226         '#title' => $this->t('Automatically submit selection'),
227         '#default_value' => $this->configuration['auto_select'],
228       ];
229     }
230
231     return $form;
232   }
233
234   /**
235    * {@inheritdoc}
236    */
237   public function id() {
238     return $this->id;
239   }
240
241   /**
242    * {@inheritdoc}
243    */
244   public function uuid() {
245     return $this->uuid;
246   }
247
248   /**
249    * {@inheritdoc}
250    */
251   public function label() {
252     return $this->label;
253   }
254
255   /**
256    * {@inheritdoc}
257    */
258   public function setLabel($label) {
259     $this->label = $label;
260     return $this;
261   }
262
263   /**
264    * {@inheritdoc}
265    */
266   public function getWeight() {
267     return $this->weight;
268   }
269
270   /**
271    * {@inheritdoc}
272    */
273   public function setWeight($weight) {
274     $this->weight = $weight;
275     return $this;
276   }
277
278   /**
279    * Prepares the entities without saving them.
280    *
281    * We need this method when we want to validate or perform other operations
282    * before submit.
283    *
284    * @param array $form
285    *   Complete form.
286    * @param \Drupal\Core\Form\FormStateInterface $form_state
287    *   The form state object.
288    *
289    * @return \Drupal\Core\Entity\EntityInterface[]
290    *   Array of entities.
291    */
292   abstract protected function prepareEntities(array $form, FormStateInterface $form_state);
293
294   /**
295    * {@inheritdoc}
296    */
297   public function validate(array &$form, FormStateInterface $form_state) {
298     $entities = $this->prepareEntities($form, $form_state);
299     $validators = $form_state->get(['entity_browser', 'validators']);
300     if ($validators) {
301       $violations = $this->runWidgetValidators($entities, $validators);
302       foreach ($violations as $violation) {
303         $form_state->setError($form['widget'], $violation->getMessage());
304       }
305     }
306   }
307
308   /**
309    * Run widget validators.
310    *
311    * @param array $entities
312    *   Array of entity ids to validate.
313    * @param array $validators
314    *   Array of widget validator ids.
315    *
316    * @return \Symfony\Component\Validator\ConstraintViolationListInterface
317    *   A list of constraint violations. If the list is empty, validation
318    *   succeeded.
319    */
320   protected function runWidgetValidators(array $entities, $validators = []) {
321     $violations = new ConstraintViolationList();
322     foreach ($validators as $validator_id => $options) {
323       /** @var \Drupal\entity_browser\WidgetValidationInterface $widget_validator */
324       $widget_validator = $this->validationManager->createInstance($validator_id, []);
325       if ($widget_validator) {
326         $violations->addAll($widget_validator->validate($entities, $options));
327       }
328     }
329
330     return $violations;
331   }
332
333   /**
334    * {@inheritdoc}
335    */
336   public function submit(array &$element, array &$form, FormStateInterface $form_state) {}
337
338   /**
339    * Dispatches event that informs all subscribers about new selected entities.
340    *
341    * @param array $entities
342    *   Array of entities.
343    */
344   protected function selectEntities(array $entities, FormStateInterface $form_state) {
345     $selected_entities = &$form_state->get(['entity_browser', 'selected_entities']);
346     $selected_entities = array_merge($selected_entities, $entities);
347
348     $this->eventDispatcher->dispatch(
349       Events::SELECTED,
350       new EntitySelectionEvent(
351         $this->configuration['entity_browser_id'],
352         $form_state->get(['entity_browser', 'instance_uuid']),
353         $entities
354       ));
355   }
356
357   /**
358    * {@inheritdoc}
359    */
360   public function requiresJsCommands() {
361     return $this->getPluginDefinition()['auto_select'] && $this->getConfiguration()['settings']['auto_select'];
362   }
363
364 }