Passed
Push — developer ( 3e6d7c...adc0a6 )
by Mariusz
19:16
created

getMultiReferenceFieldsRelatedWithModule()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 17
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
cc 3
eloc 13
nc 3
nop 1
dl 0
loc 17
ccs 0
cts 0
cp 0
crap 12
rs 9.8333
c 0
b 0
f 0
1
<?php
2
/* +**********************************************************************************
3
 * The contents of this file are subject to the vtiger CRM Public License Version 1.1
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 Settings_LayoutEditor_Module_Model extends Vtiger_Module_Model
13
{
14
	/** {@inheritdoc} */
15
	public $name = 'LayoutEditor';
16
	/** @var string Parent name */
17
	public $parent = 'Settings';
18
	/** {@inheritdoc} */
19
	public $isentitytype = false;
20
	/** @var string[] List of supported modules */
21
	public static $supportedModules = false;
22
	/** @var string[] List of supported relation types */
23
	const TYPES = [
24
		'getRelatedList' => 'PLL_RELATED_LIST',
25
		'getManyToMany' => 'PLL_SPLITED_RELATED_LIST',
26
		'getAttachments' => 'PLL_ATTACHMENTS',
27
		'getEmails' => 'PLL_EMAILS',
28
		'getMultiReference' => 'PLL_MULTI_REFERENCE',
29
		//'getDependentsList' => 'PLL_DEPENDENTS_LIST',
30
		// 'getActivities' => 'PLL_ACTIVITIES',
31
	];
32
	/** @var string[] Related view types. */
33
	public const RELATED_VIEW_TYPE = [
34
		'RelatedTab' => 'LBL_RELATED_TAB_TYPE',
35
		'DetailTop' => 'LBL_DETAIL_TOP_TYPE',
36
		'DetailBottom' => 'LBL_DETAIL_BOTTOM_TYPE',
37
		'SummaryTop' => 'LBL_SUMMARY_TOP_TYPE',
38
		'SummaryBottom' => 'LBL_SUMMARY_BOTTOM_TYPE',
39
	];
40
41
	/**
42
	 * Gets parent name.
43
	 *
44
	 * @return string
45
	 */
46
	public function getParentName()
47
	{
48
		return $this->parent;
49
	}
50
51
	/**
52
	 * Function that returns all the fields for the module.
53
	 *
54
	 * @param mixed $blockInstance
55
	 *
56
	 * @return Vtiger_Field_Model[] - list of field models
57
	 */
58
	public function getFields($blockInstance = false)
59
	{
60
		if (empty($this->fieldsModule)) {
61
			$fieldList = [];
62
			$blocks = $this->getBlocks();
63
			$blockId = [];
64
			foreach ($blocks as $block) {
65
				$blockId[] = $block->get('id');
66
			}
67
			if (\count($blockId) > 0) {
68
				$fieldList = Settings_LayoutEditor_Field_Model::getInstanceFromBlockIdList($blockId);
69
			}
70
			$this->fieldsModule = $fieldList;
0 ignored issues
show
Bug Best Practice introduced by
The property fieldsModule does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
71
		}
72
		return $this->fieldsModule;
73
	}
74
75
	/**
76
	 * Function returns all the blocks for the module.
77
	 *
78
	 * @return <Array of Vtiger_Block_Model> - list of block models
0 ignored issues
show
Documentation Bug introduced by
The doc comment <Array at position 0 could not be parsed: Unknown type name '<' at position 0 in <Array.
Loading history...
79
	 */
80
	public function getBlocks()
81
	{
82
		if (empty($this->blocks)) {
83
			$blocksList = [];
84
			$moduleBlocks = Settings_LayoutEditor_Block_Model::getAllForModule($this);
85 21
			foreach ($moduleBlocks as $block) {
86
				if (!$block->get('label')) {
87
					continue;
88 21
				}
89
				if ('HelpDesk' === $this->getName() && 'LBL_COMMENTS' === $block->get('label')) {
90
					continue;
91
				}
92
93
				if ('LBL_ITEM_DETAILS' != $block->get('label')) {
94
					$blocksList[$block->get('label')] = $block;
95
				}
96
			}
97
			$this->blocks = $blocksList;
98
		}
99
		return $this->blocks;
100
	}
101
102
	/**
103
	 * List of supported field types.
104
	 *
105
	 * @return string[]
106
	 */
107
	public function getAddSupportedFieldTypes()
108
	{
109
		return [
110
			'Text', 'Decimal', 'Integer',  'Currency',  'Percent', 'AdvPercentage', 'Date', 'Time', 'DateTime', 'RangeTime', 'Phone', 'Email', 'MultiEmail', 'MultiDomain', 'Picklist', 'MultiSelectCombo', 'MultipicklistTags', 'Country', 'URL', 'Checkbox', 'TextArea', 'Related1M', 'MultiReference', 'Editor', 'Tree', 'CategoryMultipicklist', 'Image', 'MultiImage',  'MultiAttachment', 'MultiReferenceValue', 'ServerAccess', 'Skype', 'Twitter', 'Token', 'Smtp', 'MapCoordinates', 'Group',
111
		];
112
	}
113
114
	/**
115
	 * Function which will give information about the field types that are supported for add.
116
	 *
117
	 * @return array
118
	 */
119
	public function getAddFieldTypeInfo()
120
	{
121
		$fieldTypesInfo = [];
122
		$addFieldSupportedTypes = $this->getAddSupportedFieldTypes();
123
		$lengthSupportedFieldTypes = ['Text', 'Decimal', 'Integer', 'Currency', 'Editor', 'AdvPercentage'];
124
		foreach ($addFieldSupportedTypes as $fieldType) {
125
			$details = [];
126
			if (\in_array($fieldType, $lengthSupportedFieldTypes)) {
127
				$details['lengthsupported'] = true;
128
			}
129
			if ('Editor' === $fieldType) {
130
				$details['noLimitForLength'] = true;
131
			}
132
			if ('Decimal' === $fieldType || 'Currency' === $fieldType || 'AdvPercentage' === $fieldType) {
133
				$details['decimalSupported'] = true;
134
				$details['maxFloatingDigits'] = 5;
135
				if ('Currency' === $fieldType) {
136
					$details['decimalReadonly'] = true;
137
				}
138
				//including mantisaa and integer part
139
				$details['maxLength'] = 64;
140
			}
141
			if ('Picklist' === $fieldType || 'MultiSelectCombo' === $fieldType || 'MultipicklistTags' === $fieldType) {
142
				$details['preDefinedValueExists'] = true;
143
				//text area value type , can give multiple values
144
				$details['preDefinedValueType'] = 'text';
145
				if ('Picklist' === $fieldType) {
146
					$details['picklistoption'] = true;
147
				}
148
			}
149 21
			if ('Related1M' === $fieldType) {
150
				$details['ModuleListMultiple'] = true;
151 21
			}
152 21
			$fieldTypesInfo[$fieldType] = $details;
153 21
		}
154 21
		return $fieldTypesInfo;
155 21
	}
