Passed
Pull Request — developer (#15265)
by Arkadiusz
17:52
created

Vtiger_RelationListView_Model   F

Complexity

Total Complexity 114

Size/Duplication

Total Lines 709
Duplicated Lines 0 %

Test Coverage

Coverage 41.38%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 114
eloc 302
dl 0
loc 709
ccs 96
cts 232
cp 0.4138
rs 2
c 2
b 0
f 0

33 Methods

Rating   Name   Duplication   Size   Complexity  
A getRelationModel() 0 3 1
A getRelatedModuleModel() 0 3 1
A getParentRecordModel() 0 3 1
B getRelationQuery() 0 25 7
A loadCustomView() 0 9 3
A isQuickSearchEnabled() 0 3 2
A setParentRecordModel() 0 5 1
A getInstance() 0 23 4
A setRelationModel() 0 5 1
A getQueryGenerator() 0 3 1
A setRelatedModuleModel() 0 5 1
B loadCondition() 0 18 7
B getCreateViewUrl() 0 19 8
B getTreeEntries() 0 37 7
A getTreeHeaders() 0 6 1
A loadOrderBy() 0 10 6
A getEntries() 0 17 2
A getAllEntries() 0 3 1
B getRecordsFromArray() 0 31 7
A getFavoriteRecords() 0 10 1
A getRelatedTreeEntriesCount() 0 9 1
A getTreeViewModel() 0 3 1
A getRelatedEntriesCount() 0 3 1
A getEntryExtend() 0 2 1
A getAddRelationLinks() 0 25 4
A getSelectRelationLinks() 0 15 4
A getLinks() 0 46 5
A getWidgetsList() 0 16 3
A getWidgets() 0 17 5
A setFields() 0 16 5
A isWidgetsList() 0 4 3
C getHeaders() 0 32 13
A loadSearchLockedFields() 0 13 5

How to fix   Complexity   

Complex Class

Complex classes like Vtiger_RelationListView_Model often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Vtiger_RelationListView_Model, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
 /* +***********************************************************************************
4
 * The contents of this file are subject to the vtiger CRM Public License Version 1.0
5
 * ("License"); You may not use this file except in compliance with the License
6
 * The Original Code is:  vtiger CRM Open Source
7
 * The Initial Developer of the Original Code is vtiger.
8
 * Portions created by vtiger are Copyright (C) vtiger.
9
 * All Rights Reserved.
10
 * Contributor(s): YetiForce.com
11
 * *********************************************************************************** */
12
13
class Vtiger_RelationListView_Model extends \App\Base
14
{
15
	/**
16
	 * Relation model instance.
17
	 *
18
	 * @var Vtiger_Relation_Model
19
	 */
20
	protected $relationModel;
21
22
	/**
23
	 * Parent record model instance.
24
	 *
25
	 * @var Vtiger_Record_Model
26
	 */
27
	protected $parentRecordModel;
28
29
	/**
30
	 * Related module model instance.
31
	 *
32
	 * @var Vtiger_Module_Model
33
	 */
34
	protected $relatedModuleModel;
35
36
	/**
37
	 * Mandatory columns.
38
	 *
39
	 * @var array
40
	 */
41
	protected $mandatoryColumns = [];
42
43
	/**
44
	 * Set relation model instance.
45
	 *
46
	 * @param Vtiger_Relation_Model $relation
47
	 *
48
	 * @return $this
49 1
	 */
50
	public function setRelationModel($relation)
51 1
	{
52
		$this->relationModel = $relation;
53 1
54
		return $this;
55
	}
56
57
	/**
58
	 * Get relation model instance.
59
	 *
60
	 * @return Vtiger_Relation_Model
61 1
	 */
62
	public function getRelationModel()
63 1
	{
64
		return $this->relationModel;
65
	}
66
67
	/**
68
	 * Set parent record model instance.
69
	 *
70
	 * @param Vtiger_Record_Model $parentRecord
71
	 *
72
	 * @return $this
73 1
	 */
74
	public function setParentRecordModel($parentRecord)
75 1
	{
76
		$this->parentRecordModel = $parentRecord;
77 1
78
		return $this;
79
	}
80
81
	/**
82
	 * Get parent record model instance.
83
	 *
84
	 * @return Vtiger_Record_Model
85 1
	 */
86
	public function getParentRecordModel()
87 1
	{
88
		return $this->parentRecordModel;
89
	}
90
91
	/**
92
	 * Set related module model instance.
93
	 *
94
	 * @param Vtiger_Module_Model $relatedModuleModel
95
	 *
96
	 * @return $this
97 1
	 */
98
	public function setRelatedModuleModel($relatedModuleModel)
99 1
	{
100
		$this->relatedModuleModel = $relatedModuleModel;
101 1
102
		return $this;
103
	}
104
105
	/**
106
	 * Get related module model instance.
107
	 *
108
	 * @return Vtiger_Module_Model
109 1
	 */
110
	public function getRelatedModuleModel()
111 1
	{
112
		return $this->relatedModuleModel;
113
	}
114
115
	/**
116
	 * Get query generator instance.
117
	 *
118
	 * @return \App\QueryGenerator
119 1
	 */
120
	public function getQueryGenerator()
121 1
	{
122
		return $this->getRelationModel()->getQueryGenerator();
123
	}
124
125
	/**
126
	 * Function to identify if the module supports quick search or not.
127
	 */
128
	public function isQuickSearchEnabled()
129
	{
130
		return $this->has('quickSearchEnabled') ? $this->get('quickSearchEnabled') : true;
131
	}
132
133 1
	/**
134
	 * Get relation list view model instance.
135 1
	 *
136 1
	 * @param Vtiger_Record_Model $parentRecordModel
137 1
	 * @param string              $relationModuleName
138
	 * @param bool|int            $relationId
139 1
	 * @param int|string          $cvId
140 1
	 *
141 1
	 * @return self
142
	 */
143 1
	public static function getInstance(Vtiger_Record_Model $parentRecordModel, string $relationModuleName, $relationId = false, $cvId = 0)
144 1
	{
145 1
		$parentModuleModel = $parentRecordModel->getModule();
146 1
		$className = Vtiger_Loader::getComponentClassName('Model', 'RelationListView', $parentModuleModel->getName());
147
		$instance = new $className();
148 1
		if ($relationId) {
149 1
			$relationModelInstance = Vtiger_Relation_Model::getInstanceById($relationId);
0 ignored issues
show
Bug introduced by
It seems like $relationId can also be of type true; however, parameter $relationId of Vtiger_Relation_Model::getInstanceById() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

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

149
			$relationModelInstance = Vtiger_Relation_Model::getInstanceById(/** @scrutinizer ignore-type */ $relationId);
Loading history...
150 1
		} else {
151 1
			$relationModelInstance = Vtiger_Relation_Model::getInstance($parentModuleModel, Vtiger_Module_Model::getInstance($relationModuleName), $relationId);
152
		}
153 1
		if (!$relationModelInstance) {
0 ignored issues
show
introduced by
$relationModelInstance is of type Vtiger_Relation_Model, thus it always evaluated to true.
Loading history...
154
			return false;
155
		}
156
		$instance->setParentRecordModel($parentRecordModel);
157
		$instance->setRelatedModuleModel($relationModelInstance->getRelationModuleModel());
158
		$queryGenerator = new \App\QueryGenerator($relationModelInstance->getRelationModuleModel()->getName());
159
		if ($cvId) {
160
			$instance->set('cvId', $cvId);
161
		}
162
		$relationModelInstance->set('query_generator', $queryGenerator);
163 1
		$relationModelInstance->set('parentRecord', $parentRecordModel);
164
		$instance->setRelationModel($relationModelInstance);
165 1
		return $instance;
166
	}
167
168 1
	/**
169 1
	 * Function to get Relation query.
170 1
	 *
171 1
	 * @param mixed $returnQueryGenerator
172 1
	 *
173 1
	 * @return \App\Db\Query|\App\QueryGenerator
174 1
	 */
175
	public function getRelationQuery($returnQueryGenerator = false)
176
	{
177
		if ($this->has('Query')) {
178
			return $this->get('Query');
179 1
		}
180
		$this->loadCustomView();
181
		$this->loadCondition();
182 1
		$this->loadOrderBy();
183 1
		$relationModelInstance = $this->getRelationModel();
184 1
		if (!empty($relationModelInstance) && $relationModelInstance->get('name')) {
185
			$queryGenerator = $relationModelInstance->getQuery();
186
			$relationModuleName = $queryGenerator->getModule();
187
			if (isset($this->mandatoryColumns[$relationModuleName])) {
188
				foreach ($this->mandatoryColumns[$relationModuleName] as &$columnName) {
189
					$queryGenerator->setCustomColumn($columnName);
190
				}
191
			}
192 1
			if ($returnQueryGenerator) {
193
				return $queryGenerator;
194 1
			}
195 1
			$query = $queryGenerator->createQuery();
196 1
			$this->set('Query', $query);
197
			return $query;
198
		}
199 1
		throw new \App\Exceptions\AppException('>>> No relationModel instance, requires verification 2 <<<');
200
	}
201
202 1
	/**
203 1
	 * Load list view conditions.
204
	 */
205 1
	public function loadCondition()
206
	{
207
		$relatedModuleName = $this->getRelatedModuleModel()->getName();
208 1
		$queryGenerator = $this->getRelationModel()->getQueryGenerator();
209
		if ($entityState = $this->get('entityState')) {
210
			$queryGenerator->setStateCondition($entityState);
211
		}
212
		if ($relatedModuleName === $this->get('src_module') && !$this->isEmpty('src_record')) {
213
			$queryGenerator->addCondition('id', $this->get('src_record'), 'n');
214
		}
215
		if ($searchParams = $this->getArray('search_params')) {
216
			$queryGenerator->parseAdvFilter($searchParams);
217 1
		}
218
		if (!$this->isEmpty('search_key')) {
219 1
			$queryGenerator->addCondition($this->get('search_key'), $this->get('search_value'), $this->get('operator'));
220 1
		}
221 1
		if ($searchParams = $this->getArray('search_rel_params')) {
222 1
			$this->getRelationModel()->setRelationConditions($searchParams);
223 1
		}
224
	}
225 1
226 1
	/**
227 1
	 * Load custom view.
228
	 */
229
	public function loadCustomView()
230
	{
231 1
		if ($this->has('cvId')) {
232
			$cvId = $this->get('cvId');
233 1
		} else {
234 1
			$cvId = array_key_first($this->getRelationModel()->getCustomViewList());
235 1
		}
236 1
		if ('relation' !== $cvId) {
237 1
			$this->getRelationModel()->getQueryGenerator()->initForCustomViewById($cvId);
238 1
		}
239 1
	}
240
241
	/**
242 1
	 * Function to get the related list view entries.
243 1
	 *
244
	 * @param Vtiger_Paging_Model $pagingModel
245
	 *
246
	 * @return Vtiger_Record_Model[]
247
	 */
248
	public function getEntries(Vtiger_Paging_Model $pagingModel)
249
	{
250
		$pageLimit = $pagingModel->getPageLimit();
251 1
		$query = $this->getRelationQuery();
252
		$query->limit($pageLimit + 1)->offset($pagingModel->getStartIndex());
0 ignored issues
show
Bug introduced by
The method offset() does not exist on App\QueryGenerator. ( Ignorable by Annotation )

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

252
		$query->limit($pageLimit + 1)->/** @scrutinizer ignore-call */ offset($pagingModel->getStartIndex());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
Bug introduced by
The method limit() does not exist on App\QueryGenerator. ( Ignorable by Annotation )

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

252
		$query->/** @scrutinizer ignore-call */ 
253
          limit($pageLimit + 1)->offset($pagingModel->getStartIndex());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
253 1
		$rows = $query->all();
0 ignored issues
show
Bug introduced by
The method all() does not exist on App\QueryGenerator. ( Ignorable by Annotation )

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

253
		/** @scrutinizer ignore-call */ 
254
  $rows = $query->all();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
254
255
		$count = \count($rows);
256
		if ($count > $pageLimit) {
257
			array_pop($rows);
258 1
			$pagingModel->set('nextPageExists', true);
259
		} else {
260 1
			$pagingModel->set('nextPageExists', false);
261 1
		}
262
		$relatedRecordList = $this->getRecordsFromArray($rows);
263
		$pagingModel->calculatePageRange(\count($relatedRecordList));
264
		return $relatedRecordList;
265
	}
266
267
	/**
268
	 * Gets all entries.
269
	 *
270
	 * @return \Vtiger_Record_Model[]
271 1
	 */
272
	public function getAllEntries(): array
273
	{
274
		return $this->getRecordsFromArray($this->getRelationQuery()->all());
275
	}
276
277
	/**
278 1
	 * Get models of records from array.
279
	 *
280 1
	 * @param array $rows
281 1
	 *
282 1
	 * @return \Vtiger_Record_Model[]
283 1
	 */
284
	public function getRecordsFromArray(array $rows)
285
	{
286
		$listViewRecordModels = $relatedFields = [];
287 1
		$moduleModel = $this->getRelationModel()->getRelationModuleModel();
288
		$recordId = $this->getParentRecordModel()->getId();
289
		foreach ($this->getQueryGenerator()->getRelatedFields() as $fieldInfo) {
290
			$relatedFields[$fieldInfo['relatedModule']][$fieldInfo['sourceField']][] = $fieldInfo['relatedField'];
291
		}
292
		foreach ($rows as $row) {
293
			if ($recordId == $row['id']) {
294
				continue;
295
			}
296
			$extRecordModel = [];
297
			foreach ($relatedFields as $relatedModuleName => $fields) {
298
				foreach ($fields as $sourceField => $field) {
299
					$recordData = [
300
						'id' => $row[$sourceField . $relatedModuleName . 'id'] ?? 0,
301
					];
302
					foreach ($field as $relatedFieldName) {
303
						$recordData[$relatedFieldName] = $row[$sourceField . $relatedModuleName . $relatedFieldName];
304
						unset($row[$sourceField . $relatedModuleName . $relatedFieldName]);
305
					}
306
					$extRecordModel[$sourceField][$relatedModuleName] = Vtiger_Module_Model::getInstance($relatedModuleName)->getRecordFromArray($recordData);
307
				}
308
			}
309
			$recordModel = $moduleModel->getRecordFromArray($row);
310
			$recordModel->ext = $extRecordModel;
311
			$this->getEntryExtend($recordModel);
312
			$listViewRecordModels[$row['id']] = $recordModel;
313
		}
314
		return $listViewRecordModels;
315
	}
316
317
	/**
318
	 * Function extending recordModel object with additional information.
319
	 *
320
	 * @param Vtiger_Record_Model $recordModel
321
	 */
322
	public function getEntryExtend(Vtiger_Record_Model $recordModel)
0 ignored issues
show
Unused Code introduced by
The parameter $recordModel is not used and could be removed. ( Ignorable by Annotation )

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

322
	public function getEntryExtend(/** @scrutinizer ignore-unused */ Vtiger_Record_Model $recordModel)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
323
	{
324
	}
325
326
	/**
327
	 * Set list view order by.
328
	 */
329
	public function loadOrderBy()
330
	{
331
		$orderBy = $this->get('orderby');
332
		if (!empty($orderBy) && \is_array($orderBy)) {
333
			foreach ($orderBy as $fieldName => $sortFlag) {
334
				$field = $this->getRelationModel()->getRelationModuleModel()->getFieldByName($fieldName);
335
				if ($field || 'id' === $fieldName) {
336
					$this->getRelationModel()->getQueryGenerator()->setOrder($fieldName, $sortFlag);
337
				} else {
338
					\App\Log::warning("[RelationListView] Incorrect value of sorting: '$fieldName'");
339
				}
340
			}
341
		}
342
	}
343
344
	/**
345
	 * Get header fields.
346
	 *
347
	 * @return Vtiger_Field_Model[]
348
	 */
349
	public function getHeaders()
350
	{
351
		$fields = [];
352
		if ($this->get('viewId')) {
353
			$moduleModel = $this->getRelationModel()->getRelationModuleModel();
354
			$customView = App\CustomView::getInstance($moduleModel->getName());
355
			foreach ($customView->getColumnsListByCvid($this->get('viewId')) as $fieldInfo) {
356
				$fieldName = $fieldInfo['field_name'];
357
				$sourceFieldName = $fieldInfo['source_field_name'] ?? '';
358
				$fieldModel = Vtiger_Field_Model::getInstance($fieldName, Vtiger_Module_Model::getInstance($fieldInfo['module_name']));
359
				if (!$fieldModel || !$fieldModel->isActiveField() || ($sourceFieldName && !$moduleModel->getFieldByName($sourceFieldName)->isActiveField())) {
360
					continue;
361
				}
362
				if ($sourceFieldName) {
363
					$fieldModel->set('source_field_name', $sourceFieldName);
364
				}
365
				$fields[$fieldModel->getFullName()] = $fieldModel;
366
			}
367
		}
368
		if (empty($fields)) {
369
			$fields = $this->getRelationModel()->getQueryFields();
370
		}
371
		unset($fields['id']);
372
		foreach ($fields as $fieldName => $fieldModel) {
373
			if (!$fieldModel->isViewable() && !$fieldModel->get('fromOutsideList')) {
374
				unset($fields[$fieldName]);
375
			}
376
		}
377
		if ($relFields = $this->getRelationModel()->getRelationFields()) {
378
			$fields = array_merge($fields, $relFields);
379
		}
380
		return $fields;
381
	}
382
383
	/**
384
	 * Function to get Total number of record in this relation.
385
	 *
386
	 * @return int
387
	 */
388
	public function getRelatedEntriesCount()
389
	{
390
		return $this->getRelationQuery()->count();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getRelationQuery()->count() also could return the type string which is incompatible with the documented return type integer.
Loading history...
Bug introduced by
The method count() does not exist on App\QueryGenerator. ( Ignorable by Annotation )

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

390
		return $this->getRelationQuery()->/** @scrutinizer ignore-call */ count();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
391
	}
392
393
	/**
394
	 * Get tree view model.
395
	 *
396
	 * @return Vtiger_TreeCategoryModal_Model
397
	 */
398
	public function getTreeViewModel()
399
	{
400
		return Vtiger_TreeCategoryModal_Model::getInstance($this->getRelatedModuleModel());
0 ignored issues
show
Bug Best Practice introduced by
The expression return Vtiger_TreeCatego...etRelatedModuleModel()) returns the type Vtiger_TreeView_Model which is incompatible with the documented return type Vtiger_TreeCategoryModal_Model.
Loading history...
401
	}
402
403
	/**
404
	 * Get tree headers.
405
	 *
406
	 * @return string[]
407
	 */
408
	public function getTreeHeaders()
409
	{
410
		$fields = $this->getTreeViewModel()->getTreeField();
411
412
		return [
413
			'name' => $fields['fieldlabel'],
414
		];
415
	}
416
417
	/**
418
	 * Get tree entries.
419
	 *
420
	 * @return array[]
421
	 */
422
	public function getTreeEntries()
423
	{
424
		$relModuleName = $this->getRelatedModuleModel()->getName();
425
		$relationModelInstance = $this->getRelationModel();
426
		$template = $this->getTreeViewModel()->getTemplate();
427
		$showCreatorDetail = $relationModelInstance->get('creator_detail');
428
		$showComment = $relationModelInstance->get('relation_comment');
429
430
		$rows = $relationModelInstance->getRelationTree();
431
		$trees = [];
432
		foreach ($rows as &$row) {
433
			$pieces = explode('::', $row['parentTree']);
434
			end($pieces);
435
			$parent = prev($pieces);
436
			$parentName = '';
437
			if ($row['depth'] > 0) {
438
				$treeDetail = App\Fields\Tree::getValueByTreeId($template, $parent);
0 ignored issues
show
Bug introduced by
$template of type type is incompatible with the type integer expected by parameter $templateId of App\Fields\Tree::getValueByTreeId(). ( Ignorable by Annotation )

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

438
				$treeDetail = App\Fields\Tree::getValueByTreeId(/** @scrutinizer ignore-type */ $template, $parent);
Loading history...
439
				$parentName = '(' . App\Language::translate($treeDetail['name'], $relModuleName) . ') ';
0 ignored issues
show
Bug introduced by
$treeDetail['name'] of type array is incompatible with the type string expected by parameter $key of App\Language::translate(). ( Ignorable by Annotation )

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

439
				$parentName = '(' . App\Language::translate(/** @scrutinizer ignore-type */ $treeDetail['name'], $relModuleName) . ') ';
Loading history...
440
			}
441
			$tree = [
442
				'id' => $row['tree'],
443
				'name' => $parentName . App\Language::translate($row['name'], $relModuleName),
444
				'parent' => 0 == $parent ? '#' : $parent,
445
			];
446
			if ($showCreatorDetail) {
447
				$tree['rel_created_user'] = \App\Fields\Owner::getLabel($row['rel_created_user']);
448
				$tree['rel_created_time'] = App\Fields\DateTime::formatToDisplay($row['rel_created_time']);
449
			}
450
			if ($showComment) {
451
				$tree['rel_comment'] = $row['rel_comment'];
452
			}
453
			if (!empty($row['icon'])) {
454
				$tree['icon'] = $row['icon'];
455
			}
456
			$trees[] = $tree;
457
		}
458
		return $trees;
459
	}
460
461
	/**
462
	 * Function to get Total number of record in this relation.
463
	 *
464
	 * @return int
465
	 */
466
	public function getRelatedTreeEntriesCount()
467
	{
468
		$recordId = $this->getParentRecordModel()->getId();
469
		$relModuleId = $this->getRelatedModuleModel()->getId();
470
		$treeViewModel = $this->getTreeViewModel();
471
		$template = $treeViewModel->getTemplate();
472
473
		return (new \App\Db\Query())->from('vtiger_trees_templates_data ttd')->innerJoin('u_#__crmentity_rel_tree rel', 'rel.tree = ttd.tree')
0 ignored issues
show
Bug Best Practice introduced by
The expression return new App\Db\Query(...$relModuleId))->count() also could return the type string which is incompatible with the documented return type integer.
Loading history...
474
			->where(['ttd.templateid' => $template, 'rel.crmid' => $recordId, 'rel.relmodule' => $relModuleId])->count();
475
	}
