Completed
Push — 8.x-1.x ( ae01cf...f588c4 )
by Janez
02:43
created

WidgetBase::label()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
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 View Code Duplication
  public function __construct(array $configuration, $plugin_id, $plugin_definition, EventDispatcherInterface $event_dispatcher, EntityTypeManagerInterface $entity_type_manager, WidgetValidationManager $validation_manager) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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
}
376