156
157
	/**
158 21
	 * Verification of data.
159
	 *
160
	 * @param array $data
161 21
	 * @param bool  $throw
162
	 */
163
	public function validate(array $data, bool $throw = true)
164 21
	{
165
		$message = null;
166
		$code = null;
167 21
		$result = false;
168
		foreach ($data as $key => $value) {
169
			switch ($key) {
170 21
				case 'fieldLabel':
171 21
					if ($result = $this->checkFieldLabelExists($value)) {
172
						$message = \App\Language::translate('LBL_DUPLICATE_FIELD_EXISTS', 'Settings::LayoutEditor');
173
						$code = 513;
174 21
					}
175 3
					break;
176 3
				case 'fieldName':
177
					$value = strtolower($value);
178
					if ($result = $this->checkFieldNameCharacters($value)) {
179 3
						$message = \App\Language::translate('LBL_INVALIDCHARACTER', 'Settings::LayoutEditor');
180 3
						$code = 512;
181
					} elseif ($result = $this->checkFieldNameExists($value)) {
182
						$message = \App\Language::translate('LBL_DUPLICATE_FIELD_EXISTS', 'Settings::LayoutEditor');
183 3
						$code = 512;
184
					} elseif ($result = $this->checkFieldNameIsAnException($value)) {
185
						$message = \App\Language::translate('LBL_FIELD_NAME_IS_RESERVED', 'Settings::LayoutEditor');
186
						$code = 512;
187
					} elseif (\strlen($value) > 30) {
188 21
						$message = \App\Language::translate('LBL_EXCEEDED_MAXIMUM_NUMBER_CHARACTERS_FOR_FIELD_NAME', 'Settings::LayoutEditor');
189 21
						$code = 512;
190 21
					} elseif (isset($data['fieldType']) && \in_array($data['fieldType'], ['Picklist', 'MultiSelectCombo']) && ($result = $this->checkIfPicklistFieldNameReserved($value))) {
191 21
						$message = \App\Language::translate('LBL_FIELD_NAME_IS_RESERVED', 'Settings::LayoutEditor');
192
						$code = 512;
193
					}
194
					break;
195
				case 'fieldType':
196
					if ($result = !\in_array($value, $this->getAddSupportedFieldTypes())) {
197
						$message = \App\Language::translate('LBL_WRONG_FIELD_TYPE', 'Settings::LayoutEditor');
198
						$code = 513;
199 21
					}
200 2
					break;
201 19
				case 'pickListValues':
202 1
					foreach ($value as $val) {
203 1
						if (($result = preg_match('/[\<\>\"\#\,]/', $val)) || ($result = preg_match('/[\<\>\"\#\,]/', \App\Purifier::decodeHtml($val)))) {
204 1
							$message = \App\Language::translateArgs('ERR_SPECIAL_CHARACTERS_NOT_ALLOWED', 'Other.Exceptions', '<>"#,');
205 1
							$code = 512;
206 1
						} elseif ($result = \strlen($val) > 200) {
207 1
							$message = \App\Language::translate('ERR_EXCEEDED_NUMBER_CHARACTERS', 'Other.Exceptions');
208 18
							$code = 512;
209
						}
210
					}
211 21
					if (\count($value) !== \count(array_unique(array_map('strtolower', $value)))) {
212 21
						$message = \App\Language::translate('LBL_DUPLICATES_VALUES_FOUND', 'Other.Exceptions');
213 21
						$code = 512;
214 21
					}
215 21
					break;
216 21
				default:
217 21
					break;
218 21
			}
219 21
			if ($result) {
220 21
				if ($throw) {
221 21
					throw new \App\Exceptions\AppException($message, $code);
222 21
				}
223 21
				return [$key => $message];
224 21
			}
225 21
		}
226 21
		return $result;
227 1
	}
228
229 21
	/**
230 21
	 * Add field.
231
	 *
232 21
	 * @param string $fieldType
233 21
	 * @param int    $blockId
234 21
	 * @param array  $params
235 3
	 *
236
	 * @throws Exception
237 21
	 *
238 1
	 * @return \Settings_LayoutEditor_Field_Model
239
	 */
240
	public function addField($fieldType, $blockId, $params)