476
477
	public function getCreateViewUrl()
478
	{
479
		$relationModelInstance = $this->getRelationModel();
480
		$relatedModel = $relationModelInstance->getRelationModuleModel();
481
		$parentRecordModule = $this->getParentRecordModel();
482
		$createViewUrl = $relatedModel->getCreateRecordUrl() . '&sourceModule=' . $parentRecordModule->getModule()->getName() . '&sourceRecord=' . $parentRecordModule->getId() . '&relationOperation=true&relationId=' . $relationModelInstance->getId();
483
		//To keep the reference fieldname and record value in the url if it is direct relation
484
		if ($relationModelInstance->isDirectRelation()) {
485
			$relationField = $relationModelInstance->getRelationField();
486
			$createViewUrl .= '&' . $relationField->getName() . '=' . $parentRecordModule->getId();
487
		}
488
		if (!empty(Config\Relation::$addSearchParamsToCreateView) && ($searchParams = $this->getArray('search_params')) && isset($searchParams['and']) && \is_array($searchParams['and'])) {
0 ignored issues
show
Bug introduced by
The type Config\Relation 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...
489
			foreach ($searchParams['and'] as $row) {
490
				if ('e' === $row['comparator']) {
491
					$createViewUrl .= "&{$row['field_name']}={$row['value']}";
492
				}
493
			}
494
		}
495
		return $createViewUrl;
496
	}
