Completed
Push — 8.x-1.x ( fc4997...0b3da9 )
by Janez
01:48
created

EntityBrowserElement::processEntityBrowser()   B

Complexity

Conditions 5
Paths 12

Size

Total Lines 73
Code Lines 44

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 44
c 1
b 0
f 0
nc 12
nop 3
dl 0
loc 73
rs 8.5021

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Drupal\entity_browser\Element;
4
5
use Drupal\Component\Utility\Html;
6
use Drupal\Core\Form\FormStateInterface;
7
use Drupal\Core\Render\Element\FormElement;
8
use Drupal\entity_browser\Entity\EntityBrowser;
9
use Drupal\Core\Entity\EntityInterface;
10
11
/**
12
 * Provides an Entity Browser form element.
13
 *
14
 * Properties:
15
 * - #entity_browser: Entity browser or ID of the Entity browser to be used.
16
 * - #cardinality: (optional) Maximum number of items that are expected from
17
 *     the entity browser. Unlimited by default.
18
 * - #default_value: (optional) Array of entities that Entity browser should be
19
 *     initialized with. It's only applicable when edit selection mode is used.
20
 * - #entity_browser_validators: (optional) Array of validators that are to be
21
 *     passed to the entity browser. Array keys are plugin IDs and array values
22
 *     are plugin configuration values. Cardinality validator will be set
23
 *     automatically.
24
 * - #selection_mode: (optional) Determines how selection in entity browser will
25
 *     be handled. Will selection be appended/prepended or it will be replaced
26
 *     in case of editing. Defaults to append.
27
 * - #widget_context: (optional) Widget configuration overrides which enable
28
 *     use cases where the instance of a widget needs awareness of contextual
29
 *     configuration like field settings.
30
 *
31
 * Return value will be an array of selected entities, which will appear under
32
 * 'entities' key on the root level of the element's values in the form state.
33
 *
34
 * @FormElement("entity_browser")
35
 */