241 1
	{
242
		$label = $params['fieldLabel'];
243 1
		$name = strtolower($params['fieldName']);
244 1
		$pickListValues = [];
245 1
		if (\array_key_exists('pickListValues', $params)) {
246 1
			$pickListValues = $params['pickListValues'] = \is_string($params['pickListValues']) ? [$params['pickListValues']] : $params['pickListValues'];
247
		}
248
		$fieldParams = '';
249 21
		$this->validate($params);
250 21
		$moduleName = $this->getName();
251
		$tableName = $this->getTableName($params['fieldTypeList']);
252
		switch ($fieldType) {
253
			case 'Tree':
254
			case 'CategoryMultipicklist':
255
				$fieldParams = (int) $params['tree'];
256
				break;
257
			case 'MultiReferenceValue':
258
				$fieldParams = [
259
					'module' => $params['MRVModule'],
260
					'field' => $params['MRVField'],
261 21
					'filterField' => $params['MRVFilterField'] ?? null,
262
					'filterValue' => $params['MRVFilterValue'] ?? null,
263 21
				];
264 21
				\App\Db::getInstance()->createCommand()->insert('s_#__multireference', ['source_module' => $moduleName, 'dest_module' => $params['MRVModule']])->execute();
265 21
				break;
266 21
			case 'ServerAccess':
267 1
				$fieldParams = (int) $params['server'];
268 1
				break;
269 1
			case 'Token':
270 1
				(new \App\BatchMethod(['method' => '\App\Fields\Token::setTokens', 'params' => [$name, $moduleName]]))->save();
271 1
				break;
272 20
			case 'MultiReference':
273
				$fieldParams = [
274
					'module' => $params['referenceModule']
275 20
				];
276 1
				break;
277 1
			case 'MapCoordinates':
278 1
				$fieldParams = [
279 1
					'showType' => $params['isCoordinateType'] ?? 0,
280 1
					'type' => $params['type'] ?? null,
281
					'showMap' => $params['isCoordinateMap'] ?? 0,
282 1
					'showLocation' => $params['isCoordinateMeLokaction'] ?? 0,
283 1
				];
284 19
				break;
285 1
			case 'Group':
286 1
				$fieldParams = [
287 1
					'showAllGroups' => $params['showAllGroups'] ?? 0
288 1
				];
289 18
				break;
290 1
			default:
291 1
				break;
292 1
		}
293 1
		$details = $this->getTypeDetailsForAddField($fieldType, $params);
294
		$fieldModel = new Settings_LayoutEditor_Field_Model();
295
		$fieldModel->set('name', $name)
296 1
			->set('table', $tableName)
297
			->set('generatedtype', $params['generatedtype'] ?? 2)
298 1
			->set('helpinfo', $params['helpinfo'] ?? '')
299 1
			->set('uitype', $details['uitype'])
300 1
			->set('label', $label)
301 1
			->set('typeofdata', $details['typeofdata'])
302 17
			->set('quickcreate', $params['quickcreate'] ?? 1)
303 1
			->set('summaryfield', $params['summaryfield'] ?? 0)
304 1
			->set('header_field', $params['header_field'] ?? null)
305 1
			->set('fieldparams', $params['fieldparams'] ?? ($fieldParams ? \App\Json::encode($fieldParams) : ''))
306 1
			->set('columntype', $details['dbType']);
307 16
		if ('Editor' === $fieldType) {
308 1
			$fieldModel->set('maximumlength', $params['fieldLength'] ?? null);
309 1
		}
310 1
		if (isset($details['displayType']) || isset($params['displayType'])) {
311 1
			$fieldModel->set('displaytype', $params['displayType'] ?? $details['displayType']);
312 15
		}
313 1
		$blockModel = Vtiger_Block_Model::getInstance($blockId, $moduleName);
0 ignored issues
show
Bug introduced by
$moduleName of type string is incompatible with the type boolean|vtlib\ModuleBasic expected by parameter $moduleInstance of Vtiger_Block_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

313
		$blockModel = Vtiger_Block_Model::getInstance($blockId, /** @scrutinizer ignore-type */ $moduleName);
Loading history...
314 1
		$blockModel->addField($fieldModel);
315 1
		if ('Phone' === $fieldType) {
316 1
			$fieldInstance = new vtlib\Field();
317 14
			$fieldInstance->name = $name . '_extra';
318 1
			$fieldInstance->table = $tableName;
319 1
			$fieldInstance->label = 'FL_PHONE_CUSTOM_INFORMATION';
320 1
			$fieldInstance->column = $name . '_extra';
321 1
			$fieldInstance->uitype = 1;
322 13
			$fieldInstance->displaytype = 3;
323 2
			$fieldInstance->maxlengthtext = 100;
324 2
			$fieldInstance->typeofdata = 'V~O';
325 1
			$fieldInstance->save($blockModel);
326
		}
327 2
		if ('Picklist' === $fieldType || 'MultiSelectCombo' === $fieldType || 'MultipicklistTags' === $fieldType) {
328 2
			$fieldModel->setPicklistValues($pickListValues);
329 2
		}
330 11
		if ('Related1M' === $fieldType) {
331 1
			if (!\is_array($params['referenceModule'])) {
332 1
				$moduleList[] = $params['referenceModule'];
0 ignored issues
show
Comprehensibility Best Practice introduced by
$moduleList was never initialized. Although not strictly required by PHP, it is generally a good practice to add $moduleList = array(); before regardless.
Loading history...
333 1
			} else {
334 1
				$moduleList = $params['referenceModule'];
335 10
			}
336 1
			$fieldModel->setRelatedModules($moduleList);
337 1
			foreach ($moduleList as $module) {
338 1
				$targetModule = vtlib\Module::getInstance($module);
339 1
				$targetModule->setRelatedList($this, $moduleName, ['Add'], 'getDependentsList', $name);
340 9
			}
341 1
		}
342 1
		App\Cache::clear();
343 1
		return $fieldModel;
344 1
	}
345 8
346 1
	/**
347 1
	 * Function defines details of the created field.
348 1
	 *
349 1
	 * @param string $fieldType
350 7
	 * @param array  $params
351 1
	 *
352 1
	 * @return (sting|int)[]
353 1
	 */
354 1
	public function getTypeDetailsForAddField($fieldType, $params)
