Passed
Push — developer ( 9459cf...0f6457 )
by Radosław
26:45
created

getEntityInstance()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
rs 10
ccs 0
cts 0
cp 0
cc 1
nc 1
nop 0
crap 2
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 Settings_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
	/** @var string[] List of fields in edit view modal */
41
	const EDIT_FIELDS_FORM = [
42
		'label', 'presence', 'quickcreate', 'summaryfield', 'generatedtype', 'masseditable', 'header_field',
43
		'displaytype', 'maxlengthtext', 'maxwidthcolumn', 'tabindex', 'mandatory', 'icon',
44
	];
45
	/** @var array Relations */
46
	public $relations;
47
	/** @var Vtiger_Module_Model Source module */
48
	public $sourceModule;
49
50
	/**
51
	 * Function to get the Module/Tab id.
52
	 *
53
	 * @return int
54
	 */
55
	public function getId()
56
	{
57
		return $this->getSourceModule()->getId();
58
	}
59
60
	/**
61
	 * Set source module.
62
	 *
63
	 * @param string $sourceModule
64
	 *
65
	 * @return $this
66
	 */
67
	public function setSourceModule(string $sourceModule)
68
	{
69
		$this->sourceModule = \Vtiger_Module_Model::getInstance($sourceModule);
70
71
		return $this;
72
	}
73
74
	/**
75
	 * Get source module model.
76
	 *
77
	 * @return Vtiger_Module_Model
78
	 */
79
	public function getSourceModule(): Vtiger_Module_Model
80
	{
81
		return $this->sourceModule;
82
	}
83
84
	/**
85 21
	 * Gets parent name.
86
	 *
87
	 * @return string
88 21
	 */
89
	public function getParentName()
90
	{
91
		return $this->parent;
92
	}
93
94
	/**
95
	 * Function that returns all the fields for the module.
96
	 *
97
	 * @param mixed $blockInstance
98
	 *
99
	 * @return Vtiger_Field_Model[] - list of field models
100
	 */
101
	public function getFields($blockInstance = false)
0 ignored issues
show
Unused Code introduced by
The parameter $blockInstance 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