497
498
	/**
499
	 * Function to get the links for related list.
500
	 *
501
	 * @return Vtiger_Link_Model[]
502
	 */
503
	public function getLinks(): array
504
	{
505
		$parentRecordModel = $this->getParentRecordModel();
506
		$relationModelInstance = $this->getRelationModel();
507
		$relatedLink = [
508
			'RELATEDLIST_VIEWS' => [
509
				Vtiger_Link_Model::getInstanceFromValues([
510
					'linktype' => 'RELATEDLIST_VIEWS',
511
					'linklabel' => 'LBL_RECORDS_LIST',
512
					'view' => 'List',
513
					'linkicon' => 'far fa-list-alt',
514
				]),
515
				Vtiger_Link_Model::getInstanceFromValues([
516
					'linktype' => 'RELATEDLIST_VIEWS',
517
					'linklabel' => 'LBL_RECORDS_PREVIEW_LIST',
518
					'view' => 'ListPreview',
519
					'linkicon' => 'fas fa-desktop',
520
				]),
521
			],
522
		];
523
		if (!$parentRecordModel->isReadOnly()) {
524
			$selectLinks = $this->getSelectRelationLinks();
525 1
			foreach ($selectLinks as $selectLinkModel) {
526
				$selectLinkModel->set('_selectRelation', true)->set('_module', $relationModelInstance->getRelationModuleModel());
527 1
			}
528 1
			$relatedLink['LISTVIEWBASIC'] = array_merge($selectLinks, $this->getAddRelationLinks());
529
			if ('Documents' === $relationModelInstance->getRelationModuleModel()->getName()) {
0 ignored issues
show
introduced by
The condition 'Documents' === $relatio...oduleModel()->getName() is always false.
Loading history...
530 1
				$relatedLink['RELATEDLIST_MASSACTIONS'][] = Vtiger_Link_Model::getInstanceFromValues([
531 1
					'linktype' => 'RELATEDLIST_MASSACTIONS',
532 1
					'linklabel' => 'LBL_MASS_DOWNLOAD',
533 1
					'linkurl' => "javascript:Vtiger_RelatedList_Js.triggerMassDownload('index.php?module={$parentRecordModel->getModuleName()}&action=RelationAjax&mode=massDownload&src_record={$parentRecordModel->getId()}&relatedModule=Documents&mode=multiple','sendByForm')",
534 1
					'linkclass' => '',
535
					'linkicon' => 'fas fa-download',
536
				]);
537 1
			}
538 1
			if ($relationModelInstance->getRelationModuleModel()->isPermitted('QuickExportToExcel')) {
539
				$relatedLink['RELATEDLIST_MASSACTIONS'][] = Vtiger_Link_Model::getInstanceFromValues([
540
					'linktype' => 'RELATEDLIST_MASSACTIONS',
541
					'linklabel' => 'LBL_QUICK_EXPORT',
542
					'linkurl' => "javascript:Vtiger_RelatedList_Js.triggerMassAction('index.php?module={$parentRecordModel->getModuleName()}&action=RelationAjax&mode=exportToExcel&src_record={$parentRecordModel->getId()}&relatedModule={$relationModelInstance->getRelationModuleModel()->getName()}&relationId={$this->getRelationModel()->getId()}&isSortActive=true','sendByForm')",
543
					'linkclass' => '',
544
					'linkicon' => 'fas fa-file-export',
545
				]);
546
			}
547
		}
548
		return $relatedLink;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $relatedLink returns the type array<string,array<integer,Vtiger_Link_Model>> which is incompatible with the documented return type Vtiger_Link_Model[].
Loading history...
549
	}