355 6
	{
356 1
		$displayType = 1;
357 1
		$importerType = new \App\Db\Importers\Base();
358 1
		switch ($fieldType) {
359
			case 'Text':
360
				$fieldLength = $params['fieldLength'];
361 1
				$uichekdata = 'V~O~LE~' . $fieldLength;
362
				$uitype = 1;
363 1
				$type = $importerType->stringType($fieldLength)->defaultValue('');
364 1
				break;
365 5
			case 'AdvPercentage':
366 1
				$uitype = 365;
367 1
				// no break
368 1
			case 'Decimal':
369 1
				$fieldLength = $params['fieldLength'];
370 4
				$decimal = $params['decimal'];
371 1
				$uitype = $uitype ?? 7;
372 1
				$dbfldlength = $fieldLength + $decimal + 1;
373 1
				$type = $importerType->decimal($dbfldlength, $decimal);
374 1
				// Fix for http://trac.vtiger.com/cgi-bin/trac.cgi/ticket/6363
375 1
				$uichekdata = 'NN~O';
376 3
				break;
377 1
			case 'Percent':
378 1
				$uitype = 9;
379 1
				$type = $importerType->decimal(5, 2);
380 1
				$uichekdata = 'N~O~2~2';
381 2
				break;
382 1
			case 'Currency':
383 1
				$fieldLength = $params['fieldLength'];
384 1
				$decimal = $params['decimal'];
385 1
				$uitype = 71;
386 1
				if (1 == $fieldLength) {
387 1
					$dbfldlength = $fieldLength + $decimal + 2;
388
				} else {
389
					$dbfldlength = $fieldLength + $decimal + 1;
390
				}
391
				$decimal = $decimal + 3;
392 1
				$type = $importerType->decimal($dbfldlength, $decimal);
393
				$uichekdata = 'N~O';
394
				break;
395
			case 'Date':
396
				$uichekdata = 'D~O';
397 1
				$uitype = 5;
398 1
				$type = $importerType->date();
399 1
				break;
400 1
			case 'Email':
401 1
				$uitype = 13;
402
				$type = $importerType->stringType(100)->defaultValue('');
403
				$uichekdata = 'E~O';
404
				break;
405
			case 'Time':
406
				$uitype = 14;
407
				$type = $importerType->time();
408
				$uichekdata = 'T~O';
409
				break;
410
			case 'Phone':
411
				$uitype = 11;
412
				$type = $importerType->stringType(30)->defaultValue('');
413
				$uichekdata = 'V~O';
414
				break;
415
			case 'Picklist':
416
				$uitype = 16;
417
				if (!empty($params['isRoleBasedPickList'])) {
418
					$uitype = 15;
419
				}
420
				$type = $importerType->stringType()->defaultValue('');
421
				$uichekdata = 'V~O';
422
				break;
423
			case 'URL':
424
				$uitype = 17;
425
				$type = $importerType->stringType()->defaultValue('');
426
				$uichekdata = 'V~O';
427
				break;
428
			case 'MultipicklistTags':
429
				$uitype = 18;
430
				$type = $importerType->text();
431
				$uichekdata = 'V~O';
432
				break;
433
			case 'Checkbox':
434
				$uitype = 56;
435
				$type = $importerType->boolean()->defaultValue(false);
436
				$uichekdata = 'C~O';
437
				break;
438
			case 'TextArea':
439
				$uitype = 21;
440
				$type = $importerType->text();
441
				$uichekdata = 'V~O';
442
				break;
443
			case 'MultiSelectCombo':
444
				$uitype = 33;
445
				$type = $importerType->text();
446
				$uichekdata = 'V~O';
447 21
				break;
448 21
			case 'Skype':
449 21
				$uitype = 85;
450 21
				$type = $importerType->stringType()->defaultValue('');
451
				$uichekdata = 'V~O';
452
				break;
453
			case 'Integer':
454
				$fieldLength = $params['fieldLength'];
455
				$uitype = 7;
456
				$type = $importerType->integer($fieldLength)->defaultValue(0);
457
				$uichekdata = 'I~O';
458
				break;
459
			case 'Related1M':
460
				$uitype = 10;
461 21
				$type = $importerType->integer(10)->defaultValue(0)->unsigned();
462
				$uichekdata = 'V~O';
463 21
				break;
464
			case 'Editor':
465
				$fieldLength = $params['fieldLength'];
466 21
				$uitype = 300;
467
				$type = $importerType->text($fieldLength);
468
				$uichekdata = 'V~O';
469 21
				break;
470
			case 'Tree':
471
				$uitype = 302;
472
				$type = $importerType->stringType(30)->defaultValue('');
473
				$uichekdata = 'V~O';
474
				break;
475
			case 'MultiReferenceValue':
476
				$uitype = 305;
477
				$type = $importerType->text();
478
				$uichekdata = 'V~O';
479 21
				$displayType = 5;
480
				break;
481 21
			case 'MultiImage':
482
				$uitype = 311;
483
				$type = $importerType->text();
484
				$uichekdata = 'V~O';
485
				break;
486
			case 'Image':
487
				$uitype = 69;
488
				$type = $importerType->text();
489
				$uichekdata = 'V~O';
490
				break;
491 21
			case 'CategoryMultipicklist':
492
				$uitype = 309;
493 21
				$type = $importerType->text();
494 21
				$uichekdata = 'V~O';
495
				break;
496
			case 'DateTime':
497
				$uichekdata = 'DT~O';
498
				$uitype = 79;
499
				$type = $importerType->dateTime();
500
				break;
501
			case 'Country':
502
				$uitype = 35;
503
				$uichekdata = 'V~O';
504 21
				$type = $importerType->stringType(255);
505
				break;
506 21
			case 'Twitter':
507
				$fieldLength = Vtiger_Twitter_UIType::MAX_LENGTH;
508
				$uichekdata = 'V~O~LE~' . $fieldLength;
509
				$uitype = 313;
510
				$type = $importerType->stringType($fieldLength)->defaultValue('');
511
				break;
512
			case 'MultiEmail':
513
				$uitype = 314;
514
				$type = $importerType->text();
515
				$uichekdata = 'V~O';
516
				break;
517
			case 'Smtp':
518
				$uitype = 316;
519
				$uichekdata = 'V~O';
520
				$type = $importerType->integer()->defaultValue(null)->unsigned();
521
				break;
522
			case 'ServerAccess':
523
				$uitype = 318;
524
				$uichekdata = 'C~O';
525
				$type = $importerType->boolean()->defaultValue(false);
526
				break;
527
			case 'MultiDomain':
528
				$uitype = 319;
529 22
				$uichekdata = 'V~O';
530
				$type = $importerType->text();
531 22
				break;
532 22
			case 'RangeTime':
533 22
				$uitype = 308;
534 22
				$uichekdata = 'I~O';
535 22
				$type = $importerType->integer()->null();
536
				break;
537 22
			case 'Token':
538
				$uitype = 324;
539
				$uichekdata = 'V~O';
540
				$displayType = 3;
541
				$type = $importerType->stringType(Vtiger_Token_UIType::MAX_LENGTH)->defaultValue('');
542
				break;
543
			case 'MultiAttachment':
544
				$uitype = 330;
545
				$type = $importerType->text();
546
				$uichekdata = 'V~O';
547
				break;
548
			case 'MultiReference':
549
				$uitype = 321;
550
				$type = $importerType->text();
551
				$uichekdata = 'V~O';
552
				break;
553
			case 'MapCoordinates':
554
				$uitype = 331;
555
				$type = $importerType->stringType(100);
556
				$uichekdata = 'V~O';
557
				break;
558
			case 'Group':
559
				$uitype = 333;
560
				$type = $importerType->integer(10);
561
				$uichekdata = 'I~O';
562
				break;
563
			default:
564
				break;
565
		}
566
		return [
567
			'uitype' => $uitype,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $uitype does not seem to be defined for all execution paths leading up to this point.
Loading history...
568
			'typeofdata' => $uichekdata,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $uichekdata does not seem to be defined for all execution paths leading up to this point.
Loading history...
569
			'dbType' => $type,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $type does not seem to be defined for all execution paths leading up to this point.
Loading history...
570
			'displayType' => $displayType,
571
		];
572
	}