36
class EntityBrowserElement extends FormElement {
37
38
  /**
39
   * Indicating an entity browser can return an unlimited number of values.
40
   *
41
   * Note: When entity browser is used in Fields, cardinality is directly
42
   * propagated from Field settings, that's why this constant should be equal to
43
   * FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED.
44
   */
45
  const CARDINALITY_UNLIMITED = -1;
46
47
  /**
48
   * Selection from entity browser will be appended to existing list.
49
   *
50
   * When this selection mode is used, then entity browser will not be
51
   * populated with existing selection. Preselected list will be empty.
52
   *
53
   * Note: This option is also used by "js/entity_browser.common.js".
54
   */
55
  const SELECTION_MODE_APPEND = 'selection_append';
56
57
  /**
58
   * Selection from entity browser will be prepended to existing list.
59
   *
60
   * When this selection mode is used, then entity browser will not be
61
   * populated with existing selection. Preselected list will be empty.
62
   *
63
   * Note: This option is also used by "js/entity_browser.common.js".
64
   */
65
  const SELECTION_MODE_PREPEND = 'selection_prepend';
66
67
  /**
68
   * Selection from entity browser will replace existing.
69
   *
70
   * When this selection mode is used, then entity browser will be populated
71
   * with existing selection and returned selected list will replace existing
72
   * selection. This option requires entity browser selection display with
73
   * preselection support.
74
   *
75
   * Note: This option is also used by "js/entity_browser.common.js".
76
   */
77
  const SELECTION_MODE_EDIT = 'selection_edit';
78
79
  /**
80
   * {@inheritdoc}
81
   */
82
  public function getInfo() {
83
    $class = get_class($this);
84
    return [
85
      '#input' => TRUE,
86
      '#tree' => TRUE,
87
      '#cardinality' => static::CARDINALITY_UNLIMITED,
88
      '#selection_mode' => static::SELECTION_MODE_APPEND,
89
      '#process' => [[$class, 'processEntityBrowser']],
90
      '#default_value' => [],
91
      '#entity_browser_validators' => [],
92
      '#widget_context' => [],
93
      '#attached' => ['library' => ['entity_browser/common']],
94
    ];
95
  }
96
97
  /**
98
   * Get selection mode options.
99
   *
100
   * @return array
101
   *   Selection mode options.
102
   */
103
  public static function getSelectionModeOptions() {
104
    return [
105
      static::SELECTION_MODE_APPEND => t('Append to selection'),
106
      static::SELECTION_MODE_PREPEND => t('Prepend selection'),
107
      static::SELECTION_MODE_EDIT => t('Edit selection'),
108
    ];
109
  }
110
111
  /**
112
   * Check whether entity browser should be available for selection of entities.
113
   *
114
   * @param string $selection_mode
115
   *   Used selection mode.
116
   * @param int $cardinality
117
   *   Used cardinality.
118
   * @param int $preselection_size
119
   *   Preseletion size, if it's available.
120
   *
121
   * @return bool
122
   *   Returns positive if entity browser can be used.
123
   */
124
  public static function isEntityBrowserAvailable($selection_mode, $cardinality, $preselection_size) {
125
    if ($selection_mode == static::SELECTION_MODE_EDIT) {
126
      return TRUE;
127
    }
128
129
    $cardinality_exceeded =
130
      $cardinality != static::CARDINALITY_UNLIMITED
131
      && $preselection_size >= $cardinality;
132
133
    return !$cardinality_exceeded;
134
  }
135
136
  /**
137
   * Render API callback: Processes the entity browser element.
138
   */
139
  public static function processEntityBrowser(&$element, FormStateInterface $form_state, &$complete_form) {
140
    /** @var \Drupal\entity_browser\EntityBrowserInterface $entity_browser */
141
    if (is_string($element['#entity_browser'])) {
142
      $entity_browser = EntityBrowser::load($element['#entity_browser']);
143
    }
144
    else {
145
      $entity_browser = $element['#entity_browser'];
146
    }
147
148
    // Propagate selection if edit selection mode is used.
149
    $entity_browser_preselected_entities = [];
150
    if ($element['#selection_mode'] === static::SELECTION_MODE_EDIT) {
151
      $entity_browser->getSelectionDisplay()->checkPreselectionSupport();
152
153
      $entity_browser_preselected_entities = $element['#default_value'];
154
    }
155
156
    $default_value = implode(' ', array_map(
157
      function (EntityInterface $item) {
158
        return $item->getEntityTypeId() . ':' . $item->id();
159
      },
160
      $entity_browser_preselected_entities
161
    ));
162
    $validators = array_merge(
163
      $element['#entity_browser_validators'],
164
      ['cardinality' => ['cardinality' => $element['#cardinality']]]
165
    );
166
167
    // Display error message if the entity browser was not found.
168
    if (!$entity_browser) {
169
      $element['entity_browser'] = [
170
        '#type' => 'markup',
171
        '#markup' => is_string($element['#entity_browser']) ? $this->t('Entity browser @browser not found.', ['@browser' => $element['#entity_browser']]) : $this->t('Entity browser not found.'),
0 ignored issues
show
Bug introduced by
The variable $this does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
172
      ];
173
    }
174
    // Display entity_browser
175
    else {
176
      $display = $entity_browser->getDisplay();
177
      $display->setUuid(sha1(implode('-', array_merge([$complete_form['#build_id']], $element['#parents']))));
178
      $element['entity_browser'] = [
179
        '#eb_parents' => array_merge($element['#parents'], ['entity_browser']),
180
      ];
181
      $element['entity_browser'] = $display->displayEntityBrowser(
182
        $element['entity_browser'],
183
        $form_state,
184
        $complete_form,
185
        [
186
          'validators' => $validators,
187
          'selected_entities' => $entity_browser_preselected_entities,
188
          'widget_context' => $element['#widget_context'],
189
        ]
190
      );
191
192
      $hidden_id = Html::getUniqueId($element['#id'] . '-target');
193
      $element['entity_ids'] = [
194
        '#type' => 'hidden',
195
        '#id' => $hidden_id,
196
        // We need to repeat ID here as it is otherwise skipped when rendering.
197
        '#attributes' => ['id' => $hidden_id, 'class' => ['eb-target']],
198
        '#default_value' => $default_value,
199
      ];
200
201
      $element['#attached']['drupalSettings']['entity_browser'] = [
202
        $entity_browser->getDisplay()->getUuid() => [
203
          'cardinality' => $element['#cardinality'],
204
          'selection_mode' => $element['#selection_mode'],
205
          'selector' => '#' . $hidden_id,
206
        ],
207
      ];
208
    }
209
210
    return $element;
211
  }
212
213
  /**
214
   * {@inheritdoc}
215
   */
216
  public static function valueCallback(&$element, $input, FormStateInterface $form_state) {
217
    if ($input === FALSE) {
218
      return $element['#default_value'] ?: [];
219
    }
220
221
    $entities = [];
222
    if ($input['entity_ids']) {
223
      $entities = static::processEntityIds($input['entity_ids']);
224
    }
225
226
    return ['entities' => $entities];
227
  }
228
229
  /**
230
   * Processes entity IDs and gets array of loaded entities.
231
   *
232
   * @param array|string $ids
233
   *   Processes entity IDs as they are returned from the entity browser. They
234
   *   are in [entity_type_id]:[entity_id] form. Array of IDs or a
235
   *   space-delimited string is supported.
236
   *
237
   * @return \Drupal\Core\Entity\EntityInterface[]
238
   *   Array of entity objects.
239
   */
240
  public static function processEntityIds($ids) {
241
    if (!is_array($ids)) {
242
      $ids = array_filter(explode(' ', $ids));
243
    }
244
245
    return array_map(
246
      function ($item) {
247
        list($entity_type, $entity_id) = explode(':', $item);
248
        return \Drupal::entityTypeManager()->getStorage($entity_type)->load($entity_id);
249
      },
250
      $ids
251
    );
252
  }
253
254
  /**
255
   * Processes entity IDs and gets array of loaded entities.
256
   *
257
   * @param string $id
258
   *   Processes entity ID as it is returned from the entity browser. ID should
259
   *   be in [entity_type_id]:[entity_id] form.
260
   *
261
   * @return \Drupal\Core\Entity\EntityInterface
262
   *   Entity object.
263
   */
264
  public static function processEntityId($id) {
265
    $return = static::processEntityIds([$id]);
266
    return current($return);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The expression current($return); of type Drupal\Core\Entity\EntityInterface|false adds false to the return on line 266 which is incompatible with the return type documented by Drupal\entity_browser\El...lement::processEntityId of type Drupal\Core\Entity\EntityInterface. It seems like you forgot to handle an error condition.
Loading history...
267
  }
268
269
}
270