550
551
	/**
552
	 * Function to get the select links for related list.
553
	 *
554
	 * @return Vtiger_Link_Model[]
555
	 */
556
	public function getSelectRelationLinks(): array
557
	{
558
		if (!$this->getRelationModel()->isSelectActionSupported() || $this->getParentRecordModel()->isReadOnly()) {
559
			return [];
560
		}
561
		$relatedModel = $this->getRelationModel()->getRelationModuleModel();
562
		if (!$relatedModel->isPermitted('DetailView')) {
563
			return [];
564
		}
565
		return [
566
			Vtiger_Link_Model::getInstanceFromValues([
567
				'linktype' => 'LISTVIEWBASIC',
568
				'linklabel' => \App\Language::translate('LBL_SELECT_RELATION', $relatedModel->getName()),
569
				'linkurl' => '',
570
				'linkicon' => 'fas fa-level-up-alt',
571
			]),
572
		];
573
	}
574
575
	/**
576
	 * Function to get the add links for related list.
577
	 *
578
	 * @return Vtiger_Link_Model[]
579
	 */
580
	public function getAddRelationLinks(): array
581
	{
582
		$relationModelInstance = $this->getRelationModel();
583
		if (!$relationModelInstance->isAddActionSupported() || $this->getParentRecordModel()->isReadOnly()) {
584
			return [];
585
		}
586
		$relatedModel = $relationModelInstance->getRelationModuleModel();
587
		$addLinkModel = [
588
			Vtiger_Link_Model::getInstanceFromValues([
589
				'linktype' => 'LISTVIEWBASIC',
590
				'linklabel' => App\Language::translate('LBL_ADD_RELATION', $relatedModel->getName()),
591
				'linkurl' => $this->getCreateViewUrl(),
592
				'linkqcs' => $relatedModel->isQuickCreateSupported(),
593
				'linkicon' => 'fas fa-plus',
594
			]),
595
		];
596
		if ('Documents' === $relatedModel->getName()) {
0 ignored issues
show
introduced by
The condition 'Documents' === $relatedModel->getName() is always false.
Loading history...
597
			$addLinkModel[] = Vtiger_Link_Model::getInstanceFromValues([
598
				'linktype' => 'LISTVIEWBASIC',
599
				'linklabel' => App\Language::translate('LBL_MASS_ADD', 'Documents'),
600
				'linkurl' => 'javascript:Vtiger_Index_Js.massAddDocuments("index.php?module=Documents&view=MassAddDocuments")',
601
				'linkicon' => 'yfi-document-templates',
602
			]);
603
		}
604
		return $addLinkModel;
605
	}
