CustomView::getDefaultCvId()   B
last analyzed

Complexity

Conditions 10
Paths 22

Size

Total Lines 28
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 17.8732

Importance

Changes 0
Metric Value
eloc 19
dl 0
loc 28
ccs 8
cts 14
cp 0.5714
rs 7.6666
c 0
b 0
f 0
cc 10
nc 22
nop 0
crap 17.8732

How to fix   Complexity   

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
 * Custom view file.
4
 *
5
 * @package App
6
 *
7
 * @copyright YetiForce S.A.
8
 * @license   YetiForce Public License 6.5 (licenses/LicenseEN.txt or yetiforce.com)
9
 * @author    Mariusz Krzaczkowski <[email protected]>
10
 * @author    Radosław Skrzypczak <[email protected]>
11
 */
12
13
namespace App;
14
15
/**
16
 * Custom view class.
17
 */
18
class CustomView
19
{
20
	const CV_STATUS_DEFAULT = 0;
21
	const CV_STATUS_PRIVATE = 1;
22
	const CV_STATUS_PENDING = 2;
23
	const CV_STATUS_PUBLIC = 3;
24
	const CV_STATUS_SYSTEM = 4;
25
26
	/**
27 3
	 * Do we have multiple ids.
28
	 *
29 3
	 * @param string $cvId (comma separated id list or one id)
30
	 *
31
	 * @return bool
32
	 */
33
	public static function isMultiViewId($cvId)
34
	{
35
		return false !== strpos($cvId, ',');
36
	}
37
38
	/**
39
	 * Function to get all the date filter type informations.
40
	 *
41
	 * @return array
42
	 */
43
	public static function getDateFilterTypes()
44
	{
45
		$dateFilters = Condition::DATE_OPERATORS;
46
		foreach (array_keys($dateFilters) as $filterType) {
47
			$dateValues = \DateTimeRange::getDateRangeByType($filterType);
48
			$dateFilters[$filterType]['startdate'] = $dateValues[0];
49
			$dateFilters[$filterType]['enddate'] = $dateValues[1];
50
		}
51
		return $dateFilters;
52
	}
53
54
	/**
55
	 * Get current page.
56
	 *
57
	 * @param string     $moduleName
58
	 * @param int|string $viewId
59
	 *
60
	 * @return int
61
	 */
62
	public static function getCurrentPage($moduleName, $viewId)
63
	{
64
		if (!empty($_SESSION['lvs'][$moduleName][$viewId]['start'])) {
65
			return $_SESSION['lvs'][$moduleName][$viewId]['start'];
66
		}
67
		return 1;
68
	}
69
70
	/**
71
	 * Set current page.
72
	 *
73
	 * @param string     $moduleName
74
	 * @param int|string $viewId
75
	 * @param int        $start
76
	 */
77
	public static function setCurrentPage($moduleName, $viewId, $start)
78
	{
79
		if (empty($start)) {
80
			unset($_SESSION['lvs'][$moduleName][$viewId]['start']);
81
		} else {
82
			$_SESSION['lvs'][$moduleName][$viewId]['start'] = $start;
83
		}
84
	}
85
86
	/**
87
	 * Function that sets the module filter in session.
88
	 *
89
	 * @param string     $moduleName - module name
90
	 * @param int|string $viewId     - filter id
91
	 */
92
	public static function setCurrentView($moduleName, $viewId)
93
	{
94
		$_SESSION['lvs'][$moduleName]['viewname'] = $viewId;
95
	}
96
97
	/**
98 1
	 * Function that reads current module filter.
99
	 *
100 1
	 * @param string $moduleName - module name
101
	 *
102
	 * @return int|string
103 1
	 */
104
	public static function getCurrentView($moduleName)
105
	{
106
		return $_SESSION['lvs'][$moduleName]['viewname'] ?? null;
107
	}
108
109
	/**
110
	 * Get sorted by.
111
	 *
112
	 * @param string $moduleName
113
	 *
114
	 * @return string
115
	 */
116
	public static function getSortBy($moduleName)
117
	{
118
		return empty($_SESSION['lvs'][$moduleName]['sortby']) ? [] : $_SESSION['lvs'][$moduleName]['sortby'];
0 ignored issues
show
Bug Best Practice introduced by
The expression return empty($_SESSION['...[$moduleName]['sortby'] also could return the type array which is incompatible with the documented return type string.
Loading history...
119
	}
120
121
	/**
122
	 * Set sorted by.
123
	 *
124
	 * @param string $moduleName
125
	 * @param mixed  $sortBy
126
	 */
127
	public static function setSortBy(string $moduleName, $sortBy)
128
	{
129
		if (empty($sortBy)) {
130
			unset($_SESSION['lvs'][$moduleName]['sortby']);
131
		} else {
132
			$_SESSION['lvs'][$moduleName]['sortby'] = $sortBy;
133
		}
134
	}
135
136
	/**
137
	 * Has view changed.
138
	 *
139
	 * @param string     $moduleName
140
	 * @param int|string $viewId
141
	 *
142
	 * @return bool
143
	 */
144
	public static function hasViewChanged(string $moduleName, $viewId = false): bool
145
	{
146
		return empty($_SESSION['lvs'][$moduleName]['viewname'])
147
		|| ($viewId && ($viewId !== $_SESSION['lvs'][$moduleName]['viewname']))
148
		|| !isset($_SESSION['lvs'][$moduleName]['sortby']);
149
	}
150
151
	/**
152
	 * Static Function to get the Instance of CustomView.
153
	 *
154
	 * @param string $moduleName
155
	 * @param mixed  $userModelOrId
156
	 *
157
	 * @return \self
0 ignored issues
show
Bug introduced by
The type self was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
158
	 */
159
	public static function getInstance($moduleName, $userModelOrId = false)
160
	{
161
		if (!$userModelOrId) {
162
			$userModelOrId = User::getCurrentUserId();
163
		}
164
		if (is_numeric($userModelOrId)) {
165
			$userModel = User::getUserModel($userModelOrId);
166
		} else {
167
			$userModel = $userModelOrId;
168
		}
169
		$cacheName = $moduleName . '.' . $userModel->getId();
170
		if (\App\Cache::staticHas('AppCustomView', $cacheName)) {
171
			return \App\Cache::staticGet('AppCustomView', $cacheName);
172
		}
173
		$instance = new self();
174
		$instance->moduleName = $moduleName;
175
		$instance->user = $userModel;
176
		\App\Cache::staticSave('AppCustomView', $cacheName, $instance);
177
178
		return $instance;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $instance returns the type App\CustomView which is incompatible with the documented return type self.
Loading history...
179
	}
180
181
	/** @var \Vtiger_Module_Model */
182
	private $module;
183
	private $moduleName;
184
	private $user;
185
	private $defaultViewId;
186
187
	/**
188
	 * Gets module object.
189
	 *
190
	 * @return false|\Vtiger_Module_Model
191
	 */
192
	public function getModule()
193
	{
194
		if (!$this->module) {
195
			$this->module = \Vtiger_Module_Model::getInstance($this->moduleName);
196
		}
197
		return $this->module;
198
	}
199
200
	/**
201
	 * Get custom view from file.
202
	 *
203
	 * @param string $cvId
204
	 *
205
	 * @throws Exceptions\AppException
206
	 */
207
	private function getCustomViewFromFile($cvId)
208
	{
209 3
		\App\Log::trace(__METHOD__ . ' - ' . $cvId);
210
		$handlerClass = \Vtiger_Loader::getComponentClassName('Filter', $cvId, $this->moduleName);
211 3
		$filter = new $handlerClass();
212 2
		Cache::staticSave('getCustomView', $cvId, $filter);
213
		return $filter;
214 3
	}
215 2
216
	/**
217 3
	 * Get custom view from file.
218
	 *
219 3
	 * @param string $cvIds (comma separated multi cdIds)
220 3
	 *
221 3
	 * @throws Exceptions\AppException
222
	 */
223 3
	public function getCustomView($cvIds)
224 3
	{
225 3
		\App\Log::trace(__METHOD__ . ' - ' . $cvIds);
226 3
		if (Cache::staticHas('getCustomView', $cvIds)) {
227
			return Cache::staticGet('getCustomView', $cvIds);
228 3
		}
229
		if (empty($cvIds) || !static::isMultiViewId($cvIds)) {
230
			return $this->getCustomViewFromFile($cvIds);
231
		}
232
		$filters = [];
233
		foreach (explode(',', $cvIds) as $cvId) {
234
			$filters[] = $this->getCustomViewFromFile($cvId);
235
		}
236
		Cache::staticSave('getCustomView', $cvIds, $filters);
237
		return $filters;
238
	}
239
240
	/**
241
	 * Columns list by cvid.
242
	 *
243
	 * @param mixed $cvId
244
	 *
245
	 * @throws Exceptions\AppException
246
	 *
247
	 * @return array
248
	 */
249
	private function getColumnsByCvidFromDb($cvId)
250
	{
251
		\App\Log::trace(__METHOD__ . ' - ' . $cvId);
252
		$columnList = [];
253
		if (is_numeric($cvId)) {
254
			$dataReader = (new Db\Query())->select(['field_name', 'module_name', 'source_field_name', 'label'])
255
				->from('vtiger_cvcolumnlist')
256
				->innerJoin('vtiger_tab', 'vtiger_tab.name=vtiger_cvcolumnlist.module_name')
257
				->innerJoin('vtiger_field', 'vtiger_tab.tabid = vtiger_field.tabid AND vtiger_field.fieldname = vtiger_cvcolumnlist.field_name')
258
				->where(['cvid' => $cvId, 'vtiger_field.presence' => [0, 2]])->orderBy('columnindex')->createCommand()->query();
259
			while ($row = $dataReader->read()) {
260
				if (!empty($row['source_field_name']) && !$this->getModule()->getFieldByName($row['source_field_name'])->isActiveField()) {
261
					continue;
262
				}
263
				$columnList[] = $row;
264
			}
265
			$dataReader->close();
266
			if ($columnList) {
267
				Cache::save('getColumnsListByCvid', $cvId, $columnList);
268
			}
269
		} else {
270
			$view = $this->getCustomViewFromFile($cvId);
271
			$columnList = $view->getColumnList();
272
			Cache::save('getColumnsListByCvid', $cvId, $columnList);
273
		}
274
		return $columnList;
275
	}
276
277
	/**
278
	 * Columns list by cvid.
279
	 *
280
	 * @param mixed $cvIds (comma separated)
281
	 *
282
	 * @throws Exceptions\AppException
283
	 *
284
	 * @return array
285
	 */
286
	public function getColumnsListByCvid($cvIds)
287 3
	{
288
		\App\Log::trace(__METHOD__ . ' - ' . $cvIds);
289 3
		if (Cache::has('getColumnsListByCvid', $cvIds)) {
290 3
			return Cache::get('getColumnsListByCvid', $cvIds);
291 3
		}
292 3
		if (empty($cvIds) || !static::isMultiViewId($cvIds)) {
293 3
			return $this->getColumnsByCvidFromDb($cvIds);
294 3
		}
295
		$columnLists = [];
296
		foreach (explode(',', $cvIds) as $cvId) {
297
			$columnLists[] = $this->getColumnsByCvidFromDb($cvId);
298
		}
299
		Cache::save('getColumnsListByCvid', $cvIds, $columnLists);
300
		return $columnLists;
301 3
	}
302
303
	/**
304
	 * Returns conditions for filter.
305
	 *
306
	 * @param int|string $id
307
	 *
308
	 * @return array
309
	 *               [
310
	 *               'condition' => "AND" or "OR"
311
	 *               'rules' => [[
312
	 *               'fieldname' => name of fields
313 3
	 *               'operator' => operator, for instance: 'e'
314
	 *               'value' => values
315 3
	 *               ]]
316 3
	 *               ]
317 1
	 */
318
	public static function getConditions($id): array
319 3
	{
320 3
		if (Cache::has('CustomView_GetConditions', $id)) {
321
			return Cache::get('CustomView_GetConditions', $id);
322
		}
323
		$dataReader = (new \App\Db\Query())->select([
324
			'u_#__cv_condition.group_id',
325
			'u_#__cv_condition.field_name',
326
			'u_#__cv_condition.module_name',
327
			'u_#__cv_condition.source_field_name',
328
			'u_#__cv_condition.operator',
329
			'u_#__cv_condition.value',
330
			'condition_index' => 'u_#__cv_condition.index',
331
			'u_#__cv_condition_group.id',
332
			'u_#__cv_condition_group.condition',
333
			'u_#__cv_condition_group.parent_id',
334
			'group_index' => 'u_#__cv_condition_group.index',
335
		])->from('u_#__cv_condition_group')
336
			->leftJoin('u_#__cv_condition', 'u_#__cv_condition.group_id = u_#__cv_condition_group.id')
337
			->where(['u_#__cv_condition_group.cvid' => $id])
338
			->orderBy(['u_#__cv_condition_group.parent_id' => SORT_ASC])
339
			->createCommand()->query();
340
		$referenceGroup = $referenceParent = $conditions = [];
341
		while ($condition = $dataReader->read()) {
342
			if ($condition['group_id']) {
343
				$isEmptyCondition = false;
344
			} else {
345 3
				$condition['group_id'] = $condition['id'];
346
				$isEmptyCondition = true;
347 3
			}
348 1
			$value = $condition['value'];
349
			$fieldName = "{$condition['field_name']}:{$condition['module_name']}" . ($condition['source_field_name'] ? ':' . $condition['source_field_name'] : '');
350 3
			if (isset($referenceParent[$condition['parent_id']], $referenceGroup[$condition['group_id']])) {
351 3
				$referenceParent[$condition['parent_id']][$condition['condition_index']] = [
352
					'fieldname' => $fieldName,
353
					'operator' => $condition['operator'],
354
					'value' => $value,
355
				];
356
			} elseif (isset($referenceGroup[$condition['parent_id']])) {
357
				if ($isEmptyCondition) {
358
					$referenceGroup[$condition['parent_id']][$condition['group_index']] = [
359
						'condition' => $condition['condition'],
360
						'rules' => [],
361
					];
362 3
				} else {
363 3
					$referenceGroup[$condition['parent_id']][$condition['group_index']] = [
364 3
						'condition' => $condition['condition'],
365 3
						'rules' => [
366 3
							$condition['condition_index'] => [
367 3
								'fieldname' => $fieldName,
368 3
								'operator' => $condition['operator'],
369
								'value' => $value,
370
							],
371
						],
372
					];
373
				}
374
				$referenceParent[$condition['parent_id']] = &$referenceGroup[$condition['parent_id']][$condition['group_index']]['rules'];
375
				$referenceGroup[$condition['group_id']] = &$referenceGroup[$condition['parent_id']][$condition['group_index']]['rules'];
376
			} else {
377
				if ($isEmptyCondition) {
378
					$conditions = [
379
						'condition' => $condition['condition'],
380
						'rules' => [],
381
					];
382
				} else {
383
					$conditions = [
384
						'condition' => $condition['condition'],
385
						'rules' => [
386
							$condition['condition_index'] => [
387
								'fieldname' => $fieldName,
388
								'operator' => $condition['operator'],
389
								'value' => $value,
390
							],
391
						],
392
					];
393
				}
394
				$referenceParent[$condition['parent_id']] = &$conditions['rules'];
395
				$referenceGroup[$condition['group_id']] = &$conditions['rules'];
396
			}
397
		}
398
		$conditions = static::sortConditions($conditions);
399
		Cache::save('CustomView_GetConditions', $id, $conditions, Cache::LONG);
400
		return $conditions;
401
	}
402
403
	/**
404
	 * Sorting conditions.
405
	 *
406
	 * @param array|null $array
407
	 * @param ?array     $arrayToSort
408
	 *
409
	 * @return array|null
410
	 */
411
	private static function sortConditions(?array $arrayToSort): ?array
412
	{
413
		if (isset($arrayToSort['rules'])) {
414
			ksort($arrayToSort['rules']);
415
			foreach ($arrayToSort['rules'] as $rule) {
416
				if (isset($rule['condition'])) {
417
					static::sortConditions($rule);
418
				}
419
			}
420
		}
421
		return $arrayToSort;
422
	}
423
424
	/**
425 3
	 * Get fields to detect duplicates.
426 3
	 *
427 3
	 * @param int|string $viewId
428
	 *
429
	 * @return array
430
	 */
431
	public static function getDuplicateFields($viewId): array
432
	{
433
		if (!is_numeric($viewId)) {
434
			return [];
435
		}
436
		if (Cache::has('CustomView_GetDuplicateFields', $viewId)) {
437
			return Cache::get('CustomView_GetDuplicateFields', $viewId);
438 3
		}
439
		$data = (new \App\Db\Query())->select(['vtiger_field.fieldname', 'u_#__cv_duplicates.ignore'])
440 3
			->from('u_#__cv_duplicates')
441
			->innerJoin('vtiger_field', 'vtiger_field.fieldid = u_#__cv_duplicates.fieldid')
442
			->where(['u_#__cv_duplicates.cvid' => $viewId])->all();
443
		Cache::save('CustomView_GetDuplicateFields', $viewId, $data);
444
		return $data;
445
	}
446
447
	/**
448 3
	 * To get the customViewId of the specified module.
449
	 *
450
	 * @param mixed $noCache
451
	 *
452
	 * @return int|string
453
	 */
454
	public function getViewId($noCache = false)
455
	{
456
		\App\Log::trace(__METHOD__);
457
		if (isset($this->defaultViewId)) {
458 3
			return $this->defaultViewId;
459
		}
460 3
		if ($noCache || Request::_isEmpty('viewname')) {
0 ignored issues
show
Bug introduced by
The method _isEmpty() does not exist on App\Request. Since you implemented __callStatic, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

460
		if ($noCache || Request::/** @scrutinizer ignore-call */ _isEmpty('viewname')) {
Loading history...
461
			$viewId = null;
462
			if (Request::_has('mid')) {
0 ignored issues
show
Bug introduced by
The method _has() does not exist on App\Request. Since you implemented __callStatic, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

462
			if (Request::/** @scrutinizer ignore-call */ _has('mid')) {
Loading history...
463 3
				$viewId = current(self::getModuleFiltersByMenuId(Request::_getInteger('mid'), $this->moduleName));
0 ignored issues
show
Bug introduced by
The method _getInteger() does not exist on App\Request. Since you implemented __callStatic, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

463
				$viewId = current(self::getModuleFiltersByMenuId(Request::/** @scrutinizer ignore-call */ _getInteger('mid'), $this->moduleName));
Loading history...
464 1
			}
465
			if (empty($viewId) && !$noCache && self::getCurrentView($this->moduleName)) {
466 3
				$viewId = self::getCurrentView($this->moduleName);
467 3
				if (empty($this->getFilterInfo($viewId))) {
468 3
					$viewId = null;
469 3
				}
470 3
			}
471 3
			if (empty($viewId)) {
472
				$viewId = $this->getDefaultCvId();
473
			}
474
			if (empty($viewId) || !$this->isPermittedCustomView($viewId)) {
475
				$viewId = $this->getMandatoryFilter();
476
			}
477
		} else {
478
			$viewId = Request::_get('viewname');
0 ignored issues
show
Bug introduced by
The method _get() does not exist on App\Request. Since you implemented __callStatic, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

478
			/** @scrutinizer ignore-call */ 
479
   $viewId = Request::_get('viewname');
Loading history...
479
			if (!is_numeric($viewId)) {
480
				if ('All' === $viewId) {
481 2
					$viewId = $this->getMandatoryFilter();
482
				} else {
483 2
					$viewId = $this->getViewIdByName($viewId);
484 2
				}
485
				if (!$viewId) {
486
					$viewId = $this->getDefaultCvId();
487 2
				}
488 2
			} else {
489
				$viewId = (int) $viewId;
490
				if (!$this->isPermittedCustomView($viewId)) {
491 2
					throw new Exceptions\NoPermitted('ERR_NO_PERMITTED_TO_VIEW');
492
				}
493 2
			}
494
		}
495
		$this->defaultViewId = $viewId;
496
		return $viewId;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $viewId also could return the type array which is incompatible with the documented return type integer|string.
Loading history...
497
	}
498
499
	/**
500
	 * Get default cvId.
501
	 *
502
	 * @return int|string
503
	 */
504
	public function getDefaultCvId()
505
	{
506
		$cacheName = $this->moduleName . $this->user->getId();
507
		if (Cache::has('GetDefaultCvId', $cacheName)) {
508
			return Cache::get('GetDefaultCvId', $cacheName);
509
		}
510
		$query = (new Db\Query())->select(['userid', 'default_cvid'])->from('vtiger_user_module_preferences')->where(['tabid' => Module::getModuleId($this->moduleName)]);
511
		$data = $query->createCommand()->queryAllByGroup();
512
		$defaultCvId = null;
513
		foreach ($this->user->getMemberStructure() as $member) {
514 2
			if (isset($data[$member]) && $this->isPermittedCustomView($data[$member])) {
515 2
				$defaultCvId = $data[$member];
516
				break;
517
			}
518
		}
519
		if (!$defaultCvId) {
520
			foreach ($this->getFilters() as $cvId => $values) {
521
				if (1 === $values['setdefault'] && $this->isPermittedCustomView($cvId)) {
522
					$defaultCvId = $cvId;
523 2
					break;
524
				}
525 2
			}
526 2
			if (!$defaultCvId) {
527 2
				$defaultCvId = $this->getMandatoryFilter();
528
			}
529
		}
530 2
		Cache::save('GetDefaultCvId', $cacheName, $defaultCvId);
531 2
		return $defaultCvId;
532 2
	}
533 2
534
	/**
535
	 * Function to check if the current user is able to see the customView.
536
	 *
537
	 * @param int|string $viewId
538 2
	 *
539 2
	 * @return bool
540 2
	 */
541
	public function isPermittedCustomView($viewId)
542
	{
543
		return self::isPermitted($viewId, $this->moduleName, $this->user->getId());
544
	}
545 2
546 2
	/**
547
	 * Get mandatory filter by module.
548
	 *
549
	 * @param bolean $returnData
0 ignored issues
show
Bug introduced by
The type App\bolean was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
550 2
	 *
551 2
	 * @return array|int
552 2
	 */
553
	public function getMandatoryFilter($returnData = false)
554
	{
555
		Log::trace(__METHOD__);
556
		$info = $this->getFilters();
557 2
		$returnValue = '';
558 2
		foreach ($info as $index => &$values) {
559 2
			if (0 === $values['presence']) {
560 2
				$returnValue = $index;
561 2
				break;
562
			}
563
			if (2 === $values['presence']) {
564
				$returnValue = $index;
565
			}
566
		}
567
		return $returnData ? $info[$returnValue] : $returnValue;
568
	}
569
570
	/**
571
	 * Get viewId by name.
572
	 *
573 2
	 * @param string $viewName
574
	 *
575 2
	 * @return int|null
576 2
	 */
577 2
	public function getViewIdByName(string $viewName): ?int
578 2
	{
579 2
		$viewId = null;
580 2
		foreach ($this->getFilters() as $cvId => &$values) {
0 ignored issues
show
Bug introduced by
The expression $this->getFilters() cannot be used as a reference.

Let?s assume that you have the following foreach statement:

foreach ($array as &$itemValue) { }

$itemValue is assigned by reference. This is possible because the expression (in the example $array) can be used as a reference target.

However, if we were to replace $array with something different like the result of a function call as in

foreach (getArray() as &$itemValue) { }

then assigning by reference is not possible anymore as there is no target that could be modified.

Available Fixes

1. Do not assign by reference
foreach (getArray() as $itemValue) { }
2. Assign to a local variable first
$array = getArray();
foreach ($array as &$itemValue) {}
3. Return a reference
function &getArray() { $array = array(); return $array; }

foreach (getArray() as &$itemValue) { }
Loading history...
581 2
			if ($values['viewname'] === $viewName) {
582 2
				$viewId = $cvId;
583 2
				break;
584
			}
585
		}
586
		return $viewId;
587
	}
588
589
	/**
590
	 * Function to get basic information about filter.
591
	 *
592
	 * @param int $cvId
593
	 *
594
	 * @return array
595
	 */
596
	public function getFilterInfo(int $cvId): array
597
	{
598
		return $this->getFilters()[$cvId] ?? [];
599
	}
600
601
	/**
602
	 * Function to get basic information about all filters.
603
	 *
604
	 * @param string $moduleName
605
	 *
606
	 * @return array
607
	 */
608
	public function getFilters(): array
609
	{
610
		return self::getFiltersByModule($this->moduleName);
611
	}
612
613
	/**
614
	 * Check permissions.
615
	 *
616
	 * @param int    $cvId
617 2
	 * @param string $moduleName
618
	 * @param int    $userId
619
	 *
620
	 * @return bool
621
	 */
622
	public static function isPermitted(int $cvId, string $moduleName = null, int $userId = null): bool
623
	{
624
		$userModel = $userId ? \App\User::getUserModel($userId) : \App\User::getCurrentUserModel();
625
		return ($data = self::getCVDetails($cvId, $moduleName))
626
		&& ($userModel->isAdmin()
627 2
		|| $data['userid'] === $userModel->getId()
628
		|| 0 === $data['presence']
629 2
		|| \in_array($data['status'], [self::CV_STATUS_DEFAULT, self::CV_STATUS_PUBLIC])
630 2
		|| (self::CV_STATUS_PRIVATE === $data['status'] && array_intersect($userModel->getMemberStructure(), $data['members'])));
631 2
	}
632 2
633 2
	/**
634 2
	 * Function to get basic information about all filters for module.
635
	 *
636
	 * @param string $moduleName
637
	 *
638
	 * @return array
639 2
	 */
640
	public static function getFiltersByModule(string $moduleName): array
641
	{
642
		if (Cache::has('CustomViewInfo', $moduleName)) {
643
			return Cache::get('CustomViewInfo', $moduleName);
644
		}
645
		$members = (new Db\Query())->select(['u_#__cv_privileges.cvid', 'member'])->from('u_#__cv_privileges')
646
			->innerJoin('vtiger_customview', 'u_#__cv_privileges.cvid=vtiger_customview.cvid')
647
			->where(['entitytype' => $moduleName])->createCommand()->queryAllByGroup(2);
648
		$info = (new Db\Query())->from('vtiger_customview')->where(['entitytype' => $moduleName])->indexBy('cvid')->orderBy(['sequence' => SORT_ASC])->all();
649
		foreach ($info as &$item) {
650
			$item['cvid'] = (int) $item['cvid'];
651
			$item['setdefault'] = (int) $item['setdefault'];
652
			$item['setmetrics'] = (int) $item['setmetrics'];
653
			$item['status'] = (int) $item['status'];
654
			$item['privileges'] = (int) $item['privileges'];
655
			$item['featured'] = (int) $item['featured'];
656
			$item['presence'] = (int) $item['presence'];
657
			$item['sequence'] = (int) $item['sequence'];
658
			$item['userid'] = (int) $item['userid'];
659
			$item['members'] = $members[$item['cvid']] ?? [];
660
			Cache::save('CustomViewInfo', $item['cvid'], $item);
661
		}
662
		Cache::save('CustomViewInfo', $moduleName, $info);
663
		return $info;
664
	}
665
666
	/**
667
	 * Reset current views configuration in session.
668
	 *
669
	 * @param string|bool $moduleName
670
	 */
671
	public static function resetCurrentView($moduleName = false)
672
	{
673 2
		if (\App\Session::has('lvs')) {
674
			if ($moduleName) {
675 2
				$lvs = \App\Session::get('lvs');
676 2
				if (isset($lvs[$moduleName])) {
677 2
					unset($lvs[$moduleName]);
678 2
					\App\Session::set('lvs', $lvs);
679 2
				}
680
			} else {
681
				\App\Session::set('lvs', []);
682 2
			}
683
		}
684
	}
685
686
	/**
687
	 * Get module filters by menu id.
688
	 *
689
	 * @param int    $menuId
690
	 * @param string $moduleName
691
	 *
692 3
	 * @return array
693
	 */
694 3
	public static function getModuleFiltersByMenuId(int $menuId, string $moduleName = ''): array
695 2
	{
696
		$cacheKey = 'getModuleFiltersByMenuId' . $moduleName;
697 3
		if (\App\Cache::staticHas($cacheKey, $menuId)) {
698 3
			return \App\Cache::staticGet($cacheKey, $menuId);
699 2
		}
700 2
		$filters = [];
701 2
		$userModel = User::getCurrentUserModel();
702 2
		$roleMenu = 'user_privileges/menu_' . filter_var($userModel->getDetail('roleid'), FILTER_SANITIZE_NUMBER_INT) . '.php';
703 2
		file_exists($roleMenu) ? require $roleMenu : require 'user_privileges/menu_0.php';
704 2
		if (0 === \count($menus) && file_exists($roleMenu)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $menus seems to be never defined.
Loading history...
705 2
			require 'user_privileges/menu_0.php';
706 2
		}
707 2
		if (isset($filterList[$menuId])) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $filterList does not exist. Did you maybe mean $filters?
Loading history...
708 2
			$filtersMenu = explode(',', $filterList[$menuId]['filters']);
709
			$filtersCustomView = array_keys(\CustomView_Record_Model::getAll($moduleName));
710 3
			$filters = array_intersect($filtersMenu, $filtersCustomView);
711 3
		}
712 3
		\App\Cache::staticSave($cacheKey, $menuId, $filters);
713 3
		return $filters;
714 3
	}
715 3
716 3
	/**
717 3
	 * Get custom view by ID.
718 3
	 *
719 3
	 * @param int $cvId
720 3
	 *
721
	 * @return array
722
	 */
723 3
	public static function getCustomViewById(int $cvId): array
724 3
	{
725
		if (Cache::has('CustomViewById', $cvId)) {
726
			return Cache::get('CustomViewById', $cvId);
727
		}
728
		$data = (new Db\Query())->from('vtiger_customview')->where(['cvid' => $cvId])->one() ?: [];
729
		if (!empty($data['advanced_conditions'])) {
730
			$data['advanced_conditions'] = \App\Json::decode($data['advanced_conditions']);
731
		}
732
		Cache::save('CustomViewById', $cvId, $data);
733
		return $data;
734
	}
735
736
	/**
737
	 * Gets custom view details by ID.
738
	 *
739
	 * @param int         $cvId
740
	 * @param string|null $moduleName
741
	 *
742
	 * @return array
743
	 */
744
	public static function getCVDetails(int $cvId, string $moduleName = null): array
745
	{
746
		if (Cache::has('CustomViewInfo', $cvId)) {
747
			return Cache::get('CustomViewInfo', $cvId);
748
		}
749
		if (!$moduleName) {
750
			$moduleName = self::getCustomViewById($cvId)['entitytype'] ?? '';
751
		}
752
		return $moduleName ? (self::getFiltersByModule($moduleName)[$cvId] ?? []) : [];
753
	}
754
755
	/**
756
	 * Function clear cache by custom view ID.
757
	 *
758
	 * @param int         $cvId
759
	 * @param string|null $moduleName
760
	 *
761
	 * @return void
762
	 */
763
	public static function clearCacheById(int $cvId, string $moduleName = null): void
764
	{
765
		Cache::delete('CustomViewById', $cvId);
766
		Cache::delete('CustomViewInfo', $cvId);
767
		Cache::delete('getAllFilterColors', false);
0 ignored issues
show
Bug introduced by
false of type false is incompatible with the type string expected by parameter $key of App\Cache::delete(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

767
		Cache::delete('getAllFilterColors', /** @scrutinizer ignore-type */ false);
Loading history...
768
		Cache::delete('getAllFilterColors', true);
0 ignored issues
show
Bug introduced by
true of type true is incompatible with the type string expected by parameter $key of App\Cache::delete(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

768
		Cache::delete('getAllFilterColors', /** @scrutinizer ignore-type */ true);
Loading history...
769
		if (null === $moduleName) {
770
			foreach (\App\Module::getAllModuleNames() as $moduleName) {
771
				Cache::delete('CustomViewInfo', $moduleName);
772
			}
773
		} else {
774
			Cache::delete('CustomViewInfo', $moduleName);
775
		}
776
	}
777
}
778