573
574
	public function getTableName($type)
575
	{
576
		if (\is_int($type)) {
577
			$focus = CRMEntity::getInstance($this->getName());
578
			if (0 == $type) {
579
				$tableName = $focus->table_name;
580
			} elseif (1 == $type) {
581
				if (isset($focus->customFieldTable)) {
582
					$tableName = $focus->customFieldTable[0];
583
				} else {
584
					$tableName = $focus->table_name . 'cf';
585
				}
586
			}
587
		} else {
588
			$tableName = $type;
589
		}
590
		return $tableName;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $tableName does not seem to be defined for all execution paths leading up to this point.
Loading history...
591
	}
592
593
	/**
594
	 * Check field name characters.
595
	 *
596
	 * @param string $name
597 1
	 *
598
	 * @return bool
599 1
	 */
600 1
	public function checkFieldNameCharacters($name): bool
601
	{
602
		return preg_match('#[^a-z0-9_]#is', $name) || !preg_match('/[a-z]/i', $name) || false !== strpos($name, ' ');
603 1
	}
604
605
	/**
606
	 * Check if label exists.
607
	 *
608
	 * @param string $fieldLabel
609
	 *
610
	 * @return bool
611
	 */
612
	public function checkFieldLabelExists(string $fieldLabel): bool
613
	{
614
		return (new \App\Db\Query())->from('vtiger_field')->where(['fieldlabel' => $fieldLabel, 'tabid' => $this->getId()])->exists();
615 1
	}
616
617
	/**
618
	 * Check if field exists.
619
	 *
620
	 * @param string $fieldName
621
	 *
622
	 * @return bool
623
	 */
624
	public function checkFieldNameExists(string $fieldName): bool
625
	{
626
		return (new \App\Db\Query())->from('vtiger_field')->where(['tabid' => $this->getId()])
627
			->andWhere(['or', ['fieldname' => $fieldName], ['columnname' => $fieldName]])->exists();
628
	}
629
630
	/**
631
	 * Check if the field name is reserved.
632
	 *
633
	 * @param string $fieldName
634
	 *
635
	 * @return bool
636
	 */
637
	public function checkFieldNameIsAnException(string $fieldName)
638
	{
639
		return \in_array($fieldName, [
640
			'id', 'seq', 'header_type', 'header_class',
641
			'module', 'parent', 'action', 'mode', 'view', 'selected_ids',
642
			'excluded_ids', 'search_params', 'search_key', 'page', 'operator',
643
			'source_module', 'viewname', 'sortorder', 'orderby', 'inventory', 'private', 'src_record', 'relationid', 'relation_id', 'picklist', 'overwritten_shownerid', 'relationoperation', 'sourcemodule', 'sourcerecord'
644
		]);
645
	}
646
647
	public static function getSupportedModules()
648
	{
649
		if (empty(self::$supportedModules)) {
650
			self::$supportedModules = self::getEntityModulesList();
651
		}
652
		return self::$supportedModules;
653
	}
654
655
	/**
656
	 * Get instance by name.
657
	 *
658
	 * @param string $moduleName
659
	 *
660
	 * @return self
661
	 */
662
	public static function getInstanceByName($moduleName)
663
	{
664
		$moduleInstance = Vtiger_Module_Model::getInstance($moduleName);
665
		$objectProperties = get_object_vars($moduleInstance);
666
		$selfInstance = new self();
667
		foreach ($objectProperties as $properName => $propertyValue) {
668
			$selfInstance->{$properName} = $propertyValue;
669
		}
670
		return $selfInstance;
671
	}
672
673
	/**
674
	 * Function to get Entity module names list.
675
	 *
676
	 * @return string[] List of Entity modules
677
	 */
678
	public static function getEntityModulesList()
679
	{
680
		$restrictedModules = ['Integration', 'Dashboard'];
681
		return (new \App\Db\Query())->select(['name', 'module' => 'name'])->from('vtiger_tab')->where(['presence' => [0, 2], 'isentitytype' => 1])->andWhere(['not in', 'name', $restrictedModules])->createCommand()->queryAllByGroup();
682
	}
683
684
	/**
685
	 * Function to check field is editable or not.
686
	 *
687
	 * @return bool
688
	 */
689
	public function isSortableAllowed()
690
	{
691
		return true;
692
	}
693
694
	/**
695
	 * Function to check blocks are sortable for the module.
696
	 *
697
	 * @return bool
698
	 */
699
	public function isBlockSortableAllowed()
700
	{
701
		if ('ModComments' === $this->getName()) {
702
			return false;
703
		}
704
		return true;
705
	}
706
707
	/**
708
	 * Function to check fields are sortable for the block.
709
	 *
710
	 * @param mixed $blockName
711
	 *
712
	 * @return bool
713
	 */
714
	public function isFieldsSortableAllowed($blockName)
715
	{
716
		$moduleName = $this->getName();
717
		$blocksEliminatedArray = ['HelpDesk' => ['LBL_TICKET_RESOLUTION', 'LBL_COMMENTS'],
718
			'Faq' => ['LBL_COMMENT_INFORMATION'],
719
			'Calendar' => ['LBL_TASK_INFORMATION', 'LBL_DESCRIPTION_INFORMATION', 'LBL_REMINDER_INFORMATION', 'LBL_RECURRENCE_INFORMATION'],
720
		];
721
		if (\in_array($moduleName, ['HelpDesk', 'Faq'])) {
722
			if (!empty($blocksEliminatedArray[$moduleName])) {
723
				if (\in_array($blockName, $blocksEliminatedArray[$moduleName])) {
724
					return false;
725
				}
726
			} else {
727
				return false;
728
			}
729
		}
730
		return true;
731
	}
