Vtiger_Relation_Model::transferDelete()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
eloc 11
dl 0
loc 13
ccs 0
cts 6
cp 0
rs 9.9
c 0
b 0
f 0
cc 2
nc 2
nop 1
crap 6
1
<?php
2
/* +***********************************************************************************
3
 * The contents of this file are subject to the vtiger CRM Public License Version 1.0
4
 * ("License"); You may not use this file except in compliance with the License
5
 * The Original Code is:  vtiger CRM Open Source
6
 * The Initial Developer of the Original Code is vtiger.
7
 * Portions created by vtiger are Copyright (C) vtiger.
8
 * All Rights Reserved.
9
 * Contributor(s): YetiForce S.A.
10
 * *********************************************************************************** */
11
12
class Vtiger_Relation_Model extends \App\Base
13
{
14
	/**
15
	 *  Cached instances.
16
	 *
17
	 * @var Vtiger_Relation_Model[]
18
	 */
19
	protected static $cachedInstances = [];
20
	/**
21
	 * Cached instances by relation id.
22
	 *
23
	 * @var Vtiger_Relation_Model[]
24
	 */
25
	protected static $cachedInstancesById = [];
26
	protected $parentModule = false;
27
	protected $relatedModule = false;
28
	/**
29
	 * @var \App\Relation\RelationAbstraction Class that includes basic operations on relations
30
	 */
31
	protected $typeRelationModel;
32
	/**
33
	 * @var array Custom view list
34
	 */
35 1
	protected $customViewList;
36
37 1
	//one to many
38
	const RELATION_O2M = 1;
39
40
	//Many to many and many to one
41
	const RELATION_M2M = 2;
42
43
	/**
44
	 * Function returns the relation id.
45
	 *
46
	 * @return int
47 4
	 */
48
	public function getId()
49 4
	{
50
		return $this->get('relation_id');
51 4
	}
52
53
	/**
54
	 * Function sets the relation's parent module model.
55
	 *
56
	 * @param Vtiger_Module_Model $moduleModel
57
	 *
58
	 * @return Vtiger_Relation_Model
59 2
	 */
60
	public function setParentModuleModel($moduleModel)
61 2
	{
62
		$this->parentModule = $moduleModel;
63
		return $this;
64 2
	}
65
66
	/**
67
	 * Function that returns the relation's parent module model.
68
	 *
69
	 * @return Vtiger_Module_Model
70
	 */
71
	public function getParentModuleModel()
72
	{
73
		if (empty($this->parentModule)) {
74 2
			$this->parentModule = Vtiger_Module_Model::getInstance($this->get('tabid'));
75
		}
76 2
		return $this->parentModule;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->parentModule also could return the type boolean which is incompatible with the documented return type Vtiger_Module_Model.
Loading history...
77
	}
78 2
79
	/**
80
	 * Gets parent record model.
81
	 *
82
	 * @return Vtiger_Record_Model|null
83
	 */
84
	public function getParentRecord(): ?Vtiger_Record_Model
85
	{
86 3
		return $this->get('parentRecord') ?? null;
87
	}
88 3
89 1
	/**
90
	 * Set relation's parent module model.
91 3
	 *
92
	 * @param Vtiger_Module_Model $relationModel
93
	 *
94
	 * @return $this
95
	 */
96
	public function setRelationModuleModel($relationModel)
97
	{
98
		$this->relatedModule = $relationModel;
99 1
		return $this;
100
	}
101 1
102 1
	/**
103
	 * Function that returns the relation's related module model.
104
	 *
105 1
	 * @return Vtiger_Module_Model
106
	 */
107
	public function getRelationModuleModel()
108
	{
109
		if (!$this->relatedModule) {
110
			$this->relatedModule = Vtiger_Module_Model::getInstance($this->get('related_tabid'));
111
		}
112
		return $this->relatedModule;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->relatedModule also could return the type true which is incompatible with the documented return type Vtiger_Module_Model.
Loading history...
113
	}
114
115
	/**
116
	 * Get relation module name.
117
	 *
118
	 * @return string
119
	 */
120
	public function getRelationModuleName()
121
	{
122
		$relationModuleName = $this->get('relatedModuleName');
123
		if (!empty($relationModuleName)) {
124
			return $relationModuleName;
125
		}
126
		return $this->getRelationModuleModel()->getName();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getRelationModuleModel()->getName() returns the type boolean which is incompatible with the documented return type string.
Loading history...
127
	}
128
129
	/**
130
	 * Get actions.
131
	 *
132
	 * @return string[]
133
	 */
134
	public function getActions()
135
	{
136
		if (\is_array($this->get('actions'))) {
137
			return $this->get('actions');
138
		}
139
		// No actions for Activity history
140
		if ('Activity History' === $this->get('c')) {
141
			return [];
142
		}
143
		$actions = explode(',', strtolower($this->get('actions')));
144
		$this->set('actions', $actions);
145
		return $actions;
146
	}
147
148
	/**
149
	 * Check if action is supported.
150
	 *
151
	 * @param string $actionName
152
	 *
153
	 * @return bool
154
	 */
155
	public function isActionSupported($actionName)
156
	{
157
		return \in_array(strtolower($actionName), $this->getActions());
158
	}
159
160
	/**
161
	 * Is record selection action available.
162
	 *
163
	 * @return bool
164
	 */
165 2
	public function isSelectActionSupported()
166
	{
167 2
		return $this->isActionSupported('select');
168 2
	}
169
170
	/**
171
	 * Is record add action available.
172
	 *
173
	 * @return bool
174
	 */
175
	public function isAddActionSupported()
176
	{
177
		return $this->isActionSupported('add') && $this->getRelationModuleModel()->isPermitted('CreateView');
178 2
	}
179
180 2
	/**
181 2
	 * Check favorite.
182
	 */
183
	public function isFavorites()
184
	{
185
		return 1 == $this->get('favorites') ? true : false;
186
	}
187
188
	/**
189
	 * Check related view type.
190
	 *
191 2
	 * @param string $type
192
	 *
193 2
	 * @return bool
194 1
	 */
195
	public function isRelatedViewType($type)
196 2
	{
197
		return false !== strpos($this->get('view_type'), $type);
198
	}
199
200
	/**
201
	 * Show user who created relation.
202
	 *
203
	 * @return bool
204
	 */
205
	public function showCreatorDetail()
206
	{
207
		if (0 === $this->get('creator_detail') || self::RELATION_M2M !== $this->getRelationType()) {
208
			return false;
209
		}
210
		return (bool) $this->get('creator_detail');
211
	}
212
213
	/**
214
	 * Show comments in related module.
215
	 *
216
	 * @return bool
217
	 */
218
	public function showComment()
219
	{
220
		if (0 === $this->get('relation_comment') || self::RELATION_M2M !== $this->getRelationType()) {
221
			return false;
222
		}
223
		return (bool) $this->get('relation_comment');
224
	}
225
226
	/**
227
	 * Get query generator instance.
228
	 *
229
	 * @return \App\QueryGenerator
230
	 */
231
	public function getQueryGenerator(): App\QueryGenerator
232
	{
233
		if (!$this->has('query_generator')) {
234
			$this->set('query_generator', new \App\QueryGenerator($this->getRelationModuleName()));
235
		}
236
		return $this->get('query_generator');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->get('query_generator') could return the type null which is incompatible with the type-hinted return App\QueryGenerator. Consider adding an additional type-check to rule them out.
Loading history...
237
	}
238
239
	/**
240
	 * Get relation type.
241
	 *
242
	 * @return int
243
	 */
244
	public function getRelationType()
245
	{
246
		if (!$this->has('relationType')) {
247 2
			$this->set('relationType', $this->getTypeRelationModel()->getRelationType());
248
		}
249 2
		return $this->get('relationType');
250 2
	}
251 2
252
	/**
253 2
	 * Get related view type.
254
	 *
255
	 * @return string[]
256
	 */
257
	public function getRelatedViewType(): array
258
	{
259
		return explode(',', $this->get('view_type')) ?? [];
260
	}
261
262
	/**
263
	 * Get custom view.
264
	 *
265 2
	 * @return string[]
266 2
	 */
267 2
	public function getCustomView(): array
268 2
	{
269 2
		if ($this->isEmpty('custom_view')) {
270 2
			return [];
271
		}
272
		return explode(',', $this->get('custom_view')) ?? [];
273 2
	}
274 2
275 2
	/**
276 2
	 * Get relation model instance.
277 2
	 *
278 2
	 * @param Vtiger_Module_Model $parentModuleModel
279
	 * @param Vtiger_Module_Model $relatedModuleModel
280 2
	 * @param bool|int            $relationId
281
	 *
282 1
	 * @return $this|bool
283
	 */
284
	public static function getInstance($parentModuleModel, $relatedModuleModel, $relationId = false)
285
	{
286
		$relKey = $parentModuleModel->getId() . '_' . $relatedModuleModel->getId() . '_' . $relationId;
287
		if (isset(self::$cachedInstances[$relKey])) {
288 2
			return self::$cachedInstances[$relKey] ? clone self::$cachedInstances[$relKey] : self::$cachedInstances[$relKey];
289
		}
290 2
		if (('ModComments' == $relatedModuleModel->getName() && $parentModuleModel->isCommentEnabled()) || 'Documents' == $parentModuleModel->getName()) {
291 2
			$moduleName = 'ModComments' == $relatedModuleModel->getName() ? $relatedModuleModel->getName() : $parentModuleModel->getName();
292 2
			$relationModelClassName = Vtiger_Loader::getComponentClassName('Model', 'Relation', $moduleName);
293 2
			$relationModel = new $relationModelClassName();
294
			$relationModel->setParentModuleModel($parentModuleModel)->setRelationModuleModel($relatedModuleModel);
295
			if (method_exists($relationModel, 'setExceptionData')) {
296 2
				$relationModel->setExceptionData();
297 2
			}
298 2
			self::$cachedInstances[$relKey] = $relationModel;
299
			return clone $relationModel;
300
		}
301 2
		if (empty($relationId)) {
302
			$row = current(\App\Relation::getByModule($parentModuleModel->getName(), true, $relatedModuleModel->getName()));
0 ignored issues
show
Bug introduced by
$relatedModuleModel->getName() of type boolean is incompatible with the type null|string expected by parameter $relatedModuleName of App\Relation::getByModule(). ( Ignorable by Annotation )

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

302
			$row = current(\App\Relation::getByModule($parentModuleModel->getName(), true, /** @scrutinizer ignore-type */ $relatedModuleModel->getName()));
Loading history...
Bug introduced by
$parentModuleModel->getName() of type boolean is incompatible with the type string expected by parameter $moduleName of App\Relation::getByModule(). ( Ignorable by Annotation )

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

302
			$row = current(\App\Relation::getByModule(/** @scrutinizer ignore-type */ $parentModuleModel->getName(), true, $relatedModuleModel->getName()));
Loading history...
303
		} else {
304
			$row = \App\Relation::getById($relationId);
305
			if (1 === $row['presence'] || $row['tabid'] !== $parentModuleModel->getId() || $row['related_tabid'] !== $relatedModuleModel->getId()) {
306
				$row = [];
307
			}
308
		}
309
		if ($row) {
310
			$row['modulename'] = $row['related_modulename'];
311 2
			$relationModelClassName = Vtiger_Loader::getComponentClassName('Model', 'Relation', $parentModuleModel->get('name'));
312
			$relationModel = new $relationModelClassName();
313 2
			$relationModel->setData($row)->setParentModuleModel($parentModuleModel)->setRelationModuleModel($relatedModuleModel);
314
			$relationModel->set('relatedModuleName', $row['related_modulename']);
315
			self::$cachedInstances[$relKey] = $relationModel;
316
			self::$cachedInstancesById[$row['relation_id']] = $relationModel;
317 2
			return clone $relationModel;
318
		}
319
		self::$cachedInstances[$relKey] = false;
320
		return false;
321
	}
322 2
323 2
	/**
324 2
	 * Get relation model instance by relation id.
325
	 *
326 2
	 * @param int $relationId
327
	 *
328
	 * @return self|bool
329
	 */
330 2
	public static function getInstanceById(int $relationId)
331
	{
332
		if (!isset(self::$cachedInstancesById[$relationId])) {
333 2
			$row = \App\Relation::getById($relationId);
334 2
			$relationModel = false;
335 2
			if ($row) {
336
				$row['modulename'] = $row['related_modulename'];
337 2
				$parentModuleModel = Vtiger_Module_Model::getInstance($row['tabid']);
338
				$relationModelClassName = Vtiger_Loader::getComponentClassName('Model', 'Relation', $parentModuleModel->getName());
339
				$relationModel = new $relationModelClassName();
340
				$relationModel->setData($row)->setParentModuleModel($parentModuleModel)->setRelationModuleModel(Vtiger_Module_Model::getInstance($row['related_modulename']));
341
				$relationModel->set('relatedModuleName', $row['related_modulename']);
342
				if (method_exists($relationModel, 'setExceptionData')) {
343
					$relationModel->setExceptionData();
344
				}
345 2
			}
346
			self::$cachedInstancesById[$relationId] = $relationModel;
347 2
		}
348 2
		return self::$cachedInstancesById[$relationId] ? clone self::$cachedInstancesById[$relationId] : null;
349
	}
350 1
351 1
	/**
352
	 * Get type relation model.
353 1
	 *
354
	 * @return \App\Relation\RelationAbstraction
355
	 */
356 1
	public function getTypeRelationModel(): App\Relation\RelationAbstraction
357
	{
358
		if (!isset($this->typeRelationModel)) {
359
			$name = ucfirst($this->get('name'));
360
			$relationClassName = Vtiger_Loader::getComponentClassName('Relation', $name, $this->getParentModuleModel()->getName(), false);
361 1
			if (!$relationClassName) {
362 1
				$relationClassName = Vtiger_Loader::getComponentClassName('Relation', $name, $this->getRelationModuleName());
363 1
			}
364
			if (class_exists($relationClassName)) {
365
				$this->typeRelationModel = new $relationClassName();
366
				$this->typeRelationModel->relationModel = &$this;
367
			} else {
368
				App\Log::error("Not exist relation: {$name} in " . __METHOD__);
369
				throw new \App\Exceptions\NotAllowedMethod('LBL_NOT_EXIST_RELATION: ' . $name);
370 1
			}
371 1
		}
372 1
		return $this->typeRelationModel;
373 1
	}
374
375
	/**
376 1
	 * Get query form relation.
377
	 *
378 1
	 * @throws \App\Exceptions\NotAllowedMethod
379 1
	 *
380
	 * @return \App\QueryGenerator
381 1
	 */
382
	public function getQuery()
383
	{
384
		if (empty($this->get('parentRecord'))) {
385
			App\Log::error('No value parentRecord in ' . __METHOD__);
386
			throw new \App\Exceptions\IllegalValue('ERR_NO_VALUE||parentRecord');
387
		}
388
		$queryGenerator = $this->getQueryGenerator();
389
		$queryGenerator->setSourceRecord($this->get('parentRecord')->getId());
390
		$this->getTypeRelationModel()->getQuery();
391
		if ($this->showCreatorDetail()) {
392
			$queryGenerator->setCustomColumn('rel_created_user');
393 2
			$queryGenerator->setCustomColumn('rel_created_time');
394
		}
395 2
		if ($this->showComment()) {
396 2
			$queryGenerator->setCustomColumn('rel_comment');
397
		}
398 2
		$fields = array_keys($this->getQueryFields());
399 2
		$fields[] = 'id';
400 2
		$queryGenerator->setFields($fields);
401 2
		return $queryGenerator;
402 2
	}
403 2
404 2
	/**
405 2
	 * Get query fields.
406 2
	 *
407 2
	 * @return Vtiger_Field_Model[] with field name as key
408
	 */
409
	public function getQueryFields()
410
	{
411 2
		if ($this->has('QueryFields')) {
412 1
			return $this->get('QueryFields');
413 1
		}
414 1
		$relatedListFields = [];
415 1
		$relatedModuleModel = $this->getRelationModuleModel();
416 1
		// Get fields from panel
417
		foreach (App\Field::getFieldsFromRelation($this->getId()) as $fieldName) {
418
			$relatedListFields[$fieldName] = $relatedModuleModel->getFieldByName($fieldName);
419
		}
420
		if ($relatedListFields) {
421
			$this->set('QueryFields', $relatedListFields);
422
			return $relatedListFields;
423 2
		}
424
		$queryGenerator = $this->getQueryGenerator();
425 2
		$entity = $queryGenerator->getEntityModel();
426
		if (!empty($entity->relationFields)) {
427
			// Get fields from entity model
428
			foreach ($entity->relationFields as $fieldName) {
429
				$relatedListFields[$fieldName] = $relatedModuleModel->getFieldByName($fieldName);
430
			}
431
		} else {
432
			// Get fields from default CustomView
433
			$queryGenerator->initForDefaultCustomView(true, true);
434
			foreach ($queryGenerator->getFields() as $fieldName) {
435
				if ('id' !== $fieldName) {
436
					$relatedListFields[$fieldName] = $relatedModuleModel->getFieldByName($fieldName);
437
				}
438
			}
439
			$relatedListFields['id'] = true;
440
		}
441
		if ($relatedListFields) {
442
			$this->set('QueryFields', $relatedListFields);
443
			return $relatedListFields;
444
		}
445
		$this->set('QueryFields', $relatedListFields);
446
		return $relatedListFields;
447
	}
448
449
	/**
450
	 * Function to get relation field for relation module and parent module.
451
	 *
452
	 * @return Vtiger_Field_Model
453
	 */
454
	public function getRelationField()
455
	{
456
		if ($this->has('RelationField')) {
457
			return $this->get('RelationField');
458
		}
459
		$relatedModuleModel = $this->getRelationModuleModel();
460
		$parentModuleName = $this->getParentModuleModel()->getName();
461
		$relatedModelFields = $relatedModuleModel->getFields();
462
		if (!$this->isEmpty('field_name') && isset($relatedModelFields[$this->get('field_name')])) {
463
			$relationField = $relatedModelFields[$this->get('field_name')];
464
		} else {
465
			$fieldRel = App\Field::getRelatedFieldForModule($relatedModuleModel->getName(), $parentModuleName);
466
			if (isset($fieldRel['fieldid'])) {
467
				foreach ($relatedModelFields as $fieldModel) {
468
					if ($fieldModel->getId() === $fieldRel['fieldid']) {
469
						$relationField = $fieldModel;
470
						break;
471
					}
472
				}
473
			}
474
		}
475
		if (empty($relationField)) {
476
			$relationField = false;
477
			foreach ($relatedModelFields as $fieldModel) {
478
				if ($fieldModel->isReferenceField()) {
479
					$referenceList = $fieldModel->getReferenceList();
480
					if (!empty($referenceList) && \in_array($parentModuleName, $referenceList)) {
481
						$relationField = $fieldModel;
482
						break;
483
					}
484
				}
485
			}
486
		}
487
		$this->set('RelationField', $relationField ?: false);
488
		return $relationField;
489
	}
490
491
	/**
492
	 * Get relation inventory fields.
493
	 *
494
	 * @return Vtiger_Basic_InventoryField[]
495
	 */
496
	public function getRelationInventoryFields()
497
	{
498
		if (!$this->has('RelationInventoryFields')) {
499
			$this->set('RelationInventoryFields', []);
500
			if ($this->getRelationModuleModel()->isInventory()) {
501
				$columns = (new \App\Db\Query())
502
					->select(['fieldname'])
503
					->from('a_#__relatedlists_inv_fields')
504
					->where(['relation_id' => $this->getId()])
505
					->orderBy('sequence')
506
					->column();
507
				$inventoryFields = Vtiger_Inventory_Model::getInstance($this->getRelationModuleModel()->getName())->getFields();
0 ignored issues
show
Bug introduced by
$this->getRelationModuleModel()->getName() of type boolean is incompatible with the type string expected by parameter $moduleName of Vtiger_Inventory_Model::getInstance(). ( Ignorable by Annotation )

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

507
				$inventoryFields = Vtiger_Inventory_Model::getInstance(/** @scrutinizer ignore-type */ $this->getRelationModuleModel()->getName())->getFields();
Loading history...
508
				$fields = [];
509
				foreach ($columns as &$column) {
510
					if (!empty($inventoryFields[$column]) && $inventoryFields[$column]->isVisible()) {
511
						$fields[$column] = $inventoryFields[$column];
512
					}
513
				}
514
				$this->set('RelationInventoryFields', $fields);
515
			}
516
		}
517
		return $this->get('RelationInventoryFields');
518
	}
519
520
	/**
521
	 * Function which will specify whether the relation is editable.
522
	 *
523
	 * @return bool
524
	 */
525
	public function isEditable(): bool
526
	{
527
		return $this->getRelationModuleModel()->isPermitted('EditView');
528
	}
529
530
	/**
531
	 * Function which will specify whether the relation is deletable.
532
	 *
533
	 * @param \Vtiger_Record_Model|null $recordModel
534
	 * @param int|null                  $recordId
535
	 *
536
	 * @return bool
537
	 */
538
	public function privilegeToDelete(Vtiger_Record_Model $recordModel = null, int $recordId = null): bool
539
	{
540
		$returnVal = $this->getRelationModuleModel()->isPermitted('RemoveRelation');
541
		if ($returnVal && $this->getRelationType() === static::RELATION_O2M && ($fieldModel = $this->getRelationField())) {
542
			if (!$recordModel && $recordId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $recordId of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
543
				$recordModel = \Vtiger_Record_Model::getInstanceById($recordId);
544
			}
545
			$returnVal = !$fieldModel->isMandatory() && $fieldModel->isEditable() && !$fieldModel->isEditableReadOnly() && (!$recordModel || $recordModel->isEditable());
546
		}
547
		return $returnVal;
548
	}
549
550
	/**
551
	 * Function which will specify whether the tree element is deletable.
552
	 *
553
	 * @return bool
554
	 */
555
	public function privilegeToTreeDelete(): bool
556
	{
557
		return $this->getRelationModuleModel()->isPermitted('RemoveRelation');
558
	}
559
560
	/**
561
	 * Get list url for record.
562
	 *
563
	 * @param Vtiger_Module_Model $parentRecordModel
564
	 *
565
	 * @return string
566
	 */
567
	public function getListUrl(Vtiger_Record_Model $parentRecordModel): string
568
	{
569
		$url = 'index.php?module=' . $this->getParentModuleModel()->get('name') . '&relatedModule=' . $this->get('modulename') .
570
			'&view=Detail&record=' . $parentRecordModel->getId() . '&mode=showRelatedList&relationId=' . $this->getId();
571
		if ('Calendar' == $this->get('modulename')) {
572
			$url .= '&time=current';
573
		}
574
		return $url;
575
	}
576
577
	/**
578
	 * Get create url from parent record.
579
	 *
580
	 * @param bool $fullView
581
	 *
582
	 * @return string
583
	 */
584
	public function getCreateViewUrl(bool $fullView = false)
585
	{
586
		$parentRecord = $this->getParentRecord();
587
		$relatedModuleModel = $this->getRelationModuleModel();
588
		if (!$fullView && $relatedModuleModel->isQuickCreateSupported()) {
589
			$createViewUrl = $relatedModuleModel->getQuickCreateUrl();
590
		} else {
591
			$createViewUrl = $relatedModuleModel->getCreateRecordUrl();
592
		}
593
		$createViewUrl .= '&sourceModule=' . $parentRecord->getModule()->getName() . '&sourceRecord=' . $parentRecord->getId() . '&relationOperation=true&relationId=' . $this->getId();
594
		if ($this->isDirectRelation()) {
595
			$relationField = $this->getRelationField();
596
			$createViewUrl .= '&' . $relationField->getName() . '=' . $parentRecord->getId();
597
		}
598
599
		return $createViewUrl;
600
	}
601
602
	/**
603
	 * Get delete url from parent record.
604
	 *
605
	 * @param int $relatedRecordId
606
	 *
607
	 * @return string
608
	 */
609
	public function getDeleteUrl(int $relatedRecordId)
610
	{
611
		$parentModuleName = $this->getParentModuleModel()->getName();
612
		$relatedModuleName = $this->getRelationModuleModel()->getName();
613
		$recordId = $this->getParentRecord()->getId();
614
615
		return "index.php?module={$parentModuleName}&related_module={$relatedModuleName}&action=RelationAjax&mode=deleteRelation&related_record_list=[{$relatedRecordId}]&src_record={$recordId}&relationId={$this->getId()}";
616
	}
617
618
	/**
619
	 * Add relation.
620
	 *
621
	 * @param int       $sourceRecordId
622
	 * @param int|int[] $destinationRecordIds
623
	 * @param mixed     $params
624
	 */
625
	public function addRelation($sourceRecordId, $destinationRecordIds, $params = false)
0 ignored issues
show
Unused Code introduced by
The parameter $params 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

625
	public function addRelation($sourceRecordId, $destinationRecordIds, /** @scrutinizer ignore-unused */ $params = false)

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...
626
	{
627
		$result = false;
628
		$sourceModuleName = $this->getParentModuleModel()->getName();
629
		$relationModel = $this->getTypeRelationModel();
630
		if (!\is_array($destinationRecordIds)) {
631
			$destinationRecordIds = [$destinationRecordIds];
632
		}
633
		$data = [
634
			'CRMEntity' => $this->getParentModuleModel()->getEntityInstance(),
635
			'sourceModule' => $sourceModuleName,
636
			'sourceRecordId' => $sourceRecordId,
637
			'destinationModule' => $this->getRelationModuleModel()->getName(),
638
			'relationId' => $this->getId(),
639
		];
640
		$eventHandler = new \App\EventHandler();
641
		$eventHandler->setModuleName($sourceModuleName);
642
		foreach ($destinationRecordIds as $destinationRecordId) {
643
			$data['destinationRecordId'] = $destinationRecordId;
644
			$eventHandler->setParams($data);
645
			$eventHandler->trigger('EntityBeforeLink');
646
			if ($result = $relationModel->create($sourceRecordId, $destinationRecordId)) {
647
				\CRMEntity::trackLinkedInfo($sourceRecordId);
648
				$eventHandler->trigger('EntityAfterLink');
649
			}
650
		}
651
		return $result;
652
	}
653
654
	/**
655
	 * Transfer.
656
	 *
657
	 * @param array $recordsToTransfer
658
	 */
659
	public function transfer(array $recordsToTransfer)
660
	{
661
		$relationModel = $this->getTypeRelationModel();
662
		$eventHandler = new \App\EventHandler();
663
		$eventHandler->setModuleName($this->getParentModuleModel()->getName());
664
		$toRecordId = $this->get('parentRecord')->getId();
665
		$params = ['sourceRecordId' => $toRecordId, 'sourceModule' => $eventHandler->getModuleName(), 'destinationModule' => $this->getRelationModuleModel()->getName()];
666
667
		foreach ($recordsToTransfer as $relatedRecordId => $fromRecordId) {
668
			$params['destinationRecordId'] = $relatedRecordId;
669
			$eventHandler->setParams($params);
670
			$eventHandler->trigger('EntityBeforeTransferUnLink');
671
			if ($relationModel->transfer($relatedRecordId, $fromRecordId, $toRecordId)) {
672
				\CRMEntity::trackLinkedInfo([$toRecordId, $fromRecordId]);
673
				$eventHandler->trigger('EntityAfterTransferLink');
674
			}
675
		}
676
	}
677
678
	/**
679
	 * Transfer tree relation.
680
	 *
681
	 * @param array $relationRecords
682
	 */
683
	public function transferTree(array $relationRecords)
684
	{
685
		$recordId = $this->get('parentRecord')->getId();
686
		$dbCommand = \App\Db::getInstance()->createCommand();
687
		foreach ($relationRecords as $tree => $fromId) {
688
			if ($dbCommand->update('u_#__crmentity_rel_tree', ['crmid' => $recordId], ['crmid' => $fromId, 'relmodule' => $this->getRelationModuleModel()->getId(), 'tree' => $tree])->execute()) {
689
				$dbCommand->update('vtiger_crmentity', ['modifiedtime' => date('Y-m-d H:i:s'), 'modifiedby' => \App\User::getCurrentUserId()], ['crmid' => [$fromId, $recordId]])->execute();
690
			}
691
		}
692
	}
693
694
	/**
695
	 * Delete relation.
696
	 *
697
	 * @param int $relId
698
	 */
699
	public function transferDelete(int $relId)
700
	{
701
		$recordId = $this->get('parentRecord')->getId();
702
		$params = ['sourceRecordId' => $recordId,
703
			'sourceModule' => $this->getParentModuleModel()->getName(),
704
			'destinationModule' => $this->getRelationModuleModel()->getName(),
705
			'destinationRecordId' => $relId, ];
706
		$eventHandler = new \App\EventHandler();
707
		$eventHandler->setModuleName($this->getParentModuleModel()->getName());
708
		$eventHandler->setParams($params);
709
		$eventHandler->trigger('EntityBeforeTransferUnLink');
710
		if ($this->getTypeRelationModel()->delete($recordId, $relId)) {
711
			$eventHandler->trigger('EntityAfterTransferUnLink');
712
		}
713
	}
714
715
	/**
716
	 * Delete relation.
717
	 *
718
	 * @param int $sourceRecordId
719
	 * @param int $relatedRecordId
720
	 *
721
	 * @return bool
722
	 */
723
	public function deleteRelation($sourceRecordId, $relatedRecordId)
724
	{
725
		$sourceModuleName = $this->getParentModuleModel()->getName();
726
		$destinationModuleName = $this->getRelationModuleModel()->getName();
727
		$result = false;
728 2
		if ('ModComments' === $destinationModuleName) {
0 ignored issues
show
introduced by
The condition 'ModComments' === $destinationModuleName is always false.
Loading history...
729
			include_once 'modules/ModTracker/ModTracker.php';
730 2
			ModTracker::unLinkRelation($sourceModuleName, $sourceRecordId, $destinationModuleName, $relatedRecordId);
731 2
			$result = true;
732
		} elseif (!($this->getRelationField() && $this->getRelationField()->isMandatory())) {
733
			$destinationModuleFocus = $this->getRelationModuleModel()->getEntityInstance();
734 2
			$eventHandler = new \App\EventHandler();
735 2
			$eventHandler->setModuleName($sourceModuleName);
736 2
			$eventHandler->setParams([
737 2
				'CRMEntity' => $destinationModuleFocus,
738 2
				'sourceModule' => $sourceModuleName,
739 2
				'sourceRecordId' => $sourceRecordId,
740 1
				'destinationModule' => $destinationModuleName,
741
				'destinationRecordId' => $relatedRecordId,
742 2
				'relatedName' => $this->get('name'),
743 2
			]);
744
			$eventHandler->trigger('EntityBeforeUnLink');
745 2
			if ($result = $this->getTypeRelationModel()->delete($sourceRecordId, $relatedRecordId)) {
746 2
				$destinationModuleFocus->trackUnLinkedInfo($sourceRecordId);
747
				$eventHandler->trigger('EntityAfterUnLink');
748 2
			}
749 2
		}
750 2
		return $result;
751 2
	}
752
753 2
	/**
754
	 * Function to add tree type relation.
755
	 *
756 2
	 * @param int    $crmid
757 2
	 * @param string $tree
758 2
	 */
759
	public function addRelationTree($crmid, $tree)
760 2
	{
761
		App\Db::getInstance()->createCommand()->insert('u_#__crmentity_rel_tree', [
762
			'crmid' => $crmid,
763
			'tree' => $tree,
764
			'module' => $this->getParentModuleModel()->getId(),
765
			'relmodule' => $this->getRelationModuleModel()->getId(),
766
			'rel_created_user' => App\User::getCurrentUserId(),
767
			'rel_created_time' => date('Y-m-d H:i:s'),
768
		])->execute();
769
	}
770
771
	/**
772
	 * Function to delete tree type relation.
773
	 *
774
	 * @param int    $crmid
775
	 * @param string $tree
776
	 */
777
	public function deleteRelationTree($crmid, $tree)
778
	{
779
		App\Db::getInstance()->createCommand()
780
			->delete('u_#__crmentity_rel_tree', ['crmid' => $crmid, 'tree' => $tree, 'module' => $this->getParentModuleModel()->getId(), 'relmodule' => $this->getRelationModuleModel()->getId()])
781
			->execute();
782
	}
783
784
	/**
785
	 * Query tree category relation.
786
	 *
787
	 * @return \App\Db\Query
788
	 */
789
	public function getRelationTreeQuery()
790
	{
791
		$template = [];
792
		foreach ($this->getRelationModuleModel()->getFieldsByType('tree') as $field) {
793
			if ($field->isActiveField()) {
794
				$template[] = $field->getFieldParams();
795
			}
796
		}
797
		return (new \App\Db\Query())
798
			->select(['ttd.*', 'rel.crmid', 'rel.rel_created_time', 'rel.rel_created_user', 'rel.rel_comment'])
799
			->from('vtiger_trees_templates_data ttd')
800
			->innerJoin('u_#__crmentity_rel_tree rel', 'rel.tree = ttd.tree')
801
			->where(['ttd.templateid' => $template, 'rel.crmid' => $this->get('parentRecord')->getId(), 'rel.relmodule' => $this->getRelationModuleModel()->getId()]);
802
	}
803
804
	/**
805
	 * Tree category relation.
806
	 *
807
	 * @return array
808
	 */
809
	public function getRelationTree()
810
	{
811
		return $this->getRelationTreeQuery()->all();
812
	}
813
814
	/**
815
	 * Is the tree type relation available.
816
	 *
817
	 * @return bool
818
	 */
819
	public function isTreeRelation()
820
	{
821
		if (\in_array($this->getRelationModuleModel()->getName(), ['OutsourcedProducts', 'Products', 'Services', 'OSSOutsourcedServices'])) {
822
			foreach ($this->getRelationModuleModel()->getFieldsByType('tree') as $field) {
823
				if ($field->isActiveField()) {
824
					return true;
825
				}
826
			}
827
		}
828
		return false;
829
	}
830
831
	public function isDirectRelation()
832
	{
833
		return self::RELATION_O2M == $this->getRelationType();
834
	}
835
836
	/**
837
	 * Getting all relations.
838
	 *
839
	 * @param \Vtiger_Module_Model $moduleModel
840
	 * @param bool                 $selected
841
	 * @param bool                 $onlyActive
842
	 * @param bool                 $permissions
843
	 * @param string               $key
844
	 *
845
	 * @return \Vtiger_Relation_Model[]
846
	 */
847
	public static function getAllRelations(Vtiger_Module_Model $moduleModel, bool $selected = true, bool $onlyActive = true, bool $permissions = true, string $key = 'relation_id')
848
	{
849
		$relationModels = [];
850
		$relationModelClassName = Vtiger_Loader::getComponentClassName('Model', 'Relation', $moduleModel->get('name'));
851
		$privilegesModel = Users_Privileges_Model::getCurrentUserPrivilegesModel();
852
		foreach (\App\Relation::getByModule($moduleModel->getName(), $onlyActive) as $row) {
0 ignored issues
show
Bug introduced by
$moduleModel->getName() of type boolean is incompatible with the type string expected by parameter $moduleName of App\Relation::getByModule(). ( Ignorable by Annotation )

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

852
		foreach (\App\Relation::getByModule(/** @scrutinizer ignore-type */ $moduleModel->getName(), $onlyActive) as $row) {
Loading history...
853
			if ($selected && 1 === $row['presence']) {
854
				continue;
855
			}
856
			$row['modulename'] = $row['related_modulename'];
857
			$row['moduleid'] = $row['related_tabid'];
858
			// Skip relation where target module does not exits or is no permitted for view.
859
			if ($permissions && !$privilegesModel->hasModuleActionPermission($row['related_modulename'], 'DetailView')) {
860
				continue;
861
			}
862
			$relationModel = new $relationModelClassName();
863
			$relationModel->setData($row)->setParentModuleModel($moduleModel)->set('relatedModuleName', $row['related_modulename']);
864
			$relationModels[$row[$key]] = $relationModel;
865
		}
866
		return $relationModels;
867
	}
868
869
	/**
870
	 * Get autocomplete fields.
871
	 *
872
	 * @param \Vtiger_Record_Model $recordModel
873
	 *
874
	 * @return array
875
	 */
876
	public function getAutoCompleteField($recordModel): array
877
	{
878
		$fields = [];
879
		$fieldsReferenceList = [];
880
		$excludedModules = ['Users'];
881
		$relatedModel = $this->getRelationModuleModel();
882
		if ($relationField = $this->getRelationField()) {
883
			$fields[$relationField->getName()] = $recordModel->getId();
884
		}
885
		$parentModelFields = $this->getParentModuleModel()->getFields();
886
		foreach ($parentModelFields as $fieldName => $fieldModel) {
887
			if ($fieldModel->isReferenceField()) {
888
				$referenceList = $fieldModel->getReferenceList();
889
				foreach ($referenceList as $module) {
890
					if (!\in_array($module, $excludedModules) && 'userCreator' !== !$fieldModel->getFieldDataType()) {
891
						$fieldsReferenceList[$module] = $fieldModel;
892
					}
893
				}
894
			}
895
		}
896
		$relatedModelFields = $relatedModel->getFields();
897
		foreach ($relatedModelFields as $fieldName => $fieldModel) {
898
			if ($fieldModel->isReferenceField()) {
899
				$referenceList = $fieldModel->getReferenceList();
900
				foreach ($referenceList as $module) {
901
					if (\array_key_exists($module, $fieldsReferenceList) && $module != $recordModel->getModuleName()) {
902
						$parentFieldModel = $fieldsReferenceList[$module];
903
						$relId = $recordModel->get($parentFieldModel->getName());
904
						if (!empty($relId) && \App\Record::isExists($relId)) {
905
							$fields[$fieldName] = $relId;
906
						}
907
					}
908
				}
909
			}
910
		}
911
912
		return $fields;
913
	}
914 1
915
	public function getRestrictionsPopupField($recordModel)
916 1
	{
917 1
		$fields = [];
918 1
		$map = [];
919 1
		$relatedModel = $this->getRelationModuleModel();
920 1
		$relatedModuleName = $relatedModel->getName();
921
		$parentModuleName = $this->getParentModuleModel()->getName();
922 1
923 1
		if (\array_key_exists("$relatedModuleName::$parentModuleName", $map)) {
924 1
			$fieldMap = $map["$relatedModuleName::$parentModuleName"];
925
			$fieldModel = $recordModel->getField($fieldMap[1]);
926
			$value = $fieldModel->getEditViewDisplayValue($recordModel->get($fieldMap[1]), $recordModel);
927 1
			$fields = ['key' => $fieldMap[0], 'name' => strip_tags($value)];
928
		}
929 1
		return $fields;
930
	}
931
932
	/**
933
	 * Function to set presence relation.
934
	 *
935
	 * @param int    $relationId
936 1
	 * @param string $status
937
	 */
938
	public static function updateRelationPresence($relationId, $status)
939 1
	{
940
		\App\Db::getInstance()->createCommand()->update('vtiger_relatedlists', ['presence' => !$status ? 1 : 0], ['relation_id' => $relationId])->execute();
941 1
		\App\Relation::clearCacheById($relationId);
942 1
	}
943 1
944
	/**
945 1
	 * Function to set presence relation.
946
	 *
947
	 * @param int   $relationId
948
	 * @param array $customView
949 1
	 */
950 1
	public static function updateRelationCustomView(int $relationId, array $customView): void
951
	{
952 1
		\App\Db::getInstance()->createCommand()->update('vtiger_relatedlists', ['custom_view' => implode(',', $customView)], ['relation_id' => $relationId])->execute();
953
		\App\Relation::clearCacheById($relationId);
954
	}
955
956
	/**
957
	 * Removes relation between modules.
958
	 *
959
	 * @param int $relationId
960
	 */
961
	public static function removeRelationById($relationId)
962
	{
963
		if ($relationId) {
964
			$dbCommand = App\Db::getInstance()->createCommand();
965
			$dbCommand->delete('vtiger_relatedlists', ['relation_id' => $relationId])->execute();
966
			$dbCommand->delete('vtiger_relatedlists_fields', ['relation_id' => $relationId])->execute();
967
			App\Db::getInstance('admin')->createCommand()->delete('a_yf_relatedlists_inv_fields', ['relation_id' => $relationId])->execute();
968
		}
969
		\App\Relation::clearCacheById($relationId);
970
	}
971
972
	/**
973
	 * Function to save sequence of relation.
974
	 *
975
	 * @param array $modules
976
	 */
977
	public static function updateRelationSequence($modules)
978
	{
979
		$dbCommand = App\Db::getInstance()->createCommand();
980
		foreach ($modules as $module) {
981
			$dbCommand->update('vtiger_relatedlists', ['sequence' => (int) $module['index'] + 1], ['relation_id' => $module['relationId']])->execute();
982
			\App\Relation::clearCacheById((int) $module['relationId']);
983
		}
984
	}
985
986
	/**
987
	 * Update module related fields.
988
	 *
989
	 * @param int   $relationId
990
	 * @param array $fields
991
	 *
992
	 * @throws \yii\db\Exception
993
	 */
994
	public static function updateModuleRelatedFields(int $relationId, $fields)
995
	{
996
		$db = \App\Db::getInstance();
997
		$transaction = $db->beginTransaction();
998
		try {
999
			$db->createCommand()->delete('vtiger_relatedlists_fields', ['relation_id' => $relationId])->execute();
1000
			if ($fields) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $fields of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
1001
				$addedFields = [];
1002
				foreach ($fields as $key => $field) {
1003
					if (\in_array($field['id'], $addedFields)) {
1004
						continue;
1005
					}
1006
					$db->createCommand()->insert('vtiger_relatedlists_fields', [
1007
						'relation_id' => $relationId,
1008
						'fieldid' => $field['id'],
1009
						'sequence' => $key,
1010
					])->execute();
1011
					$addedFields[] = $field['id'];
1012
				}
1013
			}
1014
			$transaction->commit();
1015
		} catch (\Throwable $e) {
1016
			$transaction->rollBack();
1017
			throw $e;
1018
		}
1019
		\App\Relation::clearCacheById($relationId);
1020
	}
1021
1022
	public static function updateModuleRelatedInventoryFields($relationId, $fields)
1023
	{
1024
		$db = \App\Db::getInstance('admin');
1025
		$db->createCommand()->delete('a_#__relatedlists_inv_fields', ['relation_id' => $relationId])->execute();
1026
		if ($fields) {
1027
			foreach ($fields as $key => $field) {
1028
				$db->createCommand()->insert('a_#__relatedlists_inv_fields', [
1029
					'relation_id' => $relationId,
1030
					'fieldname' => $field,
1031
					'sequence' => $key,
1032
				])->execute();
1033
			}
1034
		}
1035
		\App\Cache::clear();
1036
	}
1037
1038
	public function isActive()
1039
	{
1040
		return 0 == $this->get('presence') ? true : false;
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $this->get('presence') of type mixed|null to 0; this is ambiguous as not only 0 == 0 is true, but null == 0 is true, too. Consider using a strict comparison ===.
Loading history...
1041
	}
1042
1043
	public function getFields($type = false)
1044
	{
1045
		$fields = $this->get('fields');
1046
		if (!$fields) {
1047
			$fields = [];
1048
			$relatedModel = $this->getRelationModuleModel();
1049
			$relatedModelFields = $relatedModel->getFields();
1050
1051
			foreach ($relatedModelFields as $fieldModel) {
1052
				if ($fieldModel->isViewable()) {
1053
					$fields[] = $fieldModel;
1054
				}
1055
			}
1056
			$this->set('fields', $fields);
1057
		}
1058
		if ($type) {
1059
			foreach ($fields as $key => $fieldModel) {
1060
				if ($fieldModel->getFieldDataType() != $type) {
1061
					unset($fields[$key]);
1062
				}
1063
			}
1064
		}
1065
		return $fields;
1066
	}
1067
1068
	/**
1069
	 * Gets relation data fields.
1070
	 *
1071
	 * @return array
1072
	 */
1073
	public function getRelationFields(): array
1074
	{
1075
		return method_exists($this->getTypeRelationModel(), 'getFields') ? $this->getTypeRelationModel()->getFields() : [];
1076
	}
1077
1078
	/**
1079
	 * Set conditions for relation fields.
1080
	 *
1081
	 * @param array $conditions
1082
	 *
1083
	 * @return self
1084
	 */
1085
	public function setRelationConditions(array $conditions): self
1086
	{
1087
		$group = 'and';
1088
		$relFields = $this->getRelationFields();
1089
		foreach ($conditions as $groupInfo) {
1090
			if (empty($groupInfo) || !array_filter($groupInfo)) {
1091
				$group = 'or';
1092
				continue;
1093
			}
1094
			$dataGroup = [$group];
1095
			foreach ($groupInfo as $fieldSearchInfo) {
1096
				[$fieldName, $operator, $fieldValue] = array_pad($fieldSearchInfo, 3, false);
1097
				$field = $relFields[$fieldName] ?? null;
1098
				if (!$field || (($className = '\App\Conditions\QueryFields\\' . ucfirst($field->getFieldDataType()) . 'Field') && !class_exists($className))) {
1099
					continue;
1100
				}
1101
				$queryField = new $className($this->getQueryGenerator(), $field);
1102
				$queryField->setValue($fieldValue);
1103
				$queryField->setOperator($operator);
1104
				$condition = $queryField->getCondition();
1105
				if ($condition) {
1106
					$dataGroup[] = $condition;
1107
				}
1108
			}
1109
			$this->getQueryGenerator()->addNativeCondition($dataGroup);
1110
		}
1111
		return $this;
1112
	}
1113
1114
	public static function getReferenceTableInfo($moduleName, $refModuleName)
1115
	{
1116
		$temp = [$moduleName, $refModuleName];
1117
		sort($temp);
1118
		$tableName = 'u_yf_' . strtolower($temp[0]) . '_' . strtolower($temp[1]);
1119
1120
		if ($temp[0] == $moduleName) {
1121
			$baseColumn = 'relcrmid';
1122
			$relColumn = 'crmid';
1123
		} else {
1124
			$baseColumn = 'crmid';
1125
			$relColumn = 'relcrmid';
1126
		}
1127
		return ['table' => $tableName, 'module' => $temp[0], 'base' => $baseColumn, 'rel' => $relColumn];
1128
	}
1129
1130
	public function updateFavoriteForRecord($action, $data)
1131
	{
1132
		$db = App\Db::getInstance();
1133
		$moduleName = $this->getParentModuleModel()->get('name');
1134
		$result = false;
1135
		if ('add' === $action) {
1136
			$result = $db->createCommand()->insert('u_#__favorites', [
1137
				'data' => date('Y-m-d H:i:s'),
1138
				'crmid' => $data['crmid'],
1139
				'module' => $moduleName,
1140
				'relcrmid' => $data['relcrmid'],
1141
				'relmodule' => $this->getRelationModuleName(),
1142
				'userid' => App\User::getCurrentUserId(),
1143
			])->execute();
1144
		} elseif ('delete' === $action) {
1145
			$result = $db->createCommand()->delete('u_#__favorites', [
1146
				'crmid' => $data['crmid'],
1147
				'module' => $moduleName,
1148
				'relcrmid' => $data['relcrmid'],
1149
				'relmodule' => $this->getRelationModuleName(),
1150
				'userid' => App\User::getCurrentUserId(),
1151
			])->execute();
1152
		}
1153
		return $result;
1154
	}
1155
1156
	public static function updateStateFavorites($relationId, $status)
1157
	{
1158
		\App\Db::getInstance()->createCommand()->update('vtiger_relatedlists', ['favorites' => $status], ['relation_id' => $relationId])->execute();
1159
		\App\Relation::clearCacheById($relationId);
1160
	}
1161
1162
	/**
1163
	 * Get custom view list.
1164
	 *
1165
	 * @return string[]
1166
	 */
1167
	public function getCustomViewList(): array
1168
	{
1169
		if (isset($this->customViewList)) {
1170
			return $this->customViewList;
1171
		}
1172
		$cv = [];
1173
		$selectedCv = $this->getCustomView();
1174
		if (empty($selectedCv) || \in_array('relation', $selectedCv)) {
1175
			$cv['relation'] = \App\Language::translate('LBL_RECORDS_FROM_RELATION');
1176
			unset($selectedCv[array_search('relation', $selectedCv)]);
1177
		}
1178
		if ($selectedCv) {
1179
			$moduleName = $this->getRelationModuleName();
1180
			$all = CustomView_Record_Model::getAll($moduleName);
1181
			if (\in_array('all', $selectedCv)) {
1182
				unset($selectedCv[array_search('all', $selectedCv)]);
1183
				foreach ($all as $cvId => $cvModel) {
1184
					$cv[$cvId] = \App\Language::translate($cvModel->get('viewname'), $moduleName);
1185
				}
1186
			} elseif (\in_array('private', $selectedCv)) {
1187
				unset($selectedCv[array_search('private', $selectedCv)]);
1188
				foreach ($all as $cvId => $cvModel) {
1189
					if ($cvModel->isMine()) {
1190
						$cv[$cvId] = \App\Language::translate($cvModel->get('viewname'), $moduleName);
1191
					}
1192
				}
1193
			}
1194
			foreach ($selectedCv as $cvId) {
1195
				if (isset($all[$cvId])) {
1196
					$cv[$cvId] = \App\Language::translate($all[$cvId]->get('viewname'), $moduleName);
1197
				}
1198
			}
1199
		}
1200
		return $this->customViewList = $cv;
1201
	}
1202
}
1203