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 | * @author Alexey Tatarinov <[email protected]> |
||
4 | * @link https://github.com/shogodev/argilla/ |
||
5 | * @copyright Copyright © 2003-2014 Shogo |
||
6 | * @license http://argilla.ru/LICENSE |
||
7 | * @package frontend.components.collection |
||
8 | */ |
||
9 | class FCollectionUI extends FCollection |
||
10 | { |
||
11 | /** |
||
12 | * Добавить элемент в коллекцию только 1 раз |
||
13 | */ |
||
14 | const BT_ADD_ONCE = 1; |
||
15 | |||
16 | /** |
||
17 | * Добавлять элемент в коллекцию всегда |
||
18 | */ |
||
19 | const BT_ADD_ALWAYS = 2; |
||
20 | |||
21 | /** |
||
22 | * Работа в режиме переключателя |
||
23 | */ |
||
24 | const BT_TOGGLE = 3; |
||
25 | |||
26 | public $ajaxUrl; |
||
27 | |||
28 | public $addButtonAjaxUrl; |
||
29 | |||
30 | public $addThroughButtonAjaxUrl = array('product/addThroughPopup'); |
||
31 | |||
32 | public $ajaxUpdate = array(); |
||
33 | |||
34 | public $beforeAjaxScript = array(); |
||
35 | |||
36 | public $afterAjaxScript = array(); |
||
37 | |||
38 | protected $classAdd = 'to-{keyCollection}'; |
||
39 | |||
40 | protected $classAlreadyInCollection = 'already-in-{keyCollection}'; |
||
41 | |||
42 | protected $classRemove = 'remove-{keyCollection}'; |
||
43 | |||
44 | protected $classAmount = 'amount-{keyCollection}'; |
||
45 | |||
46 | protected $classChangeAmount = 'change-amount-{keyCollection}'; |
||
47 | |||
48 | protected $classAddThroughPopupButton = 'add-through-popup-{keyCollection}'; |
||
49 | |||
50 | protected $popupAutofocusFieldId = 'autofocus-field'; |
||
51 | |||
52 | public function getSum() |
||
53 | { |
||
54 | $sum = 0; |
||
55 | |||
56 | foreach($this as $element) |
||
57 | { |
||
58 | $sum += $element->getSum(); |
||
59 | } |
||
60 | |||
61 | return $sum; |
||
62 | } |
||
63 | |||
64 | public function getSumTotal() |
||
65 | { |
||
66 | return $this->getSum(); |
||
67 | } |
||
68 | |||
69 | /** |
||
70 | * @param string|array $elements - id элемента или масив id |
||
71 | * |
||
72 | * @return $this |
||
73 | */ |
||
74 | 7 | public function ajaxUpdate($elements) |
|
75 | { |
||
76 | 7 | $elements = is_array($elements) ? $elements : array($elements); |
|
77 | |||
78 | 7 | $this->ajaxUpdate = CMap::mergeArray($this->ajaxUpdate, $elements); |
|
79 | |||
80 | 7 | return $this; |
|
81 | } |
||
82 | |||
83 | public function addBeforeAjaxScript(CJavaScriptExpression $script) |
||
84 | { |
||
85 | $this->beforeAjaxScript = CMap::mergeArray($this->beforeAjaxScript, array($script)); |
||
86 | } |
||
87 | |||
88 | 7 | public function addAfterAjaxScript(CJavaScriptExpression $script) |
|
89 | { |
||
90 | 7 | $this->afterAjaxScript = CMap::mergeArray($this->afterAjaxScript, array($script)); |
|
91 | 7 | } |
|
92 | |||
93 | /** |
||
94 | * Строит кнопку добавления в коллекцию. |
||
95 | * Пример: |
||
96 | * <pre> |
||
97 | * echo $this->basket->buttonAdd($model, 'Добавить в корзину', array('class' => 'btn, 'data-amount' => 1)) |
||
98 | * echo $this->basket->buttonAdd(array('id' => 1, 'type' => 'product'), array('Добавить в корзину', 'В корзине'), array('class' => 'btn), FCollectionUI::BT_ADD_ONCE) |
||
99 | * </pre> |
||
100 | * @param array|FCollectionElementBehavior|CActiveRecord $data |
||
101 | * @param array|string $text |
||
102 | * @param array $htmlOptions |
||
103 | * @param int $buttonType тип кнопки (может быть: self::BT_ADD_ONCE | self::BT_ADD_ALWAYS | self::BT_TOGGLE). По умодчанию BT_ADD_ALWAYS |
||
104 | * |
||
105 | * @return string |
||
106 | */ |
||
107 | 4 | public function buttonAdd($data, $text = '', $htmlOptions = array(), $buttonType = self::BT_ADD_ALWAYS) |
|
108 | { |
||
109 | 4 | $this->appendHtmlOption($htmlOptions, $this->classAdd); |
|
110 | |||
111 | 4 | return $this->createButtonAdd($data, $text, $htmlOptions, $buttonType); |
|
112 | } |
||
113 | |||
114 | /** |
||
115 | * @param array|FCollectionElementBehavior|CActiveRecord $data |
||
116 | * @param string $text |
||
117 | * @param array $htmlOptions |
||
118 | * @param bool $confirm |
||
119 | * |
||
120 | * @return string |
||
121 | */ |
||
122 | public function buttonRemove($data, $text = '', $htmlOptions = array(), $confirm = true) |
||
123 | { |
||
124 | $preparedData = $this->prepareInputData($data); |
||
125 | |||
126 | $this->appendHtmlOption($htmlOptions, $this->classRemove); |
||
127 | |||
128 | if( $confirm !== false) |
||
129 | $htmlOptions['data-confirm'] = ($confirm === true ? 'true' : CJavaScript::quote($confirm)); |
||
130 | |||
131 | return CHtml::link($text, '#', CMap::mergeArray($preparedData, $htmlOptions)); |
||
132 | } |
||
133 | |||
134 | public function buttonAddThroughPopup($data, $text = '', $htmlOptions = array(), $buttonType = self::BT_ADD_ALWAYS) |
||
135 | { |
||
136 | $this->appendHtmlOption($htmlOptions, $this->classAddThroughPopupButton); |
||
137 | |||
138 | return $this->createButtonAdd($data, $text, $htmlOptions, $buttonType); |
||
139 | } |
||
140 | |||
141 | /** |
||
142 | * Строит input меняющий количество на кнопке добавления в коллекцию. |
||
143 | * Пример: |
||
144 | * <pre> |
||
145 | * echo $this->basket->inputAmountButtonAdd('#button-id', array('class' => 'inp')) |
||
146 | * или |
||
147 | * echo $this->basket->inputAmountButtonAdd('.calculator-popup') |
||
148 | * </pre> |
||
149 | * |
||
150 | * @param string $targetSelector селектор кнопки добавления в коллекцию или селектор блока содержащего кнопку добавления в коллекцию |
||
151 | * @param array $htmlOptions |
||
152 | * @param int $defaultAmount количество по умолчанию |
||
153 | * @param int $step |
||
154 | * |
||
155 | * @return string |
||
156 | */ |
||
157 | public function inputAmountButtonAdd($targetSelector, $htmlOptions = array(), $defaultAmount = 1, $step = 1) |
||
158 | { |
||
159 | $this->appendHtmlOption($htmlOptions, $this->classAmount); |
||
160 | $this->appendHtmlOption($htmlOptions, $targetSelector, 'data-target-selector'); |
||
161 | $this->appendHtmlOption($htmlOptions, '.'.$this->classAdd, 'data-button-selector'); |
||
162 | $this->appendHtmlOption($htmlOptions, $step, 'data-step'); |
||
163 | |||
164 | return CHtml::textField('amount', $defaultAmount, $htmlOptions); |
||
165 | } |
||
166 | |||
167 | /** |
||
168 | * Строит input меняющий количество у элемента с селектором $targetSelector |
||
169 | * |
||
170 | * @param $targetSelector |
||
171 | * @param array $htmlOptions |
||
172 | * @param int $defaultAmount |
||
173 | * @param int $step |
||
174 | * |
||
175 | * @return string |
||
176 | */ |
||
177 | public function inputAmountElement($targetSelector, $htmlOptions = array(), $defaultAmount = 1, $step = 1) |
||
178 | { |
||
179 | $this->appendHtmlOption($htmlOptions, $this->classAmount); |
||
180 | $this->appendHtmlOption($htmlOptions, $targetSelector, 'data-target-selector'); |
||
181 | $this->appendHtmlOption($htmlOptions, $step, 'data-step'); |
||
182 | |||
183 | return CHtml::textField('amount', $defaultAmount, $htmlOptions); |
||
184 | } |
||
185 | |||
186 | /** |
||
187 | * Инпут смены количества в коллекции |
||
188 | * |
||
189 | * @param $element - элемент коллекции |
||
190 | * @param array $htmlOptions |
||
191 | * @param int $step |
||
192 | * |
||
193 | * @return string |
||
194 | */ |
||
195 | public function inputAmountCollection($element, $htmlOptions = array(), $step = 1) |
||
196 | { |
||
197 | $this->appendHtmlOption($htmlOptions, $this->classChangeAmount); |
||
198 | $this->appendHtmlOption($htmlOptions, $step, 'data-step'); |
||
199 | |||
200 | if( empty($htmlOptions['data-index']) ) |
||
201 | $htmlOptions['data-index'] = $element->collectionIndex; |
||
202 | |||
203 | return CHtml::textField('amount', $element->collectionAmount * $step, $htmlOptions); |
||
204 | } |
||
205 | |||
206 | 4 | protected function createButtonAdd($data, $text = '', $htmlOptions = array(), $buttonType = self::BT_ADD_ALWAYS) |
|
207 | { |
||
208 | 4 | $preparedData = $this->prepareInputData($data); |
|
209 | 4 | $isInCollection = $this->isInCollection($preparedData['data-type'], $preparedData['data-id']); |
|
210 | |||
211 | switch ($buttonType) |
||
212 | { |
||
213 | 4 | case self::BT_ADD_ONCE: |
|
214 | 1 | $this->appendHtmlOption($htmlOptions, $isInCollection ? 1 : 0, 'data-do-not-add'); |
|
215 | 1 | break; |
|
216 | |||
217 | 3 | case self::BT_TOGGLE: |
|
218 | 1 | $this->appendHtmlOption($htmlOptions, $isInCollection ? 1 : 0, 'data-do-not-add'); |
|
219 | 1 | $this->appendHtmlOption($htmlOptions, $isInCollection ? 1 : 0, 'data-remove-toggle'); |
|
220 | 1 | break; |
|
221 | } |
||
222 | |||
223 | if( $isInCollection ) |
||
224 | 4 | { |
|
225 | 3 | $this->appendHtmlOption($htmlOptions, $this->classAlreadyInCollection); |
|
226 | 3 | } |
|
227 | |||
228 | 4 | return CHtml::link($this->prepareText($text, $isInCollection, $htmlOptions), '#', CMap::mergeArray($preparedData, $htmlOptions)); |
|
229 | } |
||
230 | |||
231 | /** |
||
232 | * @param array|CModel|FCollectionElementBehavior $data |
||
233 | * |
||
234 | * @return array |
||
235 | */ |
||
236 | 4 | public function prepareInputData($data) |
|
237 | { |
||
238 | 4 | $preparedData = array(); |
|
239 | |||
240 | 4 | if( $data instanceof CModel ) |
|
0 ignored issues
–
show
|
|||
241 | 4 | { |
|
242 | 1 | $preparedData['data-id'] = $data->primaryKey; |
|
243 | 1 | $preparedData['data-type'] = Utils::toSnakeCase(get_class($data)); |
|
244 | |||
245 | 1 | if( isset($data->collectionIndex) ) |
|
246 | 1 | $preparedData['data-index'] = $data->collectionIndex; |
|
247 | |||
248 | 1 | if( $items = $data->defaultCollectionItems() ) |
|
249 | 1 | $preparedData['data-items'] = CJSON::encode($items); |
|
250 | 1 | } |
|
251 | else |
||
252 | { |
||
253 | 4 | foreach($data as $key => $item) |
|
254 | { |
||
255 | 4 | if( !preg_match('/^data-(.*)/', $key) ) |
|
256 | 4 | $preparedData['data-'.$key] = $item; |
|
257 | else |
||
258 | 1 | $preparedData[$key] = $item; |
|
259 | 4 | } |
|
260 | } |
||
261 | |||
262 | 4 | return $preparedData; |
|
263 | } |
||
264 | |||
265 | /** |
||
266 | * @param string|array $text |
||
267 | * @param $inCollection |
||
268 | * @param $htmlOptions |
||
269 | * |
||
270 | * @return array|mixed |
||
271 | */ |
||
272 | 4 | protected function prepareText($text, $inCollection, &$htmlOptions) |
|
273 | { |
||
274 | 4 | if( is_array($text) ) |
|
275 | 4 | { |
|
276 | 3 | $linkText = Arr::reset($text); |
|
277 | 3 | $this->appendHtmlOption($htmlOptions, htmlspecialchars(Arr::get($text, 0)), 'data-not-added-text'); |
|
278 | 3 | $this->appendHtmlOption($htmlOptions, htmlspecialchars(Arr::get($text, 1)), 'data-added-text'); |
|
279 | 3 | } |
|
280 | else |
||
281 | 1 | $linkText = $text; |
|
282 | |||
283 | if( $inCollection ) |
||
284 | 4 | { |
|
285 | 3 | if( is_array($text) ) |
|
286 | 3 | $linkText = is_array($text) ? Arr::get($text, 1) : $text; |
|
287 | 3 | } |
|
288 | |||
289 | 4 | return $linkText; |
|
290 | } |
||
291 | |||
292 | 11 | protected function init() |
|
293 | { |
||
294 | 11 | $this->replaceKeyCollection(); |
|
295 | |||
296 | 11 | Yii::app()->getClientScript()->attachEventHandler('onBeforeRenderClientScript', function($event){ |
|
0 ignored issues
–
show
|
|||
297 | 7 | $this->registerScripts(); |
|
298 | 11 | }); |
|
299 | 11 | } |
|
300 | |||
301 | 7 | protected function registerScripts() |
|
302 | { |
||
303 | $settings = array( |
||
304 | 7 | 'ajaxUrl' => $this->ajaxUrl, |
|
305 | 7 | 'ajaxUpdate' => $this->ajaxUpdate, |
|
306 | 7 | 'beforeAjaxScript' => $this->buildBeforeAjaxScript(), |
|
307 | 7 | 'afterAjaxScript' => $this->buildAfterAjaxScript(), |
|
308 | 7 | ); |
|
309 | |||
310 | 7 | $script = "$.fn.collection('{$this->keyCollection}', ".CJavaScript::encode($settings).");"; |
|
311 | 7 | Yii::app()->clientScript->registerScript('initScript#'.Utils::ucfirst($this->keyCollection), $script, CClientScript::POS_END); |
|
312 | |||
313 | 7 | $this->registerScriptButtonAdd(); |
|
314 | 7 | $this->registerScriptButtonRemove(); |
|
315 | 7 | $this->registerScriptInputAmountButton(); |
|
316 | 7 | $this->registerScriptInputAmountCollection(); |
|
317 | 7 | $this->registerScriptButtonAddThroughPopup(); |
|
318 | 7 | } |
|
319 | |||
320 | 7 | protected function registerScriptButtonAdd() |
|
321 | { |
||
322 | 7 | $this->registerScript("$('body').on('click', '.{$this->classAdd}', function(e){ |
|
323 | e.preventDefault(); |
||
324 | |||
325 | if( $(this).data('do-not-add') == 1 || $(this).data('remove-toggle') == 1 ) |
||
326 | return; |
||
327 | |||
328 | 7 | var classAlreadyInCollection = '{$this->classAlreadyInCollection}'; |
|
329 | 7 | var collection = $.fn.collection('{$this->keyCollection}'); |
|
330 | |||
331 | collection.send({ |
||
332 | 'action' : 'add', |
||
333 | 'element' : $(this), |
||
334 | 'data' : $(this).data(), |
||
335 | 7 | 'url' : '{$this->addButtonAjaxUrl}', |
|
336 | 'afterAjaxScript' : function(element, data, action, response) { |
||
337 | var elements = $.extend( |
||
338 | {}, |
||
339 | 7 | collection.getElementsByData(data, '.{$this->classAdd}'), |
|
340 | 7 | collection.getElementsByData(data, '.{$this->classAddThroughPopupButton}') |
|
341 | ); |
||
342 | if( elements.length > 0 ) |
||
343 | { |
||
344 | elements.each(function () { |
||
345 | var e = $(this); |
||
346 | |||
347 | if( e.hasClass(classAlreadyInCollection) ) |
||
348 | return; |
||
349 | |||
350 | if( !e.hasClass(classAlreadyInCollection) ) |
||
351 | e.addClass(classAlreadyInCollection); |
||
352 | |||
353 | if( e.data('do-not-add') == 0 ) |
||
354 | e.data('do-not-add', 1); |
||
355 | |||
356 | if( e.data('remove-toggle') == 0 ) |
||
357 | e.data('remove-toggle', 1); |
||
358 | |||
359 | if( e.data('added-text') ) |
||
360 | e.html(e.data('added-text')); |
||
361 | }); |
||
362 | } |
||
363 | } |
||
364 | }); |
||
365 | 7 | });"); |
|
366 | 7 | } |
|
367 | |||
368 | 7 | protected function registerScriptButtonRemove() |
|
369 | { |
||
370 | 7 | $this->registerScript("$('body, .{$this->classRemove}').on('click', '.{$this->classRemove}, .{$this->classAdd}[data-remove-toggle], .{$this->classAddThroughPopupButton}[data-remove-toggle]', function(e){ |
|
371 | e.preventDefault(); |
||
372 | |||
373 | if( $(this).data('remove-toggle') == 0 ) |
||
374 | return; |
||
375 | |||
376 | var self = this; |
||
377 | |||
378 | var makeAction = function() |
||
379 | { |
||
380 | 7 | var classAlreadyInCollection = '{$this->classAlreadyInCollection}'; |
|
381 | 7 | var collection = $.fn.collection('{$this->keyCollection}'); |
|
382 | |||
383 | collection.send({ |
||
384 | 'element' : $(self), |
||
385 | 'action' : 'remove', |
||
386 | 'data' : $(self).data(), |
||
387 | 'afterAjaxScript' : function(element, data, action, response) { |
||
388 | var elements = $.extend( |
||
389 | {}, |
||
390 | 7 | collection.getElementsByData(data, '.{$this->classAdd}'), |
|
391 | 7 | collection.getElementsByData(data, '.{$this->classAddThroughPopupButton}') |
|
392 | ); |
||
393 | if( elements.length > 0 ) |
||
394 | { |
||
395 | elements.each(function () { |
||
396 | var e = $(this); |
||
397 | |||
398 | if( !e.hasClass(classAlreadyInCollection) ) |
||
399 | return; |
||
400 | |||
401 | if( e.hasClass(classAlreadyInCollection) ) |
||
402 | e.removeClass(classAlreadyInCollection); |
||
403 | |||
404 | if( e.data('do-not-add') == 1 ) |
||
405 | e.data('do-not-add', 0); |
||
406 | |||
407 | if( e.data('remove-toggle') == 1 ) |
||
408 | e.data('remove-toggle', 0); |
||
409 | |||
410 | if( e.data('not-added-text') ) |
||
411 | e.html(e.data('not-added-text')); |
||
412 | }); |
||
413 | } |
||
414 | } |
||
415 | }); |
||
416 | } |
||
417 | |||
418 | var confirmValue = $(this).data('confirm'); |
||
419 | |||
420 | if( confirmValue !== undefined ) |
||
421 | { |
||
422 | alertify.confirm(confirmValue === true ? 'Вы уверены?' : confirmValue, function(answer) { |
||
423 | if( answer ) |
||
424 | { |
||
425 | makeAction(); |
||
426 | } |
||
427 | }); |
||
428 | } |
||
429 | else |
||
430 | { |
||
431 | makeAction(); |
||
432 | } |
||
433 | 7 | });"); |
|
434 | 7 | } |
|
435 | |||
436 | 7 | protected function registerScriptButtonAddThroughPopup() |
|
437 | { |
||
438 | 7 | $url = is_array($this->addThroughButtonAjaxUrl) ? CHtml::normalizeUrl($this->addThroughButtonAjaxUrl) : $this->addThroughButtonAjaxUrl; |
|
439 | |||
440 | 7 | $this->registerScript("$(document.body).on('click', '.{$this->classAddThroughPopupButton}', function(e){ |
|
441 | e.preventDefault(); |
||
442 | |||
443 | if( $(this).data('do-not-add') == 1 || $(this).data('remove-toggle') == 1 ) return; |
||
444 | |||
445 | $('.forwardElement').removeClass('forwardElement'); |
||
446 | $(this).addClass('forwardElement'); |
||
447 | |||
448 | 7 | $.post('{$url}', {'id' : $(this).data('id')}, function(resp) { |
|
449 | var popup = $('#add-through-popup'); |
||
450 | popup.find('.add-through-popup-block').replaceWith('<div class=\"add-through-popup-block\">' + resp + '</div>'); |
||
451 | $.overlayLoader(true, popup); |
||
452 | setTimeout(function() { |
||
453 | 7 | popup.find('#{$this->popupAutofocusFieldId}').focus(); |
|
454 | }, 300); |
||
455 | }, 'html'); |
||
456 | 7 | });"); |
|
457 | 7 | } |
|
458 | |||
459 | 7 | protected function registerScriptInputAmountButton() |
|
460 | { |
||
461 | 7 | $this->registerScript("$('body').on('change', '.{$this->classAmount}', function(e){ |
|
462 | e.preventDefault(); |
||
463 | var targetSelector = $(this).data('target-selector'); |
||
464 | var buttonSelector = $(this).data('button-selector'); |
||
465 | if( buttonSelector ) |
||
466 | { |
||
467 | var target = $(targetSelector + buttonSelector).length > 0 ? $(targetSelector + buttonSelector) : $(this).closest(targetSelector).find(buttonSelector); |
||
468 | } |
||
469 | else |
||
470 | { |
||
471 | var target = $(targetSelector); |
||
472 | } |
||
473 | |||
474 | target.data('amount', $(this).val() / $(this).data('step')).change(); |
||
475 | 7 | });"); |
|
476 | 7 | } |
|
477 | |||
478 | 7 | protected function registerScriptInputAmountCollection() |
|
479 | { |
||
480 | 7 | $this->registerScript("$('body').on('change', '.{$this->classChangeAmount}', function(e){ |
|
481 | e.preventDefault(); |
||
482 | var data = $(this).data(); |
||
483 | data['amount'] = $(this).val() / $(this).data('step'); |
||
484 | |||
485 | 7 | $.fn.collection('{$this->keyCollection}').send({ |
|
486 | 'action' : 'changeAmount', |
||
487 | 'data' : data, |
||
488 | }); |
||
489 | 7 | });"); |
|
490 | 7 | } |
|
491 | |||
492 | 7 | protected function buildBeforeAjaxScript() |
|
493 | { |
||
494 | 7 | return new CJavaScriptExpression("function(element, data, action){". |
|
495 | 7 | implode("\n\r", $this->beforeAjaxScript). |
|
496 | "return true; |
||
497 | 7 | }"); |
|
498 | } |
||
499 | |||
500 | 7 | protected function buildAfterAjaxScript() |
|
501 | { |
||
502 | 7 | return new CJavaScriptExpression("function(element, data, action, response){".implode("\n\r", $this->afterAjaxScript)."}"); |
|
503 | } |
||
504 | |||
505 | 11 | protected function replaceKeyCollection() |
|
506 | { |
||
507 | 11 | foreach(get_object_vars($this) as $name => $value) |
|
508 | { |
||
509 | 11 | if( is_string($value) ) |
|
510 | 11 | $this->{$name} = strtr($value, array('{keyCollection}' => $this->keyCollection)); |
|
511 | 11 | } |
|
512 | 11 | } |
|
513 | |||
514 | /** |
||
515 | * @param $htmlOptions |
||
516 | * @param $value |
||
517 | * @param string $key - по умолчанию 'class' |
||
518 | */ |
||
519 | 11 | protected function appendHtmlOption(&$htmlOptions, $value, $key = 'class') |
|
520 | { |
||
521 | 11 | $htmlOptions[$key] = !isset($htmlOptions[$key]) ? $value : $htmlOptions[$key].' '.$value; |
|
522 | 11 | } |
|
523 | |||
524 | /** |
||
525 | * @param $script |
||
526 | * @param $position |
||
527 | */ |
||
528 | 7 | protected function registerScript($script, $position = CClientScript::POS_END) |
|
529 | { |
||
530 | 7 | $calls = debug_backtrace(0, 2); |
|
531 | 7 | Yii::app()->clientScript->registerScript($calls[1]['function'].'#'.$this->keyCollection, $script, $position); |
|
532 | } |
||
533 | } |
This error could be the result of:
1. Missing dependencies
PHP Analyzer uses your
composer.json
file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects thecomposer.json
to be in the root folder of your repository.Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the
require
orrequire-dev
section?2. Missing use statement
PHP does not complain about undefined classes in
ìnstanceof
checks. For example, the following PHP code will work perfectly fine:If you have not tested against this specific condition, such errors might go unnoticed.