606
607
	public function getFavoriteRecords()
608
	{
609
		return (new App\Db\Query())->select(['relcrmid'])->from('u_#__favorites')
610
			->where([
611
				'module' => $this->getParentRecordModel()->getModuleName(),
612
				'relmodule' => $this->getRelatedModuleModel()->getName(),
613
				'crmid' => $this->getParentRecordModel()->getId(),
614
				'userid' => App\User::getCurrentUserId(),
615
			])
616
			->column();
617
	}
618
619
	/**
620
	 * Set fileds.
621
	 *
622
	 * @param string|string[] $fields
623
	 */
624
	public function setFields($fields)
625
	{
626
		if (\is_string($fields)) {
627
			$fields = explode(',', $fields);
628
		}
629
		$relatedListFields = [];
630
		$relFields = $this->getRelationModel()->getRelationFields();
631
		foreach ($fields as $fieldName) {
632
			$fieldModel = $this->relatedModuleModel->getFieldByName($fieldName);
633
			if ($fieldModel) {
634
				$relatedListFields[$fieldName] = $fieldModel;
635
			} elseif (isset($relFields[$fieldName])) {
636
				$relatedListFields[$fieldName] = $relFields[$fieldName];
637
			}
638
		}
639
		$this->relationModel->set('QueryFields', $relatedListFields);
640
	}