732
733
	public function getRelations()
734
	{
735
		if (null === $this->relations) {
736
			$this->relations = Vtiger_Relation_Model::getAllRelations($this, false, true, true);
737
		}
738
		return $this->relations;
739
	}
740
741
	/**
742
	 * Function returns available templates for tree type field.
743
	 *
744
	 * @param string $sourceModule
745
	 *
746
	 * @return array
747
	 */
748
	public function getTreeTemplates($sourceModule)
749
	{
750
		$sourceModule = \App\Module::getModuleId($sourceModule);
751
		$query = (new \App\Db\Query())->select(['templateid', 'name'])->from('vtiger_trees_templates')->where(['tabid' => $sourceModule])->orWhere(['like', 'share', ",$sourceModule,"]);
752
		$treeList = [];
753
		$dataReader = $query->createCommand()->query();
754
		while ($row = $dataReader->read()) {
755
			$treeList[$row['templateid']] = $row['name'];
756
		}
757
		$dataReader->close();
758
759
		return $treeList;
760
	}
761
762
	/**
763
	 * Get relations types.
764
	 *
765
	 * @param string|null $moduleName
766
	 *
767
	 * @return array
768
	 */
769
	public static function getRelationsTypes(?string $moduleName = null): array
770
	{
771
		$types = self::TYPES;
772
		if ('OSSMailView' === $moduleName) {
773
			$types['getRecordToMails'] = 'PLL_RECORD_TO_MAILS';
774
		}
775
		return $types;
776
	}
777
778
	public static function getRelationsActions()
779
	{
780
		return [
781
			'ADD' => 'PLL_ADD',
782
			'SELECT' => 'PLL_SELECT',
783
		];
784
	}
785
786
	/**
787
	 * Update related view type.
788
	 *
789
	 * @param int      $relationId
790
	 * @param string[] $type
791
	 */
792
	public static function updateRelatedViewType($relationId, $type)
793
	{
794
		\App\Db::getInstance()->createCommand()->update('vtiger_relatedlists', ['view_type' => implode(',', $type)], ['relation_id' => $relationId])->execute();
795
		\App\Relation::clearCacheById($relationId);
796
	}
797
798
	/**
799
	 * Check if picklist field can have that name.
800
	 *
801
	 * @param string $fieldName
802
	 *
803
	 * @return bool
804
	 */
805
	public function checkIfPicklistFieldNameReserved(string $fieldName): bool
806
	{
807
		return (
808
			\App\Fields\Picklist::isPicklistExist($fieldName)
809
			&& !(new \App\Db\Query())->from('vtiger_field')->where(['or', ['fieldname' => $fieldName], ['columnname' => $fieldName]])->exists()
810
		) || \in_array($fieldName, (new \App\Db\Query())->select(['fieldname'])->from('vtiger_field')->where(['tabid' => \App\Module::getModuleId('Users'), 'uitype' => [16, 15, 33, 115]])->column());
811
	}
812
813
	/**
814
	 * Get missing system fields.
815
	 *
816
	 * @return \Vtiger_Field_Model[]
817
	 */
818
	public function getMissingSystemFields(): array
819
	{
820
		$fields = $this->getFields();
821
		$systemFields = \App\Field::SYSTEM_FIELDS;
822
		$missingFields = [];
823
		foreach (Settings_WebserviceApps_Module_Model::getServers() as $id => $field) {
824
			$name = 'share_externally_' . $id;
825
			$systemFields[$name] = array_merge($systemFields['share_externally'], [
826
				'name' => $name,
827
				'column' => $name,
828
				'label' => $field['name'] . ' (' . \App\Language::translate($field['type'], 'Settings:WebserviceApps') . ')',
829
				'fieldparams' => $id,
830
			]);
831
		}
832
		unset($systemFields['share_externally']);
833
		foreach ($systemFields as $name => $field) {
834
			$validationConditions = $field['validationConditions'];
835
			if ($validationConditions === ['name']) {
836
				$exist = isset($fields[$name]);
837
			} else {
838
				$exist = true;
839
				foreach ($validationConditions as $validationCondition) {
840
					$status = true;
841
					foreach ($fields as $fieldModel) {
842
						if ($fieldModel->get($validationCondition) == $field[$validationCondition]) {
843
							$status = false;
0 ignored issues
show
Unused Code introduced by
The assignment to $status is dead and can be removed.
Loading history...
844
							continue 2;
845
						}
846
					}
847
					$exist = !$status;
0 ignored issues
show
introduced by
The condition $status is always true.
Loading history...
848
				}
849
			}
850
			if (!$exist) {
851
				unset($field['validationConditions']);
852
				$missingFields[$name] = \Vtiger_Field_Model::init($this->name, $field, $field['name']);
853
			}
854
		}
855
		return $missingFields;
856
	}
857
858
	/**
859
	 * Create system field.
860
	 *
861
	 * @param string $sysName
862
	 * @param int    $blockId
863
	 * @param array  $params
864
	 *
865
	 * @return void
866
	 */
867
	public function addSystemField(string $sysName, int $blockId, array $params = []): void
868
	{
869
		$missingSystemFields = $this->getMissingSystemFields();
870
		if (empty($missingSystemFields[$sysName])) {
871
			throw new \App\Exceptions\AppException(\App\Language::translate('LBL_DUPLICATE_FIELD_EXISTS', 'Settings::LayoutEditor'), 512);
872
		}
873
		$fieldModel = $missingSystemFields[$sysName];
874
		if ($params) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $params 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...
875
			foreach ($params as $key => $value) {
876
				$fieldModel->set($key, $value);
877
			}
878
		}
879
		if ($this->checkFieldLabelExists($fieldModel->get('name'))) {
880
			throw new \App\Exceptions\AppException(\App\Language::translate('LBL_DUPLICATE_FIELD_EXISTS', 'Settings::LayoutEditor'), 513);
881
		}
882
		if ($this->checkFieldNameCharacters($fieldModel->get('name'))) {
883
			throw new \App\Exceptions\AppException(\App\Language::translate('LBL_INVALIDCHARACTER', 'Settings::LayoutEditor'), 512);
884
		}
