Completed
Pull Request — 8.x-1.x (#117)
by
unknown
04:17
created

WidgetBase::validate()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 14
rs 9.2
cc 4
eloc 8
nc 4
nop 2
1
<?php
2
3
/**
4
 * Contains \Drupal\entity_browser\WidgetBase.
5
 */
6
7
namespace Drupal\entity_browser;
8
9
use Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface;
10
use Drupal\Core\Plugin\PluginBase;
11
use Drupal\Core\Entity\EntityManagerInterface;
12
use Drupal\Core\Form\FormStateInterface;
13
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
14
use Drupal\entity_browser\Events\EntitySelectionEvent;
15
use Drupal\entity_browser\Events\Events;
16
use Symfony\Component\DependencyInjection\ContainerInterface;
17
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
18
use Symfony\Component\HttpFoundation\Request;
19
20
/**
21
 * Base class for widget plugins.
22
 */
23
abstract class WidgetBase extends PluginBase implements WidgetInterface, ContainerFactoryPluginInterface {
24
25
  use PluginConfigurationFormTrait;
26
27
  /**
28
   * Plugin id.
29
   *
30
   * @var string
31
   */
32
  protected $id;
33
34
  /**
35
   * Plugin uuid.
36
   *
37
   * @var string
38
   */
39
  protected $uuid;
40
  /**
41
   * Plugin label.
42
   *
43
   * @var string
44
   */
45
  protected $label;
46
47
  /**
48
   * Plugin weight.
49
   *
50
   * @var int
51
   */
52
  protected $weight;
53
54
  /**
55
   * Event dispatcher service.
56
   *
57
   * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
58
   */
59
  protected $eventDispatcher;
60
61
  /**
62
   * Entity manager service.
63
   *
64
   * @var \Drupal\Core\Entity\EntityManagerInterface
65
   */
66
  protected $entityManager;
67
68
  /**
69
   * The Expirable key value store.
70
   *
71
   * @var \Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface
72
   */
73
  private $keyValue;
74
75
  /**
76
   * The Request object.
77
   *
78
   * @var \Symfony\Component\HttpFoundation\Request
79
   */
80
  private $request;
81
82
  /**
83
   * Constructs widget plugin.
84
   *
85
   * @param array $configuration
86
   *   A configuration array containing information about the plugin instance.
87
   * @param string $plugin_id
88
   *   The plugin_id for the plugin instance.
89
   * @param mixed $plugin_definition
90
   *   The plugin implementation definition.
91
   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
92
   *   Event dispatcher service.
93
   */
94 View Code Duplication
  public function __construct(array $configuration, $plugin_id, $plugin_definition, EventDispatcherInterface $event_dispatcher, EntityManagerInterface $entity_manager, KeyValueStoreExpirableInterface $key_value, Request $request) {
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...
95
    parent::__construct($configuration, $plugin_id, $plugin_definition);
96
    $this->eventDispatcher = $event_dispatcher;
97
    $this->entityManager = $entity_manager;
98
    $this->setConfiguration($configuration);
99
    $this->keyValue = $key_value;
100
    $this->request = $request;
101
  }
102
103
  /**
104
   * {@inheritdoc}
105
   */
106 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...
107
    return new static(
108
      $configuration,
109
      $plugin_id,
110
      $plugin_definition,
111
      $container->get('event_dispatcher'),
112
      $container->get('entity.manager'),
113
      $container->get('keyvalue.expirable')->get('entity_browser'),
114
      $container->get('request_stack')->getCurrentRequest()
115
    );
116
  }
117
118
  /**
119
   * {@inheritdoc}
120
   */
121
  public function defaultConfiguration() {
122
    return [];
123
  }
124
125
  /**
126
   * {@inheritdoc}
127
   */
128
  public function getConfiguration() {
129
    return [
130
      'settings' => array_diff_key(
131
        $this->configuration,
132
        ['entity_browser_id' => 0]
133
      ),
134
      'uuid' => $this->uuid(),
135
      'weight' => $this->getWeight(),
136
      'label' => $this->label(),
137
      'id' => $this->id(),
138
    ];
139
  }
140
141
  /**
142
   * {@inheritdoc}
143
   */
144
  public function setConfiguration(array $configuration) {
145
    $configuration += [
146
      'settings' => [],
147
      'uuid' => '',
148
      'weight' => '',
149
      'label' => '',
150
      'id' => '',
151
    ];
152
153
    $this->configuration = $configuration['settings'] + $this->defaultConfiguration();
154
    $this->label = $configuration['label'];
155
    $this->weight = $configuration['weight'];
156
    $this->uuid = $configuration['uuid'];
157
    $this->id = $configuration['id'];
158
  }
159
160
  /**
161
   * {@inheritdoc}
162
   */
163
  public function calculateDependencies() {
164
    return [];
165
  }
166
167
  /**
168
   * {@inheritdoc}
169
   */
170
  public function id() {
171
    return $this->id;
172
  }
173
174
  /**
175
   * {@inheritdoc}
176
   */
177
  public function uuid() {
178
    return $this->uuid;
179
  }
180
181
  /**
182
   * {@inheritdoc}
183
   */
184
  public function label() {
185
    return $this->label;
186
  }
187
188
  /**
189
   * {@inheritdoc}
190
   */
191
  public function getWeight() {
192
    return $this->weight;
193
  }
194
195
  /**
196
   * {@inheritdoc}
197
   */
198
  public function setWeight($weight) {
199
    $this->weight = $weight;
200
    return $this;
201
  }
202
203
  /**
204
   * {@inheritdoc}
205
   */
206
  public function prepareEntities(FormStateInterface $form_state) {
207
    return [];
208
  }
209
210
  /**
211
   * {@inheritdoc}
212
   */
213
  public function validate(array &$form, FormStateInterface $form_state) {
214
    $trigger = $form_state->getTriggeringElement();
215
216
    if (in_array('submit', $trigger['#array_parents'])) {
217
      $entities = $this->prepareEntities($form_state);
218
      $violations = $this->runWidgetValidators($entities);
219
      if (!empty($violations)) {
220
        /** @var \Symfony\Component\Validator\ConstraintViolationListInterface $violation */
221
        foreach ($violations as $violation) {
222
          $form_state->setError($form['widget']['upload'], $violation->getMessage());
223
        }
224
      }
225
    }
226
  }
227
228
  /**
229
   * {@inheritdoc}
230
   */
231
  public function runWidgetValidators(array $entities, $validators = []) {
232
    // @todo Implement a centralized way to get arguments from path for all widgets?
233
    if ($validators_hash = $this->request->get('validators')) {
234
      $passed_validators = $this->keyValue->get($validators_hash);
235
236
      if (!empty($passed_validators)) {
237
        $validators += $passed_validators;
238
      }
239
    }
240
241
    foreach ($validators as $validator_id => $options) {
242
      /** @var \Drupal\entity_browser\WidgetValidationInterface $widget_validator */
243
      $widget_validator = \Drupal::service('plugin.manager.entity_browser.widget_validation')->createInstance($validator_id, []);
244
    }
245
    return $widget_validator->validate($entities, $options);
0 ignored issues
show
Bug introduced by
The variable $widget_validator does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Bug introduced by
The variable $options seems to be defined by a foreach iteration on line 241. Are you sure the iterator is never empty, otherwise this variable is not defined?

It seems like you are relying on a variable being defined by an iteration:

foreach ($a as $b) {
}

// $b is defined here only if $a has elements, for example if $a is array()
// then $b would not be defined here. To avoid that, we recommend to set a
// default value for $b.


// Better
$b = 0; // or whatever default makes sense in your context
foreach ($a as $b) {
}

// $b is now guaranteed to be defined here.
Loading history...
246
  }
247
248
  /**
249
   * {@inheritdoc}
250
   */
251
  public function submit(array &$element, array &$form, FormStateInterface $form_state) {}
252
253
  /**
254
   * Dispatches event that informs all subscribers about new selected entities.
255
   *
256
   * @param array $entities
257
   *   Array of entities.
258
   */
259
  protected function selectEntities(array $entities, FormStateInterface $form_state) {
260
    $selected_entities = &$form_state->get(['entity_browser', 'selected_entities']);
261
    $selected_entities = array_merge($selected_entities, $entities);
262
263
    $this->eventDispatcher->dispatch(
264
      Events::SELECTED,
265
      new EntitySelectionEvent(
266
        $this->configuration['entity_browser_id'],
267
        $form_state->get(['entity_browser', 'instance_uuid']),
268
        $entities
269
      ));
270
  }
271
272
}
273