This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
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']) ? t('Entity browser @browser not found.', ['@browser' => $element['#entity_browser']]) : t('Entity browser not found.'), |
||
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
![]() |
|||
267 | } |
||
268 | |||
269 | } |
||
270 |