885
		if ($this->checkFieldNameExists($fieldModel->get('name'))) {
886
			throw new \App\Exceptions\AppException(\App\Language::translate('LBL_DUPLICATE_FIELD_EXISTS', 'Settings::LayoutEditor'), 512);
887
		}
888
		$blockModel = Vtiger_Block_Model::getInstance($blockId, $this->name);
0 ignored issues
show
Bug introduced by
$this->name of type string is incompatible with the type boolean|vtlib\ModuleBasic expected by parameter $moduleInstance of Vtiger_Block_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

888
		$blockModel = Vtiger_Block_Model::getInstance($blockId, /** @scrutinizer ignore-type */ $this->name);
Loading history...
889
		$blockModel->addField($fieldModel);
890
	}
891
892
	/**
893
	 * Get fields for webservice apps.
894
	 *
895
	 * @param int $webserviceApp
896
	 *
897
	 * @return array
898
	 */
899
	public function getFieldsForWebserviceApps(int $webserviceApp): array
900
	{
901
		return (new \App\Db\Query())->from('w_#__fields_server')->where(['serverid' => $webserviceApp])->indexBy('fieldid')->all(\App\Db::getInstance('webservice')) ?: [];
902
	}
903
904
	public function getEditFields()
905
	{
906
		$editFields = ['label', 'presence', 'quickcreate', 'summaryfield', 'generatedtype', 'masseditable', 'header_field',
907
			'displaytype', 'maxlengthtext', 'maxwidthcolumn', 'tabindex', 'mandatory', 'icon'];
908
		foreach ($editFields as $fieldName) {
909
			$propertyModel = $this->getFieldInstanceByName($fieldName);
910
			if (null !== $this->get($fieldName)) {
911
				$propertyModel->set('fieldvalue', $this->get($fieldName));
912
			} elseif (($defaultValue = $propertyModel->get('defaultvalue')) !== null) {
913
				$propertyModel->set('fieldvalue', $defaultValue);
914
			}
915
			$fields[$fieldName] = $propertyModel;
916
		}
917
918
		return $fields;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $fields seems to be defined by a foreach iteration on line 908. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
919
	}
920
921
	/**
922
	 * Get fields instance by name.
923
	 *
924
	 * @param string $name
925
	 *
926
	 * @return Vtiger_Field_Model
927
	 */
928
	public function getFieldInstanceByName($name)
