Completed
Pull Request — 8.x-1.x (#153)
by
unknown
03:18
created

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