101
	public function getFields(/** @scrutinizer ignore-unused */ $blockInstance = 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...
102
	{
103
		if (empty($this->fields)) {
104
			$fieldList = [];
105
			$blocks = $this->getBlocks();
106
			$blockId = [];
107
			foreach ($blocks as $block) {
108
				$blockId[] = $block->get('id');
109
			}
110
			if (\count($blockId) > 0) {
111
				$fieldList = Settings_LayoutEditor_Field_Model::getInstanceFromBlockIdList($blockId);
112
			}
113
			$this->fields = $fieldList;
0 ignored issues
show
Bug Best Practice introduced by
The property fields does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
114
		}
115
116
		return $this->fields;
117
	}
118
119
	/**
120
	 * Function returns all the blocks for the module.
121
	 *
122
	 * @return Vtiger_Block_Model[] - list of block models
123
	 */
124
	public function getBlocks()
125
	{
126
		if (empty($this->blocks)) {
127
			$blocksList = [];
128
			$moduleBlocks = Settings_LayoutEditor_Block_Model::getAllForModule($this->sourceModule);
129
			foreach ($moduleBlocks as $block) {
130
				if ($block->get('label')) {
131
					$blocksList[$block->get('label')] = $block;
132
				}
133
			}
134
			$this->blocks = $blocksList;
0 ignored issues
show
Bug Best Practice introduced by
The property blocks does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
135
		}
136
137
		return $this->blocks;
138
	}
139
140
	/**
141
	 * List of supported field types.
142
	 *
143
	 * @return string[]
144
	 */
145
	public function getAddSupportedFieldTypes()
146
	{
147
		return [
148
			'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',
149 21
		];
150
	}
151 21
152 21
	/**
153 21
	 * Function which will give information about the field types that are supported for add.
154 21
	 *
155 21
	 * @return array
156
	 */
157
	public function getAddFieldTypeInfo()
158 21
	{
159
		$fieldTypesInfo = [];
160
		$addFieldSupportedTypes = $this->getAddSupportedFieldTypes();
161 21
		$lengthSupportedFieldTypes = ['Text', 'Decimal', 'Integer', 'Currency', 'Editor', 'AdvPercentage'];
162
		foreach ($addFieldSupportedTypes as $fieldType) {
163
			$details = [];
164 21
			if (\in_array($fieldType, $lengthSupportedFieldTypes)) {
165
				$details['lengthsupported'] = true;
166
			}
167 21
			if ('Editor' === $fieldType) {
168
				$details['noLimitForLength'] = true;
169
			}
170 21
			if ('Decimal' === $fieldType || 'Currency' === $fieldType || 'AdvPercentage' === $fieldType) {
171 21
				$details['decimalSupported'] = true;
172
				$details['maxFloatingDigits'] = 5;
173
				if ('Currency' === $fieldType) {
174 21
					$details['decimalReadonly'] = true;
175 3
				}
176 3
				//including mantisaa and integer part
177
				$details['maxLength'] = 64;
178
			}
179 3
			if ('Picklist' === $fieldType || 'MultiSelectCombo' === $fieldType || 'MultipicklistTags' === $fieldType) {
180 3
				$details['preDefinedValueExists'] = true;
181
				//text area value type , can give multiple values
182
				$details['preDefinedValueType'] = 'text';
183 3
				if ('Picklist' === $fieldType) {
184
					$details['picklistoption'] = true;
185
				}
186
			}
187
			if ('Related1M' === $fieldType) {
188 21
				$details['ModuleListMultiple'] = true;
189 21
			}
190 21
			$fieldTypesInfo[$fieldType] = $details;
191 21
		}
192
		return $fieldTypesInfo;
193
	}
194
195
	/**
196
	 * Verification of data.
197
	 *
198
	 * @param array $data
199 21
	 * @param bool  $throw
200 2
	 */
201 19
	public function validate(array $data, bool $throw = true)
202 1
	{
203 1
		$message = null;
204 1
		$code = null;
205 1
		$result = false;
206 1
		foreach ($data as $key => $value) {
207 1
			switch ($key) {
208 18
				case 'fieldLabel':
209
					if ($result = $this->checkFieldLabelExists($value)) {
210
						$message = \App\Language::translate('LBL_DUPLICATE_FIELD_EXISTS', 'Settings::LayoutEditor');
211 21
						$code = 513;
212 21
					}
213 21
					break;
214 21
				case 'fieldName':
215 21
					$value = strtolower($value);
216 21
					if ($result = $this->checkFieldNameCharacters($value)) {
217 21
						$message = \App\Language::translate('LBL_INVALIDCHARACTER', 'Settings::LayoutEditor');
218 21
						$code = 512;
219 21
					} elseif ($result = $this->checkFieldNameExists($value)) {
220 21
						$message = \App\Language::translate('LBL_DUPLICATE_FIELD_EXISTS', 'Settings::LayoutEditor');
221 21
						$code = 512;
222 21
					} elseif ($result = $this->checkFieldNameIsAnException($value)) {
223 21
						$message = \App\Language::translate('LBL_FIELD_NAME_IS_RESERVED', 'Settings::LayoutEditor');
224 21
						$code = 512;
225 21
					} elseif (\strlen($value) > 30) {
226 21
						$message = \App\Language::translate('LBL_EXCEEDED_MAXIMUM_NUMBER_CHARACTERS_FOR_FIELD_NAME', 'Settings::LayoutEditor');
227 1
						$code = 512;
228
					} elseif (isset($data['fieldType']) && \in_array($data['fieldType'], ['Picklist', 'MultiSelectCombo']) && ($result = $this->checkIfPicklistFieldNameReserved($value))) {
229 21
						$message = \App\Language::translate('LBL_FIELD_NAME_IS_RESERVED', 'Settings::LayoutEditor');
230 21
						$code = 512;
231
					}
232 21
					break;
233 21
				case 'fieldType':
234 21
					if ($result = !\in_array($value, $this->getAddSupportedFieldTypes())) {
235 3
						$message = \App\Language::translate('LBL_WRONG_FIELD_TYPE', 'Settings::LayoutEditor');
236
						$code = 513;
237 21
					}
238 1
					break;
239
				case 'pickListValues':
240
					foreach ($value as $val) {
241 1
						if (($result = preg_match('/[\<\>\"\#\,]/', $val)) || ($result = preg_match('/[\<\>\"\#\,]/', \App\Purifier::decodeHtml($val)))) {
242
							$message = \App\Language::translateArgs('ERR_SPECIAL_CHARACTERS_NOT_ALLOWED', 'Other.Exceptions', '<>"#,');
243 1
							$code = 512;
244 1
						} elseif ($result = \strlen($val) > 200) {
245 1
							$message = \App\Language::translate('ERR_EXCEEDED_NUMBER_CHARACTERS', 'Other.Exceptions');
246 1
							$code = 512;
247
						}
248
					}
249 21
					if (\count($value) !== \count(array_unique(array_map('strtolower', $value)))) {
250 21
						$message = \App\Language::translate('LBL_DUPLICATES_VALUES_FOUND', 'Other.Exceptions');
251
						$code = 512;
252
					}
253
					break;
254
				default:
255
					break;
256
			}
257
			if ($result) {
258
				if ($throw) {
259
					throw new \App\Exceptions\AppException($message, $code);
260
				}
261 21
				return [$key => $message];
262
			}
263 21
		}
264 21
		return $result;
265 21
	}
266 21
267 1
	/**
268 1
	 * Add field.
269 1
	 *
270 1
	 * @param string $fieldType
271 1
	 * @param int    $blockId
272 20
	 * @param array  $params
273
	 *
274
	 * @throws Exception
275 20
	 *
276 1
	 * @return \Settings_LayoutEditor_Field_Model
277 1
	 */
278 1
	public function addField($fieldType, $blockId, $params)
279 1
	{
280 1
		$label = $params['fieldLabel'];
281
		$name = strtolower($params['fieldName']);
282 1
		$pickListValues = [];
283 1
		if (\array_key_exists('pickListValues', $params)) {
284 19
			$pickListValues = $params['pickListValues'] = \is_string($params['pickListValues']) ? [$params['pickListValues']] : $params['pickListValues'];
285 1
		}
286 1
		$fieldParams = '';
287 1
		$this->validate($params);
288 1
		$moduleName = $this->getName();
289 18
		$tableName = $this->getTableName($params['fieldTypeList']);
290 1
		switch ($fieldType) {
291 1
			case 'Tree':
292 1
			case 'CategoryMultipicklist':
293 1
				$fieldParams = (int) $params['tree'];
294
				break;
295
			case 'MultiReferenceValue':
296 1
				$fieldParams = [
297
					'module' => $params['MRVModule'],
298 1
					'field' => $params['MRVField'],
299 1
					'filterField' => $params['MRVFilterField'] ?? null,
300 1
					'filterValue' => $params['MRVFilterValue'] ?? null,
301 1
				];
302 17
				\App\Db::getInstance()->createCommand()->insert('s_#__multireference', ['source_module' => $moduleName, 'dest_module' => $params['MRVModule']])->execute();
303 1
				break;
304 1
			case 'ServerAccess':
305 1
				$fieldParams = (int) $params['server'];
306 1
				break;
307 16
			case 'Token':
308 1
				(new \App\BatchMethod(['method' => '\App\Fields\Token::setTokens', 'params' => [$name, $moduleName]]))->save();
309 1
				break;
310 1
			case 'MultiReference':
311 1
				$fieldParams = [
312 15
					'module' => $params['referenceModule']
313 1
				];
314 1
				break;
315 1
			case 'MapCoordinates':
316 1
				$fieldParams = [
317 14
					'showType' => $params['isCoordinateType'] ?? 0,
318 1
					'type' => $params['type'] ?? null,
319 1
					'showMap' => $params['isCoordinateMap'] ?? 0,
320 1
					'showLocation' => $params['isCoordinateMeLokaction'] ?? 0,
321 1
				];
322 13
				break;
323 2
			case 'Group':
324 2
				$fieldParams = [
325 1
					'showAllGroups' => $params['showAllGroups'] ?? 0
326
				];
327 2
				break;
328 2
			default:
329 2
				break;
330 11
		}
331 1
		$details = $this->getTypeDetailsForAddField($fieldType, $params);
332 1
		$fieldModel = new Settings_LayoutEditor_Field_Model();
333 1
		$fieldModel->set('name', $name)
334 1
			->set('table', $tableName)
335 10
			->set('generatedtype', $params['generatedtype'] ?? 2)
336 1
			->set('helpinfo', $params['helpinfo'] ?? '')
337 1
			->set('uitype', $details['uitype'])
338 1
			->set('label', $label)
339 1
			->set('typeofdata', $details['typeofdata'])
340 9
			->set('quickcreate', $params['quickcreate'] ?? 1)
341 1
			->set('summaryfield', $params['summaryfield'] ?? 0)
342 1
			->set('header_field', $params['header_field'] ?? null)
343 1
			->set('fieldparams', $params['fieldparams'] ?? ($fieldParams ? \App\Json::encode($fieldParams) : ''))
344 1
			->set('columntype', $details['dbType']);
345 8
		if ('Editor' === $fieldType) {
346 1
			$fieldModel->set('maximumlength', $params['fieldLength'] ?? null);
347 1
		}
348 1
		if (isset($details['displayType']) || isset($params['displayType'])) {
349 1
			$fieldModel->set('displaytype', $params['displayType'] ?? $details['displayType']);
350 7
		}
351 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

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