929
	{
930
		$params = [];
931
		$qualifiedModuleName = 'Settings:LayoutEditor';
932
		// $tableName = $this->getTableName();
933
		switch ($name) {
934
			case 'icon':
935
				$params = [
936
					'name' => $name,
937
					'column' => $name,
938
					'label' => 'LBL_ICON',
939
					'uitype' => 62,
940
					'typeofdata' => 'V~O',
941
					'maximumlength' => '255',
942
					'purifyType' => \App\Purifier::TEXT,
943
					'table' => 'vtiger_field',
944
					'fieldDataType' => 'icon'
945
				];
946
				break;
947
			case 'fieldlabel':
948
				$params = [
949
					'name' => $name,
950
					'column' => $name,
951
					'label' => 'LBL_LABEL',
952
					'uitype' => 1,
953
					'typeofdata' => 'V~M',
954
					'maximumlength' => '50',
955
					'purifyType' => \App\Purifier::TEXT
956
				];
957
				break;
958
			case 'mandatory':
959
				$params = [
960
					'name' => $name,
961
					'column' => $name,
962
					'label' => 'LBL_MANDATORY_FIELD',
963
					'uitype' => 56,
964
					'typeofdata' => 'C~O',
965
					'maximumlength' => '1',
966
					'purifyType' => \App\Purifier::BOOL
967
				];
968
				break;
969
			case 'presence':
970
				$params = [
971
					'name' => $name,
972
					'column' => $name,
973
					'label' => 'LBL_ACTIVE',
974
					'uitype' => 56,
975
					'typeofdata' => 'C~O',
976
					'maximumlength' => '1',
977
					'purifyType' => \App\Purifier::BOOL
978
				];
979
				break;
980
			case 'quickcreate':
981
				$params = [
982
					'name' => $name,
983
					'column' => $name,
984
					'label' => 'LBL_QUICK_CREATE',
985
					'uitype' => 56,
986
					'typeofdata' => 'C~O',
987
					'maximumlength' => '1',
988
					'purifyType' => \App\Purifier::BOOL
989
				];
990
				break;
991
			case 'summaryfield':
992
				$params = [
993
					'name' => $name,
994
					'column' => $name,
995
					'label' => 'LBL_SUMMARY_FIELD',
996
					'uitype' => 56,
997
					'typeofdata' => 'C~O',
998
					'maximumlength' => '1',
999
					'purifyType' => \App\Purifier::BOOL
1000
				];
1001
				break;
1002
			case 'header_field':
1003
				$params = [
1004
					'name' => $name,
1005
					'column' => $name,
1006
					'label' => 'LBL_HEADER_FIELD',
1007
					'uitype' => 56,
1008
					'typeofdata' => 'C~O',
1009
					'maximumlength' => '1',
1010
					'purifyType' => \App\Purifier::BOOL
1011
				];
1012
				break;
1013
			case 'masseditable':
1014
				$params = [
1015
					'name' => $name,
1016
					'column' => $name,
1017
					'label' => 'LBL_MASS_EDIT',
1018
					'uitype' => 56,
1019
					'typeofdata' => 'C~O',
1020
					'maximumlength' => '1',
1021
					'purifyType' => \App\Purifier::BOOL
1022
				];
1023
				break;
1024
			case 'generatedtype':
1025
				$params = [
1026
					'name' => $name,
1027
					'column' => $name,
1028
					'label' => 'LBL_GENERATED_TYPE',
1029
					'uitype' => 56,
1030
					'typeofdata' => 'C~O',
1031
					'maximumlength' => '1',
1032
					'purifyType' => \App\Purifier::BOOL,
1033
					'isEditableReadOnly' => !App\Config::developer('CHANGE_GENERATEDTYPE')
1034
				];
1035
				break;
1036
			case 'defaultvalue':
1037
				$params = [
1038
					'name' => $name,
1039
					'column' => $name,
1040
					'label' => 'LBL_DEFAULT_VALUE',
1041
					'uitype' => 56,
1042
					'typeofdata' => 'C~O',
1043
					'maximumlength' => '1',
1044
					'purifyType' => \App\Purifier::BOOL
1045
				];
1046
				break;
1047
			case 'fieldMask':
1048
				$params = [
1049
					'name' => $name,
1050
					'column' => $name,
1051
					'label' => 'LBL_FIELD_MASK',
1052
					'uitype' => 1,
1053
					'typeofdata' => 'V~O',
1054
					'maximumlength' => '25',
1055
					'purifyType' => \App\Purifier::TEXT,
1056
					'tooltip' => 'LBL_FIELD_MASK_INFO'
1057
				];
1058
				break;
1059
			case 'close_state':
1060
				$params = [
1061
					'name' => $name,
1062
					'column' => $name,
1063
					'label' => 'LBL_CLOSES_RECORD',
1064
					'uitype' => 56,
1065
					'typeofdata' => 'C~O',
1066
					'maximumlength' => '5',
1067
					'purifyType' => \App\Purifier::BOOL,
1068
					'tooltip' => 'LBL_BLOCKED_RECORD_INFO',
1069
					'table' => 'u_#__picklist_close_state'
1070
				];
1071
				break;
1072
			case 'icon':
1073
				$params = [
1074
					'name' => $name,
1075
					'column' => $name,
1076
					'label' => 'LBL_ICON',
1077
					'uitype' => 62,
1078
					'typeofdata' => 'V~O',
1079
					'maximumlength' => '255',
1080
					'purifyType' => \App\Purifier::TEXT,
1081
					'table' => $tableName
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $tableName seems to be never defined.
Loading history...
1082
				];
1083
				break;
1084
			case 'time_counting':
1085
				$params = [
1086
					'name' => $name,
1087
					'column' => $name,
1088
					'label' => 'LBL_TIME_COUNTING',
1089
					'uitype' => 16,
1090
					'typeofdata' => 'V~M',
1091
					'maximumlength' => '250',
1092
					'purifyType' => \App\Purifier::INTEGER,
1093
					'tooltip' => 'LBL_TIME_COUNTING_INFO',
1094
					'defaultvalue' => 0,
1095
					'picklistValues' => [
1096
						0 => \App\Language::translate('LBL_NONE', '_Base'),
1097
						\App\RecordStatus::TIME_COUNTING_REACTION => \App\Language::translate('LBL_TIME_COUNTING_REACTION', $qualifiedModuleName),
1098
						\App\RecordStatus::TIME_COUNTING_RESOLVE => \App\Language::translate('LBL_TIME_COUNTING_RESOLVE', $qualifiedModuleName),
1099
						\App\RecordStatus::TIME_COUNTING_IDLE => \App\Language::translate('LBL_TIME_COUNTING_IDLE', $qualifiedModuleName)
1100
					],
1101
					'table' => $tableName
1102
				];
1103
				break;
1104
			case 'record_state':
1105
				$params = [
1106
					'name' => $name,
1107
					'column' => $name,
1108
					'label' => 'LBL_RECORD_STATE',
1109
					'uitype' => 16,
1110
					'typeofdata' => 'V~M',
1111
					'maximumlength' => '250',
1112
					'purifyType' => \App\Purifier::INTEGER,
1113
					'tooltip' => 'LBL_RECORD_STATE_INFO',
1114
					'defaultvalue' => \App\RecordStatus::RECORD_STATE_NO_CONCERN,
1115
					'picklistValues' => [],
1116
					'table' => $tableName
1117
				];
1118
				foreach (\App\RecordStatus::getLabels() as $key => $value) {
1119
					$params['picklistValues'][$key] = \App\Language::translate($value, $qualifiedModuleName);
1120
				}
1121
				break;
1122
			case 'roles':
1123
				$params = [
1124
					'name' => $name,
1125
					'column' => $name,
1126
					'label' => 'LBL_ASSIGN_TO_ROLE',
1127
					'uitype' => 33,
1128
					'typeofdata' => 'V~O',
1129
					'maximumlength' => '500',
1130
					'purifyType' => \App\Purifier::TEXT,
1131
					'defaultvalue' => 'all',
1132
					'picklistValues' => [
1133
						'all' => \App\Language::translate('LBL_ALL_ROLES', $qualifiedModuleName)
1134
					],
1135
					'table' => $tableName
1136
				];
1137
				foreach (\Settings_Roles_Record_Model::getAll() as $key => $roleModel) {
1138
					$params['picklistValues'][$key] = \App\Language::translate($roleModel->get('rolename'), 'Settings:Roles');
1139
				}
1140
				break;
1141
			default:
1142
				break;
1143
		}
1144
1145
		return $params ? \Vtiger_Field_Model::init($qualifiedModuleName, $params, $name)->set('sourceFieldModel', $this->fieldModel) : null;
0 ignored issues
show
Bug introduced by
The property fieldModel does not exist on Settings_LayoutEditor_Module_Model. Did you mean fieldsModule?
Loading history...
1146
	}
1147
1148
	/**
1149
	 * Loading the list of multireference fields related with module.
1150
	 *
1151
	 * @param string $sourceModule Source module name
1152
	 * @param string $moduleName
1153
	 *
1154
	 * @return Vtiger_Field_Model[]
1155
	 */
1156
	public static function getMultiReferenceFieldsRelatedWithModule(string $moduleName): array
1157
	{
1158
		$referenceFieldModels = [];
1159
		$relatedReferenceFields = (new \App\Db\Query())
1160
			->select(['fieldid'])
1161
			->from('vtiger_field')
1162
			->where(['and',
1163
				['uitype' => 321],
1164
				['like', 'fieldparams', '{"module":"' . $moduleName . '"%', false]
1165
			])->column();
1166
		foreach ($relatedReferenceFields as $fieldId) {
1167
			$fieldModel = Vtiger_Field_Model::getInstanceFromFieldId($fieldId);
1168
			if ($fieldModel->isActiveField()) {
1169
				$referenceFieldModels[] = $fieldModel;
1170
			}
1171
		}
1172
		return $referenceFieldModels;
1173
	}
1174
}
1175