641
642
	/**
643
	 * Get widgets instances.
644
	 *
645
	 * @param int $recordId
646
	 *
647
	 * @return array
648
	 */
649
	public function getWidgets(int $recordId): array
650
	{
651
		$widgets = [];
652
		$moduleModel = $this->getRelatedModuleModel();
653
		foreach ($this->getWidgetsList() as $widgetCol) {
654
			foreach ($widgetCol as $widget) {
655
				$widgetName = Vtiger_Loader::getComponentClassName('Widget', $widget['type'], $moduleModel->getName());
656
				if (class_exists($widgetName)) {
657
					$widgetInstance = new $widgetName($moduleModel->getName(), $moduleModel, $recordId, $widget);
658
					$widgetObject = $widgetInstance->getWidget();
659
					if (\count($widgetObject) > 0) {
660
						$widgets[$widgetObject['wcol']][] = $widgetObject;
661
					}
662
				}
663
			}
664
		}
665
		return $widgets;
666
	}
667
668
	/**
669
	 * Get widgets list.
670
	 *
671
	 * @return array
672
	 */
673
	public function getWidgetsList(): array
674
	{
675
		$relationId = $this->getRelationModel()->getId();
676
		if (\App\Cache::has('RelatedModuleWidgets', $relationId)) {
677
			return \App\Cache::get('RelatedModuleWidgets', $relationId);
678
		}
679
		$query = (new App\Db\Query())->from('a_#__relatedlists_widgets')->where(['relation_id' => $relationId]);
680
		$dataReader = $query->orderBy(['sequence' => SORT_ASC])->createCommand()->query();
681
		$widgets = [1 => [], 2 => [], 3 => []];
682
		while ($row = $dataReader->read()) {
683
			$row['data'] = \App\Json::decode($row['data']);
684
			$widgets[$row['wcol']][$row['id']] = $row;
685
		}
686
		$dataReader->close();
687
		App\Cache::save('RelatedModuleWidgets', $relationId, $widgets);
688
		return $widgets;
689
	}
690
691
	/**
692
	 * Check if widgets exist.
693
	 *
694
	 * @return bool
695
	 */
696
	public function isWidgetsList(): bool
697
	{
698
		$widgets = $this->getWidgetsList();
699
		return !empty($widgets[1]) || !empty($widgets[2]) || !empty($widgets[3]);
700
	}
701
702
	/**
703
	 * Locked fields according to parameters passed.
704
	 *
705
	 * @param App\Request $request
706
	 *
707
	 * @return void
708
	 */
709
	public function loadSearchLockedFields(App\Request $request): void
710
	{
711
		$moduleModel = $this->getRelationModel()->getRelationModuleModel();
712
		if (!$request->isEmpty('lockedFields')) {
713
			foreach ($request->getArray('lockedFields') as $value) {
714
				$fieldModel = $moduleModel->getFieldByName($value);
715
				$fieldModel->set('searchLockedFields', true);
716
			}
717
		}
718
		if (!$request->isEmpty('lockedEmptyFields')) {
719
			foreach ($request->getArray('lockedEmptyFields') as $value) {
720
				$fieldModel = $moduleModel->getFieldByName($value);
721
				$fieldModel->set('searchLockedEmptyFields', true);
722
			}
723
		}
724
	}
725
}
726