Passed
Push — developer ( 62331d...cbbb09 )
by Radosław
19:52
created

Vtiger_Field_Model::init()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 23
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 20
dl 0
loc 23
ccs 5
cts 5
cp 1
rs 9.6
c 0
b 0
f 0
cc 2
nc 2
nop 3
crap 2
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
/**
13
 * Vtiger Field Model Class.
14
 */
15
class Vtiger_Field_Model extends vtlib\Field
16
{
17
	const REFERENCE_TYPE = 'reference';
18
	const OWNER_TYPE = 'owner';
19
	const CURRENCY_LIST = 'currencyList';
20
	const QUICKCREATE_MANDATORY = 0;
21
	const QUICKCREATE_NOT_ENABLED = 1;
22
	const QUICKCREATE_ENABLED = 2;
23
	const QUICKCREATE_NOT_PERMITTED = 3;
24
25
	public static $referenceTypes = ['reference', 'referenceLink', 'referenceProcess', 'referenceSubProcess', 'referenceExtend', 'referenceSubProcessSL'];
26
27
	/** @var array Field maximum length by UiType. */
28
	public static $uiTypeMaxLength = [
29
		99 => 100,
30
		120 => 65535,
31
		106 => '3,64',
32
		156 => '3',
33
		360 => '0,99999999',
34
	];
35
36
	/** @var int[] Field maximum length by db type. */
37
	public static $typesMaxLength = [
38
		'tinytext' => 255,
39
		'text' => 65535,
40
		'mediumtext' => 16777215,
41
		'longtext' => 4294967295,
42
		'blob' => 65535,
43
		'mediumblob' => 16777215,
44
		'longblob' => 4294967295,
45
	];
46
47
	/** @var Vtiger_Field_Model[] Cache by field id */
48
	protected static $instanceCacheById = [];
49
50
	/** @var Vtiger_Field_Model[][] Cache by module id and field id */
51
	protected static $instanceCacheByName = [];
52
53
	/**
54
	 * @var array
55
	 */
56
	protected $fieldInfo;
57
	protected $fieldType;
58
	protected $fieldDataTypeShort;
59
	protected $uitype_instance;
60
61 118
	/** @var string[] List of modules the field referenced to. */
62
	public $referenceList;
63 118
64 118
	/** @var string[] Picklist values only for custom fields;. */
65
	public $picklistValues;
66 4
67
	/** @var bool Is calculate field */
68
	protected $isCalculateField = true;
69
70
	/** @var bool|null Field visibility permissions */
71
	protected $permissions;
72
73
	/** @var Vtiger_Base_UIType Vtiger_Base_UIType or UI Type specific model instance */
74
	protected $uitypeModel;
75
76
	/** @var bool[] Permissions cache */
77 30
	protected $permissionsCache = [];
78
79 30
	/**
80
	 * Initialize.
81 30
	 *
82
	 * @param string     $module
83
	 * @param array      $data
84
	 * @param mixed|null $name
85
	 *
86
	 * @return \Vtiger_Field_Model
87
	 */
88
	public static function init($module = 'Vtiger', $data = [], $name = '')
89 64
	{
90
		if (\App\Module::getModuleId($module)) {
91 64
			$moduleModel = Vtiger_Module_Model::getInstance($module);
92
		} else {
93
			$modelClassName = \Vtiger_Loader::getComponentClassName('Model', 'Module', $module);
94
			$moduleModel = new $modelClassName();
95
		}
96
		$modelClassName = \Vtiger_Loader::getComponentClassName('Model', 'Field', $module);
97
		$instance = new $modelClassName();
98
		$instance->setModule($moduleModel);
99 67
		$instance->setData(array_merge([
100
			'uitype' => 1,
101 67
			'column' => $name,
102
			'name' => $name,
103
			'label' => $name,
104
			'displaytype' => 1,
105
			'typeofdata' => 'V~O',
106
			'presence' => 0,
107
			'isReadOnly' => false,
108
			'isEditableReadOnly' => false,
109 53
		], $data));
110
		return $instance;
111 53
	}
112
113
	/**
114
	 * Function to get the value of a given property.
115
	 *
116
	 * @param string $propertyName
117
	 *
118
	 * @return mixed|null
119 6
	 */
120
	public function get(string $propertyName)
121 6
	{
122
		if (property_exists($this, $propertyName)) {
123
			return $this->{$propertyName};
124
		}
125
		return null;
126
	}
127
128
	/**
129 5813
	 * Function which sets value for given name.
130
	 *
131 5813
	 * @param string $name  - name for which value need to be assinged
132
	 * @param mixed  $value - values that need to be assigned
133
	 *
134
	 * @return Vtiger_Field_Model
135
	 */
136
	public function set(string $name, $value)
137
	{
138
		$this->{$name} = $value;
139 5836
		return $this;
140
	}
141 5836
142
	/**
143
	 * Function to get the Field Id.
144
	 *
145
	 * @return int
146
	 */
147
	public function getId()
148
	{
149 37
		return $this->id;
150
	}
151 37
152
	/**
153
	 * Get name.
154
	 *
155
	 * @return string
156
	 */
157
	public function getName()
158
	{
159
		return $this->name;
160
	}
161
162
	/**
163
	 * Get full name.
164
	 *
165
	 * @return string
166
	 */
167
	public function getFullName()
168
	{
169 16
		return $this->get('source_field_name') ? "{$this->getName()}:{$this->getModuleName()}:{$this->get('source_field_name')}" : $this->getName();
170
	}
171 16
172 3
	/**
173 3
	 * Get full label translation.
174
	 *
175
	 * @param Vtiger_Module_Model|null $module
176 3
	 *
177
	 * @return string
178
	 */
179 3
	public function getFullLabelTranslation(?Vtiger_Module_Model $module = null): string
180
	{
181 16
		$translation = '';
182
		if ($this->get('source_field_name') && !$this->get('isLabelCustomized')) {
183
			if (!$module) {
184
				throw new \App\Exceptions\AppException('ERR_ARGUMENT_DOES_NOT_EXIST');
185
			}
186
			$translation = \App\Language::translate($module->getFieldByName($this->get('source_field_name'))->getFieldLabel(), $module->getName()) . ' - ';
0 ignored issues
show
Bug introduced by
$module->getName() of type boolean is incompatible with the type string expected by parameter $moduleName of App\Language::translate(). ( Ignorable by Annotation )

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

186
			$translation = \App\Language::translate($module->getFieldByName($this->get('source_field_name'))->getFieldLabel(), /** @scrutinizer ignore-type */ $module->getName()) . ' - ';
Loading history...
187
		}
188
		return $translation .= \App\Language::translate($this->getFieldLabel(), $this->getModuleName());
189
	}
190
191
	/**
192
	 * Get field name.
193
	 *
194
	 * @deprecated Use $this->getName()
195
	 *
196
	 * @return string
197
	 */
198
	public function getFieldName()
199
	{
200
		return $this->name;
201 5785
	}
202
203 5785
	/**
204
	 * Get field label.
205
	 *
206
	 * @return string
207
	 */
208
	public function getFieldLabel()
209
	{
210
		return $this->label;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->label returns the type boolean which is incompatible with the documented return type string.
Loading history...
211 11
	}
212
213 11
	/**
214
	 * Get table name.
215
	 *
216
	 * @return string
217
	 */
218
	public function getTableName()
219
	{
220
		return $this->table;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->table returns the type boolean which is incompatible with the documented return type string.
Loading history...
221 89
	}
222
223 89
	/**
224 69
	 * Get column label.
225 69
	 *
226
	 * @return string
227
	 */
228 69
	public function getColumnName()
229
	{
230 69
		return $this->column;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->column returns the type boolean which is incompatible with the documented return type string.
Loading history...
231 23
	}
232
233 68
	/**
234 68
	 * Get ui type.
235 10
	 *
236 10
	 * @return int
237 68
	 */
238
	public function getUIType()
239
	{
240 68
		return $this->uitype;
241 7
	}
242 7
243 66
	/**
244 3
	 * Function to retrieve full data.
245 3
	 *
246 66
	 * @return <array>
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...
247 3
	 */
248 3
	public function getData()
249 66
	{
250 7
		return get_object_vars($this);
251 7
	}
252 66
253 10
	/**
254 10
	 * Get module model.
255 66
	 *
256 11
	 * @return Vtiger_Module_Model
257 11
	 */
258 66
	public function getModule()
259
	{
260
		if (!isset($this->module)) {
261 66
			if (isset($this->block->module)) {
262 3
				$moduleObj = $this->block->module;
263 3
			}
264 66
			//fix for opensource emailTemplate listview break
265 3
			if (empty($moduleObj)) {
266 3
				return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type Vtiger_Module_Model.
Loading history...
267 66
			}
268 3
			$this->module = Vtiger_Module_Model::getInstanceFromModuleObject($moduleObj);
0 ignored issues
show
Bug Best Practice introduced by
The property module does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
269 3
		}
270 66
		return $this->module;
271 3
	}
272 3
273 66
	public function setModule($moduleInstance)
274 3
	{
275 3
		$this->module = $moduleInstance;
0 ignored issues
show
Bug Best Practice introduced by
The property module does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
276 66
		return $this;
277 10
	}
278 10
279 65
	/**
280 65
	 * Function to retieve display value for a value.
281 8
	 *
282 8
	 * @param mixed                    $value          value which need to be converted to display value
283 65
	 * @param bool|int                 $record
284 8
	 * @param bool|Vtiger_Record_Model $recordInstance
285 8
	 * @param bool                     $rawText
286 65
	 * @param bool|int                 $length         Length of the text
287 7
	 * @param mixed                    $recordModel
288 7
	 *
289 65
	 * @return mixed converted display value
290 7
	 */
291 7
	public function getDisplayValue($value, $record = false, $recordModel = false, $rawText = false, $length = false)
292 65
	{
293 7
		return $this->getUITypeModel()->getDisplayValue($value, $record, $recordModel, $rawText, $length);
294 7
	}
295 65
296 8
	/**
297 8
	 * Function to retrieve display type of a field.
298 65
	 *
299 9
	 * @return int display type of the field
300 9
	 */
301 65
	public function getDisplayType()
302 8
	{
303 8
		return (int) $this->get('displaytype');
304 65
	}
305 8
306 8
	/**
307 63
	 * Function to get the Webservice Field data type.
308 5
	 *
309 5
	 * @return string Data type of the field
310 63
	 */
311 4
	public function getFieldDataType()
312 4
	{
313 63
		if (!isset($this->fieldDataType)) {
314 6
			$uiType = $this->getUIType();
315 6
			if (55 === $uiType) {
316 61
				$cacheName = $uiType . '-' . $this->getName();
317 3
			} else {
318 3
				$cacheName = $uiType . '-' . $this->get('typeofdata');
319 61
			}
320 6
			if (App\Cache::has('FieldDataType', $cacheName)) {
321 6
				$fieldDataType = App\Cache::get('FieldDataType', $cacheName);
322 59
			} else {
323 4
				switch ($uiType) {
324 4
					case 4:
325 59
						$fieldDataType = 'recordNumber';
326 6
						break;
327 6
					case 8:
328 59
						$fieldDataType = 'totalTime';
329 1
						break;
330 1
					case 9:
331 59
						$fieldDataType = 'percentage';
332
						break;
333
					case 12:
334 59
						$fieldDataType = 'accountName';
335 7
						break;
336 7
					case 27:
337 59
						$fieldDataType = 'fileLocationType';
338 3
						break;
339 3
					case 28:
340 59
						$fieldDataType = 'documentsFileUpload';
341 4
						break;
342 4
					case 31:
343 59
						$fieldDataType = 'theme';
344 4
						break;
345 4
					case 32:
346 58
						$fieldDataType = 'languages';
347
						break;
348
					case 35:
349
						$fieldDataType = 'country';
350 58
						break;
351 58
					case 54:
352 45
						$fieldDataType = 'multiowner';
353
						break;
354 33
					case 64:
355 33
						$fieldDataType = 'referenceSubProcessSL';
356 33
						break;
357 5
					case 65:
358 5
						$fieldDataType = 'referenceExtend';
359 31
						break;
360 14
					case 66:
361 14
						$fieldDataType = 'referenceProcess';
362 28
						break;
363 9
					case 67:
364 9
						$fieldDataType = 'referenceLink';
365 27
						break;
366 8
					case 68:
367 8
						$fieldDataType = 'referenceSubProcess';
368 27
						break;
369 26
					case 69:
370 17
						$fieldDataType = 'image';
371 17
						break;
372 23
					case 79:
373
					case 80:
374
						$fieldDataType = 'datetime';
375 23
						break;
376 18
					case 86:
377 18
						$fieldDataType = 'pbx';
378 19
						break;
379
					case 87:
380 19
						$fieldDataType = 'mailComposer';
381 19
						break;
382
					case 98:
383
						$fieldDataType = 'userRole';
384 58
						break;
385
					case 99:
386 68
						$fieldDataType = 'password';
387
						break;
388 69
					case 101:
389
						$fieldDataType = 'userReference';
390 89
						break;
391
					case 115:
392
						$fieldDataType = 'picklist';
393
						break;
394
					case 117:
395
						$fieldDataType = 'currencyList';
396
						break;
397
					case 120:
398 6
						$fieldDataType = 'sharedOwner';
399
						break;
400 6
					case 301:
401 3
						$fieldDataType = 'modules';
402
						break;
403 6
					case 302:
404 1
						$fieldDataType = 'tree';
405
						break;
406 6
					case 303:
407 5
						$fieldDataType = 'taxes';
408 5
						break;
409 5
					case 304:
410 5
						$fieldDataType = 'inventoryLimit';
411 5
						break;
412 5
					case 305:
413
						$fieldDataType = 'multiReferenceValue';
414 5
						break;
415 5
					case 308:
416 5
						$fieldDataType = 'rangeTime';
417 5
						break;
418 5
					case 309:
419 5
						$fieldDataType = 'categoryMultipicklist';
420
						break;
421 6
					case 311:
422 6
						$fieldDataType = 'multiImage';
423 6
						break;
424 6
					case 312:
425
						$fieldDataType = 'authySecretTotp';
426
						break;
427
					case 313:
428 6
						$fieldDataType = 'twitter';
429
						break;
430 6
					case 314:
431
						$fieldDataType = 'multiEmail';
432
						break;
433
					case 315:
434
						$fieldDataType = 'multiDependField';
435
						break;
436
					case 316:
437
						$fieldDataType = 'smtp';
438
						break;
439
					case 317:
440
						$fieldDataType = 'currencyInventory';
441
						break;
442
					case 318:
443
						$fieldDataType = 'serverAccess';
444
						break;
445
					case 319:
446
						$fieldDataType = 'multiDomain';
447
						break;
448
					case 320:
449
						$fieldDataType = 'multiListFields';
450
						break;
451
					case 321:
452
						$fieldDataType = 'multiReference';
453
						break;
454
					case 322:
455
						$fieldDataType = 'mailScannerActions';
456
						break;
457
					case 323:
458
						$fieldDataType = 'mailScannerFields';
459
						break;
460
					case 324:
461
						$fieldDataType = 'token';
462 5851
						break;
463
					case 325:
464 5851
						$fieldDataType = 'magentoServer';
465 5827
						break;
466
					case 326:
467 44
						$fieldDataType = 'meetingUrl';
468
						break;
469
					case 327:
470
						$fieldDataType = 'barcode';
471
						break;
472
					case 328:
473
						$fieldDataType = 'changesJson';
474
						break;
475
					case 329:
476
						$fieldDataType = 'iban';
477
						break;
478
					case 330:
479
						$fieldDataType = 'multiAttachment';
480
						break;
481
					default:
482 4
						$fieldsDataType = App\Field::getFieldsTypeFromUIType();
483
						if (isset($fieldsDataType[$uiType])) {
484 4
							$fieldDataType = $fieldsDataType[$uiType]['fieldtype'];
485
						} else {
486
							$fieldTypeArray = explode('~', $this->get('typeofdata'));
487
							switch ($fieldTypeArray[0]) {
488
								case 'T':
489
									$fieldDataType = 'time';
490
									break;
491
								case 'D':
492
									$fieldDataType = 'date';
493
									break;
494 4
								case 'DT':
495
									$fieldDataType = 'datetime';
496 4
									break;
497
								case 'E':
498
									$fieldDataType = 'email';
499 4
									break;
500 4
								case 'N':
501 4
								case 'NN':
502 4
									$fieldDataType = 'double';
503 3
									break;
504 3
								case 'P':
505
									$fieldDataType = 'password';
506 2
									break;
507
								case 'I':
508 4
									$fieldDataType = 'integer';
509 1
									break;
510
								case 'V':
511
								default:
512 4
									$fieldDataType = 'string';
513 3
									break;
514 3
							}
515
						}
516
						break;
517
				}
518
				App\Cache::save('FieldDataType', $cacheName, $fieldDataType);
519
			}
520
			$this->fieldDataType = $fieldDataType;
0 ignored issues
show
Bug Best Practice introduced by
The property fieldDataType does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
521
		}
522 4
		return $this->fieldDataType;
523
	}
524
525
	/**
526
	 * Function to get list of modules the field refernced to.
527
	 *
528
	 * @return string[] list of modules for which field is refered to
529
	 */
530
	public function getReferenceList()
531
	{
532
		if (isset($this->referenceList)) {
533
			return $this->referenceList;
534
		}
535
		if (\App\Cache::has('getReferenceList', $this->getId())) {
536
			return \App\Cache::get('getReferenceList', $this->getId());
537
		}
538
		if (method_exists($this->getUITypeModel(), 'getReferenceList')) {
539
			$list = $this->getUITypeModel()->getReferenceList();
540
		} else {
541
			if (10 === $this->getUIType()) {
542
				$query = (new \App\Db\Query())->select(['module' => 'relmodule'])
543
					->from('vtiger_fieldmodulerel')
544
					->innerJoin('vtiger_tab', 'vtiger_tab.name = vtiger_fieldmodulerel.relmodule')
545
					->where(['fieldid' => $this->getId()])
546
					->andWhere(['<>', 'vtiger_tab.presence', 1])
547
					->orderBy(['sequence' => SORT_ASC]);
548
			} else {
549
				$query = (new \App\Db\Query())->select(['module' => 'vtiger_ws_referencetype.type'])
550
					->from('vtiger_ws_referencetype')
551
					->innerJoin('vtiger_ws_fieldtype', 'vtiger_ws_referencetype.fieldtypeid = vtiger_ws_fieldtype.fieldtypeid')
552
					->innerJoin('vtiger_tab', 'vtiger_tab.name = vtiger_ws_referencetype.type')
553
					->where(['vtiger_ws_fieldtype.uitype' => $this->getUIType()])
554
					->andWhere(['<>', 'vtiger_tab.presence', 1]);
555
			}
556
			$list = [];
557
			foreach ($query->column() as $moduleName) {
558
				if (\App\Privilege::isPermitted($moduleName)) {
559
					$list[] = $moduleName;
560 16
				}
561
			}
562 16
		}
563 16
		\App\Cache::save('getReferenceList', $this->getId(), $list);
564
		return $list;
565
	}
566
567
	/**
568
	 * Function to check if the field is named field of the module.
569
	 *
570
	 * @return bool
571 17
	 */
572
	public function isNameField(): bool
573 17
	{
574 6
		$moduleModel = $this->getModule();
575
		return $moduleModel && !$this->isReferenceField() && !\in_array($this->getFieldDataType(), ['email', 'url', 'phone']) && \in_array($this->getName(), $moduleModel->getNameFields());
576 14
	}
577 14
578 14
	/**
579
	 * Function to get the UI Type model for the uitype of the current field.
580
	 *
581 14
	 * @return Vtiger_Base_UIType Vtiger_Base_UIType or UI Type specific model instance
582
	 */
583 14
	public function getUITypeModel(): Vtiger_Base_UIType
584
	{
585
		if (isset($this->uitypeModel)) {
586
			return $this->uitypeModel;
587
		}
588
		return $this->uitypeModel = Vtiger_Base_UIType::getInstanceFromField($this);
589
	}
590
591 11
	public function isRoleBased()
592
	{
593 11
		return 15 === $this->get('uitype') || 33 === $this->get('uitype');
594 3
	}
595
596 11
	/**
597
	 * Function to get all the available picklist values for the current field.
598
	 *
599
	 * @param bool $skipCheckingRole
600
	 *
601
	 * @return <Array> List of picklist values if the field is of type picklist or multipicklist, null otherwise
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...
602
	 */
603
	public function getPicklistValues($skipCheckingRole = false)
604 6
	{
605
		if (isset($this->picklistValues)) {
606
			return $this->picklistValues;
607 6
		}
608 6
		$fieldDataType = $this->getFieldDataType();
609
		$fieldPickListValues = [];
610 4
		if ('picklist' === $fieldDataType || 'multipicklist' === $fieldDataType) {
611
			if ($this->isRoleBased() && !$skipCheckingRole) {
612 6
				$picklistValues = \App\Fields\Picklist::getRoleBasedValues($this->getName(), \App\User::getCurrentUserModel()->getRole());
613
			} else {
614
				$picklistValues = App\Fields\Picklist::getValuesName($this->getName());
615
			}
616
			foreach ($picklistValues as $value) {
617
				$fieldPickListValues[$value] = \App\Language::translate($value, $this->getModuleName(), false, false);
0 ignored issues
show
Bug introduced by
false of type false is incompatible with the type null|string expected by parameter $language of App\Language::translate(). ( Ignorable by Annotation )

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

617
				$fieldPickListValues[$value] = \App\Language::translate($value, $this->getModuleName(), /** @scrutinizer ignore-type */ false, false);
Loading history...
618
			}
619
			// Protection against deleting a value that does not exist on the list
620
			if ('picklist' === $fieldDataType) {
621
				$fieldValue = $this->get('fieldvalue');
622
				if (!empty($fieldValue) && !isset($fieldPickListValues[$fieldValue])) {
623
					$fieldPickListValues[$fieldValue] = \App\Language::translate($fieldValue, $this->getModuleName(), false, false);
624
					$this->set('isEditableReadOnly', true);
625
				}
626
			}
627
		} elseif (method_exists($this->getUITypeModel(), 'getPicklistValues')) {
628
			$fieldPickListValues = $this->getUITypeModel()->getPicklistValues();
629
		}
630
		return $fieldPickListValues;
631
	}
632
633
	/**
634
	 * Function to get all the available picklist values for the current field.
635
	 *
636
	 * @return <Array> List of picklist values if the field is of type picklist or multipicklist, null otherwise
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...
637
	 */
638
	public function getModulesListValues()
639
	{
640
		$allModules = \vtlib\Functions::getAllModules(true, false, 0);
641
		$modules = [];
642
		foreach ($allModules as $module) {
643
			$modules[$module['tabid']] = [
644
				'name' => $module['name'],
645
				'label' => App\Language::translate($module['name'], $module['name']),
646
			];
647
		}
648
		return $modules;
649
	}
650
651
	public static function showDisplayTypeList()
652
	{
653
		return [
654
			1 => 'LBL_DISPLAY_TYPE_1',
655
			2 => 'LBL_DISPLAY_TYPE_2',
656
			3 => 'LBL_DISPLAY_TYPE_3',
657
			4 => 'LBL_DISPLAY_TYPE_4',
658
			//5 => 'LBL_DISPLAY_TYPE_5',
659
			9 => 'LBL_DISPLAY_TYPE_9',
660
			10 => 'LBL_DISPLAY_TYPE_10',
661
			6 => 'LBL_DISPLAY_TYPE_6',
662
		];
663
	}
664
665
	/**
666
	 * Function to check if the current field is mandatory or not.
667
	 *
668
	 * @return bool
669
	 */
670
	public function isMandatory()
671
	{
672
		if ($this->get('isMandatory')) {
673
			return $this->get('isMandatory');
674
		}
675
		$typeOfData = explode('~', $this->get('typeofdata'));
676
		return isset($typeOfData[1]) && 'M' === $typeOfData[1];
677
	}
678
679
	/**
680
	 * Function to get the field type.
681
	 *
682
	 * @return string type of the field
683
	 */
684
	public function getFieldType()
685
	{
686
		if (isset($this->fieldType)) {
687
			return $this->fieldType;
688
		}
689
		$fieldTypeArray = explode('~', $this->get('typeofdata'));
690
		$fieldTypeArray = array_shift($fieldTypeArray);
691
		if ('reference' === $this->getFieldDataType()) {
692
			$fieldTypeArray = 'V';
693
		} else {
694 16
			$fieldTypeArray = \vtlib\Functions::transformFieldTypeOfData($this->get('table'), $this->get('column'), $fieldTypeArray);
695
		}
696 16
		return $this->fieldType = $fieldTypeArray;
697 16
	}
698 16
699
	/**
700
	 * Function to check if the field is shown in detail view.
701 16
	 *
702
	 * @return bool
703
	 */
704
	public function isViewEnabled()
705
	{
706
		if (4 === $this->getDisplayType() || 6 === $this->getDisplayType() || 1 === $this->get('presence') || 3 === $this->get('presence')) {
707
			return false;
708
		}
709
		return $this->getPermissions();
710
	}
711
712
	/**
713
	 * Function to check if the field is shown in detail view.
714
	 *
715
	 * @return bool
716
	 */
717
	public function isViewable()
718
	{
719 6
		$return = true;
720
		if (isset($this->permissionsCache['isViewable'])) {
721 6
			return $this->permissionsCache['isViewable'];
722
		}
723
		if (
724 6
			!$this->isViewEnabled() || !$this->isActiveReference()
725
			|| ((306 === $this->get('uitype') || 307 === $this->get('uitype') || 311 === $this->get('uitype') || 312 === $this->get('uitype')) && 2 === $this->getDisplayType())
726
		) {
727
			$return = false;
728
		}
729
		return $this->permissionsCache['isViewable'] = $return;
730
	}
731
732
	/**
733
	 * Function to check if the field is exportable.
734
	 *
735
	 * @return bool
736
	 */
737
	public function isExportable(): bool
738
	{
739
		return $this->isViewable();
740
	}
741
742 48
	/**
743
	 * Function to check if the field is shown in detail view.
744 48
	 *
745 48
	 * @return bool
746 48
	 */
747 48
	public function isViewableInDetailView()
748 48
	{
749
		if (!$this->isViewable() || 3 === $this->getDisplayType() || 5 === $this->getDisplayType()) {
750 48
			return false;
751
		}
752
		return true;
753
	}
754
755
	/**
756
	 * Function to check whether the current field is writable.
757
	 *
758
	 * @return bool
759
	 */
760
	public function isWritable()
761
	{
762
		$return = true;
763
		if (isset($this->permissionsCache['isWritable'])) {
764
			return $this->permissionsCache['isWritable'];
765
		}
766
		$displayType = $this->get('displaytype');
767
		if (!$this->isViewEnabled() || 4 === $displayType || 5 === $displayType
768
			|| 0 === strcasecmp($this->getFieldDataType(), 'autogenerated')
769
			|| 0 === strcasecmp($this->getFieldDataType(), 'id')
770
			|| true === $this->isReadOnly()
771
			|| !$this->getUITypeModel()->isWritable()) {
772
			$return = false;
773
		}
774
		return $this->permissionsCache['isWritable'] = $return;
775
	}
776
777
	/**
778
	 * Function to check whether the current field is editable.
779
	 *
780
	 * @return bool
781
	 */
782
	public function isEditable(): bool
783
	{
784
		$return = true;
785
		if (isset($this->permissionsCache['isEditable'])) {
786
			return $this->permissionsCache['isEditable'];
787
		}
788
		$displayType = $this->get('displaytype');
789
		if (!$this->isWritable() || (1 !== $displayType && 10 !== $displayType) || true === $this->isReadOnly()) {
790
			$return = false;
791
		}
792
		return $this->permissionsCache['isEditable'] = $return;
793
	}
794
795
	/**
796
	 * Function to check whether field is ajax editable.
797
	 *
798
	 * @return bool
799
	 */
800
	public function isAjaxEditable()
801
	{
802
		$ajaxRestrictedFields = [72, 12, 101];
803
		return !(10 === (int) $this->get('displaytype') || $this->isReferenceField() || !$this->getUITypeModel()->isAjaxEditable() || !$this->isEditable() || \in_array($this->get('uitype'), $ajaxRestrictedFields));
804
	}
805
806
	public function isEditableReadOnly()
807
	{
808
		if (null !== $this->get('isEditableReadOnly')) {
809
			return $this->get('isEditableReadOnly');
810
		}
811
		if (10 === (int) $this->get('displaytype')) {
812
			return true;
813
		}
814
		return false;
815
	}
816
817
	/**
818
	 * Function to check whether the current field is read-only.
819
	 *
820
	 * @return bool
821
	 */
822
	public function isReadOnly(): bool
823
	{
824
		if (isset($this->isReadOnly)) {
825
			return $this->isReadOnly;
826
		}
827
		return $this->isReadOnly = !$this->getProfileReadWritePermission();
0 ignored issues
show
Bug Best Practice introduced by
The property isReadOnly does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
828
	}
829
830 16
	public function isQuickCreateEnabled()
831
	{
832 16
		$moduleModel = $this->getModule();
833 16
		$quickCreate = $this->get('quickcreate');
834 16
		if ((self::QUICKCREATE_MANDATORY == $quickCreate || self::QUICKCREATE_ENABLED == $quickCreate || $this->isMandatory()) && method_exists($moduleModel, 'isQuickCreateSupported') && $moduleModel->isQuickCreateSupported()) {
835 16
			return true;
836 16
		}
837 16
		return false;
838 16
	}
839 16
840 16
	/**
841 16
	 * Function to check whether summary field or not.
842 16
	 *
843 16
	 * @return bool true/false
844 16
	 */
845 16
	public function isSummaryField()
846
	{
847 16
		return ($this->get('summaryfield')) ? true : false;
848 16
	}
849 16
850 16
	/**
851 16
	 * Function to check whether the current reference field is active.
852 16
	 *
853 16
	 * @return bool
854 16
	 */
855 16
	public function isActiveReference()
856 16
	{
857 16
		if ('reference' === $this->getFieldDataType() && empty($this->getReferenceList())) {
858
			return false;
859
		}
860
		return true;
861
	}
862
863
	/**
864
	 * If the field is sortable in ListView.
865 16
	 */
866 16
	public function isListviewSortable()
867
	{
868
		return !$this->get('fromOutsideList') && $this->getUITypeModel()->isListviewSortable();
869 16
	}
870
871
	/**
872 16
	 * Static Function to get the instance fo Vtiger Field Model from a given vtlib\Field object.
873
	 *
874
	 * @param vtlib\Field $fieldObj - vtlib field object
875
	 *
876
	 * @return Vtiger_Field_Model instance
877 16
	 */
878 16
	public static function getInstanceFromFieldObject(vtlib\Field $fieldObj)
879 16
	{
880
		$objectProperties = get_object_vars($fieldObj);
881
		$className = Vtiger_Loader::getComponentClassName('Model', 'Field', $fieldObj->getModuleName());
882
		$fieldModel = new $className();
883
		foreach ($objectProperties as $properName => $propertyValue) {
884
			$fieldModel->{$properName} = $propertyValue;
885
		}
886
		return $fieldModel;
887
	}
888
889
	/**
890
	 * Function to get the custom view column name transformation of the field for a date field used in date filters.
891
	 *
892
	 * @return string - tablename:columnname:fieldname:module_fieldlabel
893
	 */
894
	public function getCVDateFilterColumnName()
895
	{
896 16
		$moduleName = $this->getModuleName();
897
		$tableName = $this->get('table');
898
		$columnName = $this->get('column');
899
		$fieldName = $this->get('name');
900
		$fieldLabel = $this->get('label');
901
902 16
		$escapedFieldLabel = str_replace(' ', '_', $fieldLabel);
903 16
		$moduleFieldLabel = $moduleName . '_' . $escapedFieldLabel;
904
905
		return $tableName . ':' . $columnName . ':' . $fieldName . ':' . $moduleFieldLabel;
906 16
	}
907
908
	/**
909
	 * Function to get value for customview.
910
	 *
911
	 * @param string $sourceFieldName
912
	 *
913
	 * @throws \Exception
914
	 *
915
	 * @return string
916
	 */
917
	public function getCustomViewSelectColumnName(string $sourceFieldName = '')
918
	{
919
		return "{$this->get('name')}:{$this->getModuleName()}" . ($sourceFieldName ? ":{$sourceFieldName}" : '');
920 16
	}
921 6
922 6
	/**
923 6
	 * Function to get the custom view column name transformation of the field.
924 6
	 *
925 10
	 * @return string - tablename:columnname:fieldname:module_fieldlabel:fieldtype
926 10
	 */
927 10
	public function getCustomViewColumnName()
928 10
	{
929 10
		$moduleName = $this->getModuleName();
930
		$tableName = $this->get('table');
931
		$columnName = $this->get('column');
932
		$fieldName = $this->get('name');
933 16
		$fieldLabel = $this->get('label');
934
		$typeOfData = $this->get('typeofdata');
935
		$fieldTypeOfData = explode('~', $typeOfData);
936
		$fieldTypeOfData = $fieldTypeOfData[0];
937
		//Special condition need for reference field as they should be treated as string field
938
		if ('reference' === $this->getFieldDataType()) {
939
			$fieldTypeOfData = 'V';
940
		} else {
941
			$fieldTypeOfData = \vtlib\Functions::transformFieldTypeOfData($tableName, $columnName, $fieldTypeOfData);
942
		}
943
		$escapedFieldLabel = str_replace(' ', '_', $fieldLabel);
944
		$moduleFieldLabel = "{$moduleName}_{$escapedFieldLabel}";
945
946
		return "$tableName:$columnName:$fieldName:$moduleFieldLabel:$fieldTypeOfData";
947
	}
948
949
	/**
950
	 * This is set from Workflow Record Structure, since workflow expects the field name
951
	 * in a different format in its filter. Eg: for module field its fieldname and for reference
952
	 * fields its reference_field_name : (reference_module_name) field - salesorder_id: (SalesOrder) subject.
953
	 *
954
	 * @return string
955
	 */
956
	public function getWorkFlowFilterColumnName()
957
	{
958
		return $this->get('workflow_columnname');
959
	}
960
961
	/**
962
	 * Function to get the field details.
963
	 *
964
	 * @return array - array of field values
965
	 */
966
	public function getFieldInfo(): array
967
	{
968 25
		return $this->getUITypeModel()->getFieldInfo();
969
	}
970 25
971 5
	/**
972
	 * Load field info.
973 23
	 *
974 23
	 * @return array
975 23
	 */
976 23
	public function loadFieldInfo(): array
977
	{
978
		if (null !== $this->fieldInfo) {
979 23
			return $this->fieldInfo;
980 23
		}
981 23
		$this->fieldInfo['name'] = $this->get('name');
982 23
		$this->fieldInfo['label'] = App\Language::translate($this->get('label'), $this->getModuleName(), false, false);
0 ignored issues
show
Bug introduced by
false of type false is incompatible with the type null|string expected by parameter $language of App\Language::translate(). ( Ignorable by Annotation )

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

982
		$this->fieldInfo['label'] = App\Language::translate($this->get('label'), $this->getModuleName(), /** @scrutinizer ignore-type */ false, false);
Loading history...
983 23
		$fieldDataType = $this->getFieldDataType();
984 23
		$this->fieldInfo['type'] = $fieldDataType;
985
		$this->fieldInfo['mandatory'] = $this->isMandatory();
986 23
		$this->fieldInfo['defaultvalue'] = $this->getDefaultFieldValue();
987 23
		$this->fieldInfo['presence'] = $this->isActiveField();
988
		$this->fieldInfo['quickcreate'] = $this->isQuickCreateEnabled();
989
		$this->fieldInfo['masseditable'] = $this->isMassEditable();
990
		$this->fieldInfo['header_field'] = $this->getHeaderField();
991
		$this->fieldInfo['maxlengthtext'] = $this->get('maxlengthtext');
992
		$this->fieldInfo['maximumlength'] = $this->get('maximumlength');
993
		$this->fieldInfo['maxwidthcolumn'] = $this->get('maxwidthcolumn');
994
		$this->fieldInfo['tabindex'] = $this->get('tabindex');
995
		$this->fieldInfo['fieldtype'] = explode('~', $this->get('typeofdata'))[0] ?? '';
996
		$currentUser = \App\User::getCurrentUserModel();
997
		switch ($fieldDataType) {
998 28
			case 'picklist':
999
			case 'multipicklist':
1000 28
			case 'multiowner':
1001 28
			case 'multiReferenceValue':
1002 7
			case 'inventoryLimit':
1003
			case 'languages':
1004 28
			case 'currencyList':
1005 21
			case 'fileLocationType':
1006 21
			case 'taxes':
1007
			case 'multiListFields':
1008
			case 'mailScannerFields':
1009
			case 'country':
1010
				$this->fieldInfo['picklistvalues'] = $this->getPicklistValues() ?: [];
1011 28
				break;
1012 28
			case 'date':
1013
			case 'datetime':
1014
				$this->fieldInfo['date-format'] = $currentUser->getDetail('date_format');
1015
				break;
1016
			case 'time':
1017
				$this->fieldInfo['time-format'] = $currentUser->getDetail('hour_format');
1018
				break;
1019
			case 'currency':
1020
				$this->fieldInfo['currency_symbol'] = $currentUser->getDetail('currency_symbol');
1021
				$this->fieldInfo['decimal_separator'] = $currentUser->getDetail('currency_decimal_separator');
1022
				$this->fieldInfo['group_separator'] = $currentUser->getDetail('currency_grouping_separator');
1023
				break;
1024
			case 'owner':
1025
			case 'userCreator':
1026
			case 'sharedOwner':
1027
				if (!App\Config::performance('SEARCH_OWNERS_BY_AJAX') || \in_array(\App\Request::_get('module'), ['CustomView', 'Workflows', 'PDF', 'MappedFields']) || 'showAdvancedSearch' === \App\Request::_get('mode')) {
0 ignored issues
show
Bug introduced by
The method _get() does not exist on App\Request. Since you implemented __callStatic, consider adding a @method annotation. ( Ignorable by Annotation )

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

1027
				if (!App\Config::performance('SEARCH_OWNERS_BY_AJAX') || \in_array(\App\Request::/** @scrutinizer ignore-call */ _get('module'), ['CustomView', 'Workflows', 'PDF', 'MappedFields']) || 'showAdvancedSearch' === \App\Request::_get('mode')) {
Loading history...
1028
					$userList = \App\Fields\Owner::getInstance($this->getModuleName(), $currentUser)->getAccessibleUsers('', $fieldDataType);
1029
					$groupList = \App\Fields\Owner::getInstance($this->getModuleName(), $currentUser)->getAccessibleGroups('', $fieldDataType);
1030
					$pickListValues = [];
1031
					$pickListValues[\App\Language::translate('LBL_USERS', $this->getModuleName())] = $userList;
1032
					$pickListValues[\App\Language::translate('LBL_GROUPS', $this->getModuleName())] = $groupList;
1033
					$this->fieldInfo['picklistvalues'] = $pickListValues;
1034
					if (App\Config::performance('SEARCH_OWNERS_BY_AJAX')) {
1035
						$this->fieldInfo['searchOperator'] = 'e';
1036
					}
1037
				} else {
1038
					if ('owner' === $fieldDataType) {
1039
						$this->fieldInfo['searchOperator'] = 'e';
1040
					}
1041
				}
1042
				break;
1043
			case 'modules':
1044
				foreach ($this->getModulesListValues() as $module) {
1045
					$modulesList[$module['name']] = $module['label'];
1046
				}
1047
				$this->fieldInfo['picklistvalues'] = $modulesList;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $modulesList seems to be defined by a foreach iteration on line 1044. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
1048
				break;
1049
			case 'categoryMultipicklist':
1050
			case 'tree':
1051
				$this->fieldInfo['picklistvalues'] = \App\Fields\Tree::getPicklistValue($this->getFieldParams(), $this->getModuleName());
0 ignored issues
show
Bug introduced by
$this->getFieldParams() of type array is incompatible with the type integer expected by parameter $templateId of App\Fields\Tree::getPicklistValue(). ( Ignorable by Annotation )

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

1051
				$this->fieldInfo['picklistvalues'] = \App\Fields\Tree::getPicklistValue(/** @scrutinizer ignore-type */ $this->getFieldParams(), $this->getModuleName());
Loading history...
1052
				$this->fieldInfo['treetemplate'] = $this->getFieldParams();
1053
				$this->fieldInfo['modulename'] = $this->getModuleName();
1054
				break;
1055
			case 'email':
1056
				if (\App\Config::security('EMAIL_FIELD_RESTRICTED_DOMAINS_ACTIVE') && !empty(\App\Config::security('EMAIL_FIELD_RESTRICTED_DOMAINS_VALUES'))) {
1057
					$validate = false;
1058
					if (empty(\App\Config::security('EMAIL_FIELD_RESTRICTED_DOMAINS_ALLOWED')) || \in_array($this->getModuleName(), \App\Config::security('EMAIL_FIELD_RESTRICTED_DOMAINS_ALLOWED'))) {
1059
						$validate = true;
1060
					}
1061
					if (\in_array($this->getModuleName(), \App\Config::security('EMAIL_FIELD_RESTRICTED_DOMAINS_EXCLUDED'))) {
1062
						$validate = false;
1063
					}
1064
					if ($validate) {
1065
						$this->fieldInfo['restrictedDomains'] = \App\Config::security('EMAIL_FIELD_RESTRICTED_DOMAINS_VALUES');
1066
					}
1067
				}
1068
				break;
1069
			default:
1070
				break;
1071
		}
1072
1073
		return $this->fieldInfo;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->fieldInfo returns the type void which is incompatible with the type-hinted return array.
Loading history...
1074
	}
1075
1076
	/**
1077
	 * Set field info.
1078
	 *
1079
	 * @param array $fieldInfo
1080
	 *
1081
	 * @return $this
1082
	 */
1083
	public function setFieldInfo(array $fieldInfo)
1084
	{
1085
		$this->fieldInfo = $fieldInfo;
1086
1087
		return $this;
1088
	}
1089
1090
	/**
1091
	 * Function to get the advanced filter option names by Field type.
1092
	 *
1093
	 * @return <Array>
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...
1094
	 */
1095
	public static function getAdvancedFilterOpsByFieldType()
1096
	{
1097
		return [
1098
			'V' => ['e', 'n', 's', 'ew', 'c', 'k', 'y', 'ny', 'om', 'wr', 'nwr'],
1099
			'N' => ['e', 'n', 'l', 'g', 'm', 'h', 'y', 'ny'],
1100
			'T' => ['e', 'n', 'l', 'g', 'm', 'h', 'bw', 'b', 'a', 'y', 'ny'],
1101
			'I' => ['e', 'n', 'l', 'g', 'm', 'h', 'y', 'ny'],
1102
			'C' => ['e', 'n', 'y', 'ny'],
1103
			'D' => ['e', 'n', 'bw', 'b', 'a', 'y', 'ny'],
1104
			'DT' => ['e', 'n', 'bw', 'b', 'a', 'y', 'ny'],
1105
			'NN' => ['e', 'n', 'l', 'g', 'm', 'h', 'y', 'ny'],
1106
			'E' => ['e', 'n', 's', 'ew', 'c', 'k', 'y', 'ny'],
1107
		];
1108
	}
1109
1110
	/**
1111
	 * Function to retrieve field model for specific block and module.
1112
	 *
1113
	 * @param vtlib\ModuleBasic $moduleModel
1114
	 *
1115
	 * @return Vtiger_Field_Model[][]
1116
	 */
1117
	public static function getAllForModule(vtlib\ModuleBasic $moduleModel)
1118
	{
1119
		if (\App\Cache::staticHas('ModuleFields', $moduleModel->id)) {
0 ignored issues
show
Bug introduced by
$moduleModel->id of type boolean is incompatible with the type string expected by parameter $key of App\Cache::staticHas(). ( Ignorable by Annotation )

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

1119
		if (\App\Cache::staticHas('ModuleFields', /** @scrutinizer ignore-type */ $moduleModel->id)) {
Loading history...
1120
			return \App\Cache::staticGet('ModuleFields', $moduleModel->id);
0 ignored issues
show
Bug introduced by
$moduleModel->id of type boolean is incompatible with the type string expected by parameter $key of App\Cache::staticGet(). ( Ignorable by Annotation )

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

1120
			return \App\Cache::staticGet('ModuleFields', /** @scrutinizer ignore-type */ $moduleModel->id);
Loading history...
1121
		}
1122
		$fieldModelList = [];
0 ignored issues
show
Unused Code introduced by
The assignment to $fieldModelList is dead and can be removed.
Loading history...
1123
		$fieldObjects = parent::getAllForModule($moduleModel);
1124
		$fieldModelList = [];
1125
		if (!\is_array($fieldObjects)) {
0 ignored issues
show
introduced by
The condition is_array($fieldObjects) is always false.
Loading history...
1126
			$fieldObjects = [];
1127
		}
1128
		foreach ($fieldObjects as &$fieldObject) {
1129
			$fieldModel = self::getInstanceFromFieldObject($fieldObject);
1130
			$block = $fieldModel->get('block') ? $fieldModel->get('block')->id : 0;
1131
			$fieldModelList[$block][] = $fieldModel;
1132
			self::$instanceCacheById[$fieldModel->getId()] = $fieldModel;
1133
			self::$instanceCacheByName[$moduleModel->getId()][$fieldModel->getName()] = $fieldModel;
1134
		}
1135
		\App\Cache::staticSave('ModuleFields', $moduleModel->id, $fieldModelList);
0 ignored issues
show
Bug introduced by
$moduleModel->id of type boolean is incompatible with the type string expected by parameter $key of App\Cache::staticSave(). ( Ignorable by Annotation )

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

1135
		\App\Cache::staticSave('ModuleFields', /** @scrutinizer ignore-type */ $moduleModel->id, $fieldModelList);
Loading history...
1136
		return $fieldModelList;
1137
	}
1138
1139
	/**
1140
	 * Function to get new field model instance, the function creates a new object and does not pass a reference.
1141
	 *
1142
	 * @param string|int                $value  fieldname or field id
1143
	 * @param Vtiger_Module_Model|false $module optional - module instance
1144
	 *
1145
	 * @return Vtiger_Field_Model|false
1146
	 */
1147
	public static function getInstance($value, $module = false)
1148
	{
1149
		if (\is_numeric($value)) {
1150
			if (isset(self::$instanceCacheById[$value])) {
1151
				return clone self::$instanceCacheById[$value];
1152
			}
1153
		} elseif ($module) {
1154
			if (isset(self::$instanceCacheByName[$module->getId()][$value])) {
1155
				return clone self::$instanceCacheByName[$module->getId()][$value];
1156
			}
1157
		} else {
1158
			throw new \App\Exceptions\AppException("ERR_NOT_MODULE||$value||$module");
1159
		}
1160
		if ($fieldInstance = parent::getInstance($value, $module)) {
1161
			$fieldModel = self::getInstanceFromFieldObject($fieldInstance);
1162
			self::$instanceCacheById[$fieldModel->getId()] = $fieldModel;
1163
			self::$instanceCacheByName[$fieldModel->get('tabid')][$value] = $fieldModel;
1164
			return $fieldModel;
1165
		}
1166
		return false;
1167
	}
1168
1169
	/**
1170
	 * Returns instance of field.
1171
	 *
1172
	 * @param array|string $fieldInfo
1173
	 *
1174
	 * @return bool|\Vtiger_Field_Model|\vtlib\Field|null
1175
	 */
1176
	public static function getInstanceFromFilter($fieldInfo)
1177
	{
1178
		if (\is_string($fieldInfo)) {
1179
			$fieldInfo = array_combine(['field_name', 'module_name', 'source_field_name'], array_pad(explode(':', $fieldInfo), 3, false));
1180
		}
1181
		return static::getInstance($fieldInfo['field_name'], Vtiger_Module_Model::getInstance($fieldInfo['module_name']));
1182
	}
1183
1184
	/**
1185
	 * Function checks if the current Field is Read/Write.
1186
	 *
1187
	 * @return bool
1188
	 */
1189
	public function getProfileReadWritePermission()
1190
	{
1191
		return $this->getPermissions(false);
1192
	}
1193
1194
	/**
1195
	 * Gets default validator.
1196
	 *
1197
	 * @return array
1198
	 */
1199
	public function getDefaultValidator(): array
1200
	{
1201 29
		$validator = [];
1202
		$fieldName = $this->getName();
1203 29
		switch ($fieldName) {
1204
			case 'birthday':
1205
				$funcName = ['name' => 'lessThanToday'];
1206
				$validator[] = $funcName;
1207
				break;
1208
			case 'targetenddate':
1209
			case 'actualenddate':
1210
			case 'enddate':
1211
				$funcName = ['name' => 'greaterThanDependentField',
1212
					'params' => ['startdate'], ];
1213
				$validator[] = $funcName;
1214
				break;
1215
			case 'startdate':
1216
				if ('Project' === $this->getModule()->get('name')) {
1217
					$params = ['targetenddate'];
1218
				} else {
1219
					//for project task
1220
					$params = ['enddate'];
1221
				}
1222
				$funcName = ['name' => 'lessThanDependentField',
1223
					'params' => $params, ];
1224
				$validator[] = $funcName;
1225
				break;
1226 11
			case 'expiry_date':
1227
			case 'due_date':
1228 11
				$funcName = ['name' => 'greaterThanDependentField',
1229
					'params' => ['start_date'], ];
1230
				$validator[] = $funcName;
1231
				break;
1232
			case 'sales_end_date':
1233
				$funcName = ['name' => 'greaterThanDependentField',
1234
					'params' => ['sales_start_date'], ];
1235
				$validator[] = $funcName;
1236
				break;
1237
			case 'sales_start_date':
1238
				$funcName = ['name' => 'lessThanDependentField',
1239
					'params' => ['sales_end_date'], ];
1240
				$validator[] = $funcName;
1241
				break;
1242
			case 'qty_per_unit':
1243
			case 'qtyindemand':
1244
			case 'hours':
1245
			case 'days':
1246
				$funcName = ['name' => 'PositiveNumber'];
1247
				$validator[] = $funcName;
1248
				break;
1249
			case 'employees':
1250
				$funcName = ['name' => 'WholeNumber'];
1251
				$validator[] = $funcName;
1252
				break;
1253
			case 'related_to':
1254
				$funcName = ['name' => 'ReferenceField'];
1255
				$validator[] = $funcName;
1256
				break;
1257
			//SRecurringOrders field sepecial validators
1258
			case 'end_period':
1259
				$funcName1 = ['name' => 'greaterThanDependentField',
1260
					'params' => ['start_period'], ];
1261
				$validator[] = $funcName1;
1262 21
				$funcName2 = ['name' => 'lessThanDependentField',
1263
					'params' => ['duedate'], ];
1264 21
				$validator[] = $funcName2;
1265
1266
			// no break
1267
			case 'start_period':
1268
				$funcName = ['name' => 'lessThanDependentField',
1269
					'params' => ['end_period'], ];
1270
				$validator[] = $funcName;
1271
				break;
1272 18
			default:
1273
				break;
1274 18
		}
1275
		return $validator;
1276 18
	}
1277
1278
	/**
1279 16
	 * Function returns Client Side Validators name.
1280
	 *
1281 16
	 * @return array [name=>Name of the Validator, params=>Extra Parameters]
1282
	 */
1283
	public function getValidator()
1284
	{
1285
		return method_exists($this->getUITypeModel(), 'getValidator') ? $this->getUITypeModel()->getValidator() : $this->getDefaultValidator();
1286
	}
1287
1288
	/**
1289
	 * Function to retrieve display value in edit view.
1290
	 *
1291
	 * @param mixed               $value
1292
	 * @param Vtiger_Record_Model $recordModel
1293
	 *
1294
	 * @return mixed
1295
	 */
1296 16
	public function getEditViewDisplayValue($value, $recordModel = false)
1297
	{
1298 16
		return $this->getUITypeModel()->getEditViewDisplayValue($value, $recordModel);
1299
	}
1300
1301
	/**
1302
	 * Function to retrieve user value in edit view.
1303
	 *
1304
	 * @param mixed               $value
1305
	 * @param Vtiger_Record_Model $recordModel
1306
	 *
1307
	 * @return mixed
1308
	 */
1309
	public function getEditViewValue($value, $recordModel = false)
1310
	{
1311
		return $this->getUITypeModel()->getEditViewValue($value, $recordModel);
1312
	}
1313
1314
	/**
1315
	 * Function to get Display value for RelatedList.
1316
	 *
1317
	 * @param string $value
1318
	 *
1319
	 * @return string
1320
	 */
1321
	public function getRelatedListDisplayValue($value)
1322
	{
1323
		return $this->getUITypeModel()->getRelatedListDisplayValue($value);
1324
	}
1325
1326
	/**
1327
	 * Function to get Default Field Value.
1328
	 *
1329
	 * @throws \Exception
1330
	 *
1331
	 * @return mixed
1332
	 */
1333
	public function getDefaultFieldValue()
1334
	{
1335
		return $this->getUITypeModel()->getDefaultValue();
1336
	}
1337
1338 10
	/**
1339
	 * Function whcih will get the databse insert value format from user format.
1340 10
	 *
1341
	 * @param type  $value       in user format
1342
	 * @param mixed $recordModel
1343
	 *
1344
	 * @return type
1345
	 */
1346
	public function getDBValue($value, $recordModel = false)
1347
	{
1348
		return $this->getUITypeModel()->getDBValue($value, $recordModel);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getUITypeM...e($value, $recordModel) returns the type string which is incompatible with the documented return type type.
Loading history...
1349
	}
1350
1351
	/**
1352
	 * Function to get visibilty permissions of a Field.
1353
	 *
1354
	 * @param bool $readOnly
1355
	 *
1356
	 * @return bool
1357
	 */
1358
	public function getPermissions($readOnly = true)
1359
	{
1360
		if (isset($this->permissions)) {
1361
			return $this->permissions;
1362
		}
1363
		return \App\Field::getFieldPermission($this->getModuleId(), $this->getName(), $readOnly);
1364
	}
1365
1366
	public function __update()
1367
	{
1368
		$dbCommand = \App\Db::getInstance()->createCommand();
1369
		1 === $this->get('generatedtype') ? $generatedType = 1 : $generatedType = 2;
1370
		$dbCommand->update('vtiger_field', ['typeofdata' => $this->get('typeofdata'), 'presence' => $this->get('presence'), 'quickcreate' => $this->get('quickcreate'),
1371
			'masseditable' => $this->get('masseditable'), 'header_field' => $this->get('header_field'), 'maxlengthtext' => $this->get('maxlengthtext'),
1372
			'maxwidthcolumn' => $this->get('maxwidthcolumn'), 'tabindex' => $this->get('tabindex'), 'defaultvalue' => $this->get('defaultvalue'), 'summaryfield' => $this->get('summaryfield'),
1373
			'displaytype' => $this->get('displaytype'), 'helpinfo' => $this->get('helpinfo'), 'generatedtype' => $generatedType,
1374
			'fieldparams' => $this->get('fieldparams'), 'quickcreatesequence' => $this->get('quicksequence'), 'icon' => $this->get('icon'), 'fieldlabel' => $this->get('label'),
1375
		], ['fieldid' => $this->get('id')])->execute();
1376
		if ($anonymizationTarget = $this->get('anonymizationTarget')) {
1377
			$anonymizationTarget = \App\Json::encode($anonymizationTarget);
1378
			$execute = $dbCommand->update('s_#__fields_anonymization', ['anonymization_target' => $anonymizationTarget], ['field_id' => $this->getId()])->execute();
1379
			if (!$execute) {
1380
				$dbCommand->insert('s_#__fields_anonymization', ['field_id' => $this->getId(), 'anonymization_target' => $anonymizationTarget])->execute();
1381
			}
1382
		} else {
1383
			$dbCommand->delete('s_#__fields_anonymization', ['field_id' => $this->getId()])->execute();
1384
		}
1385
		App\Cache::clear();
1386
	}
1387
1388
	/**
1389
	 * Change the mandatory field.
1390
	 *
1391
	 * @param string $mandatoryValue
1392
	 *
1393
	 * @return $this
1394
	 */
1395
	public function updateTypeofDataFromMandatory($mandatoryValue = 'O')
1396 17
	{
1397
		$mandatoryValue = strtoupper($mandatoryValue);
1398 17
		$supportedMandatoryLiterals = ['O', 'M'];
1399 17
		if (!\in_array($mandatoryValue, $supportedMandatoryLiterals)) {
1400 17
			return $this;
1401 17
		}
1402 16
		$typeOfData = $this->get('typeofdata');
1403
		$components = explode('~', $typeOfData);
1404
		$components[1] = $mandatoryValue;
1405 1
		$this->set('typeofdata', implode('~', $components));
1406
1407
		return $this;
1408
	}
1409
1410
	public function isCustomField()
1411
	{
1412
		return 2 == $this->generatedtype;
1413
	}
1414
1415
	public function hasDefaultValue()
1416
	{
1417
		return !empty($this->defaultvalue);
1418
	}
1419
1420
	public function isActiveField()
1421
	{
1422
		return \in_array($this->get('presence'), [0, 2]);
1423 19
	}
1424
1425 19
	public function isMassEditable()
1426 19
	{
1427 19
		return 1 == $this->masseditable;
1428
	}
1429
1430 19
	public function isHeaderField()
1431 19
	{
1432 19
		return !empty($this->header_field);
1433
	}
1434
1435
	/**
1436
	 * Gets header field data.
1437
	 *
1438
	 * @throws \App\Exceptions\AppException
1439
	 *
1440
	 * @return mixed
1441
	 */
1442
	public function getHeaderField()
1443 19
	{
1444
		return !empty($this->header_field) ? \App\Json::decode($this->header_field) : [];
1445
	}
1446
1447
	/**
1448
	 * Gets header field value.
1449
	 *
1450
	 * @param string $type
1451
	 * @param mixed  $default
1452
	 *
1453 21
	 * @throws \App\Exceptions\AppException
1454
	 *
1455 21
	 * @return mixed
1456 21
	 */
1457
	public function getHeaderValue(string $type, $default = '')
1458
	{
1459 21
		return $this->getHeaderField()[$type] ?? $default;
1460 21
	}
1461 2
1462
	/**
1463 19
	 * Function which will check if empty piclist option should be given.
1464 19
	 *
1465
	 * @return bool
1466
	 */
1467 19
	public function isEmptyPicklistOptionAllowed()
1468 19
	{
1469 19
		if (method_exists($this->getUITypeModel(), 'isEmptyPicklistOptionAllowed')) {
1470 8
			return $this->getUITypeModel()->isEmptyPicklistOptionAllowed();
1471 11
		}
1472 2
		return true;
1473 1
	}
1474
1475 1
	/**
1476 9
	 * Check if it is a tree field.
1477
	 *
1478
	 * @return bool
1479
	 */
1480
	public function isTreeField(): bool
1481 9
	{
1482 2
		return \in_array($this->getFieldDataType(), ['tree', 'categoryMultipicklist']);
1483
	}
1484
1485 2
	public function isReferenceField()
1486 7
	{
1487 3
		return \in_array($this->getFieldDataType(), self::$referenceTypes);
1488 4
	}
1489 4
1490
	public function isOwnerField()
1491
	{
1492
		return self::OWNER_TYPE == $this->getFieldDataType();
1493
	}
1494
1495
	/**
1496
	 * Function determines whether the field value can be duplicated.
1497
	 *
1498
	 * @return bool
1499
	 */
1500
	public function isDuplicable(): bool
1501
	{
1502
		return $this->getUITypeModel()->isDuplicable();
1503
	}
1504
1505
	/**
1506
	 * Is summation field.
1507
	 *
1508
	 * @return bool
1509
	 */
1510
	public function isCalculateField()
1511
	{
1512
		return $this->isCalculateField && !$this->get('fromOutsideList') && (\in_array($this->getUIType(), [71, 7, 317, 8]) || \in_array($this->getFieldDataType(), ['integer', 'double']));
1513
	}
1514
1515
	/**
1516
	 * Function returns field instance for field ID.
1517
	 *
1518
	 * @param int $fieldId
1519
	 * @param int $moduleTabId
1520
	 *
1521
	 * @return \Vtiger_Field_Model
1522
	 */
1523
	public static function getInstanceFromFieldId($fieldId, $moduleTabId = false)
1524
	{
1525
		if (isset(self::$instanceCacheById[$fieldId])) {
1526
			return self::$instanceCacheById[$fieldId];
1527
		}
1528
		$field = \App\Field::getFieldInfo($fieldId);
1529
		$className = Vtiger_Loader::getComponentClassName('Model', 'Field', \App\Module::getModuleName($field['tabid']));
1530
		$fieldModel = new $className();
1531
		$fieldModel->initialize($field, $field['tabid']);
1532
		self::$instanceCacheById[$fieldModel->getId()] = $fieldModel;
1533
		self::$instanceCacheByName[$fieldModel->get('tabid')][$fieldModel->getName()] = $fieldModel;
1534
		return $fieldModel;
1535
	}
1536
1537
	public function getWithDefaultValue()
1538
	{
1539
		$defaultValue = $this->getDefaultFieldValue();
1540
		$recordValue = $this->get('fieldvalue');
1541
		if (empty($recordValue) && !$defaultValue) {
1542
			$this->set('fieldvalue', $defaultValue);
1543
		}
1544
		return $this;
1545
	}
1546
1547
	/**
1548
	 * Get field params.
1549
	 *
1550
	 * @return array
1551
	 */
1552
	public function getFieldParams()
1553
	{
1554
		if (!\is_array($this->get('fieldparams')) && \App\Json::isJson($this->get('fieldparams'))) {
1555
			return \App\Json::decode($this->get('fieldparams'));
0 ignored issues
show
Bug Best Practice introduced by
The expression return App\Json::decode(...is->get('fieldparams')) also could return the type string which is incompatible with the documented return type array.
Loading history...
1556
		}
1557
		return $this->get('fieldparams') ?: [];
1558
	}
1559
1560
	/**
1561
	 * Get value of a specific parameter from the fieldparams field.
1562
	 *
1563
	 * @param string $key
1564
	 *
1565
	 * @return mixed
1566
	 */
1567
	public function getParam(string $key)
1568
	{
1569
		return $this->getFieldParams()[$key] ?? null;
1570
	}
1571
1572
	/**
1573
	 * Get field icon.
1574
	 *
1575
	 * @param string $place
1576
	 *
1577
	 * @return array
1578
	 */
1579
	public function getIcon(string $place = ''): array
1580
	{
1581
		$icon = [];
1582
		if (\is_array($this->get('icon'))) {
1583
			$icon = $this->get('icon');
1584
		} elseif ($this->get('icon') && \App\Json::isJson($this->get('icon'))) {
1585
			$icon = \App\Json::decode($this->get('icon'));
1586
		}
1587
		if ($place && isset($icon['place']) && !\in_array($place, $icon['place'])) {
1588
			$icon = [];
1589
		}
1590
		return $icon;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $icon could return the type null|string which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
1591
	}
1592
1593
	/**
1594
	 * Get anonymization target.
1595
	 *
1596
	 * @see \App\Anonymization::getTypes()
1597
	 *
1598
	 * @return int[]
1599
	 */
1600
	public function getAnonymizationTarget(): array
1601
	{
1602
		if (\is_string($this->get('anonymizationTarget'))) {
1603
			$this->set('anonymizationTarget', \App\Json::decode($this->get('anonymizationTarget')));
1604
		}
1605
		return $this->get('anonymizationTarget');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->get('anonymizationTarget') could return the type null which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
1606
	}
1607
1608
	/**
1609
	 * Get maximum value.
1610
	 *
1611
	 * @return int
1612
	 */
1613
	public function getMaxValue(): int
1614
	{
1615
		if (($maximumLength = $this->get('maximumlength')) && false !== strpos($maximumLength, ',')) {
1616
			return (int) explode(',', $maximumLength)[1];
1617
		}
1618
		if (empty($maximumLength)) {
1619
			$maximumLength = $this->getDbValueLength();
1620
		}
1621
1622
		return (int) $maximumLength;
1623
	}
1624
1625
	/**
1626
	 * Get length value form database.
1627
	 *
1628
	 * @return int
1629
	 */
1630
	public function getDbValueLength(): int
1631
	{
1632
		$db = \App\Db::getInstance();
1633
		$tableSchema = $db->getSchema()->getTableSchema($this->getTableName());
1634
		if (empty($tableSchema)) {
1635
			throw new \App\Exceptions\AppException('ERR_TABLE_DOES_NOT_EXISTS||' . $this->getTableName());
1636
		}
1637
		return $tableSchema->getColumn($this->getColumnName())->size ?: 0;
1638
	}
1639
1640
	public function isActiveSearchView()
1641
	{
1642
		if ($this->get('fromOutsideList') || $this->get('searchLockedFields')) {
1643
			return false;
1644
		}
1645
		return $this->getUITypeModel()->isActiveSearchView();
1646
	}
1647
1648
	/**
1649
	 * Empty value search in view.
1650
	 *
1651
	 * @return bool
1652
	 */
1653
	public function searchLockedEmptyFields(): bool
1654
	{
1655
		return empty($this->get('searchLockedEmptyFields'));
1656
	}
1657
1658
	/**
1659
	 * Function returns info about field structure in database.
1660
	 *
1661
	 * @param bool $returnString
1662
	 *
1663
	 * @return array|string
1664
	 */
1665
	public function getDBColumnType($returnString = true)
1666
	{
1667
		$db = \App\Db::getInstance();
1668
		$tableSchema = $db->getSchema()->getTableSchema($this->getTableName(), true);
1669
		if (empty($tableSchema)) {
1670
			return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type array|string.
Loading history...
1671
		}
1672
		$columnSchema = $tableSchema->getColumn($this->getColumnName());
1673
		$data = get_object_vars($columnSchema);
1674
		if ($returnString) {
1675
			$string = $data['type'];
1676
			if ($data['size']) {
1677
				if ('decimal' === $data['type']) {
1678
					$string .= '(' . $data['size'] . ',' . $data['scale'] . ')';
1679
				} else {
1680
					$string .= '(' . $data['size'] . ')';
1681
				}
1682
			}
1683
			return $string;
1684
		}
1685
		return $data;
1686
	}
1687
1688
	/**
1689
	 * Function to get range of values.
1690
	 *
1691
	 * @throws \App\Exceptions\AppException
1692
	 *
1693
	 * @return string|null
1694
	 */
1695
	public function getRangeValues()
1696
	{
1697
		$uiTypeModel = $this->getUITypeModel();
1698
		if (method_exists($uiTypeModel, 'getRangeValues')) {
1699
			return $uiTypeModel->getRangeValues();
1700
		}
1701
		$allowedTypes = $uiTypeModel->getAllowedColumnTypes();
1702
		if (null === $allowedTypes) {
0 ignored issues
show
introduced by
The condition null === $allowedTypes is always false.
Loading history...
1703
			return;
1704
		}
1705
		$data = $this->getDBColumnType(false);
1706
		if (!\in_array($data['type'], $allowedTypes)) {
1707
			throw new \App\Exceptions\AppException('ERR_NOT_ALLOWED_TYPE||' . $data['type'] . '||' . print_r($allowedTypes, true));
0 ignored issues
show
Bug introduced by
Are you sure print_r($allowedTypes, true) of type string|true can be used in concatenation? ( Ignorable by Annotation )

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

1707
			throw new \App\Exceptions\AppException('ERR_NOT_ALLOWED_TYPE||' . $data['type'] . '||' . /** @scrutinizer ignore-type */ print_r($allowedTypes, true));
Loading history...
1708
		}
1709
		preg_match('/^([\w\-]+)/i', $data['dbType'], $matches);
1710
		$type = $matches[1] ?? $data['type'];
1711
		$uitype = $this->getUIType();
1712
		if (isset(self::$uiTypeMaxLength[$uitype])) {
1713
			$range = self::$uiTypeMaxLength[$uitype];
1714
		} elseif (isset(self::$typesMaxLength[$type])) {
1715
			$range = self::$typesMaxLength[$type];
1716
		} else {
1717
			switch ($type) {
1718
				case 'binary':
1719
				case 'string':
1720
				case 'varchar':
1721
				case 'varbinary':
1722
					$range = (int) $data['size'];
1723
					break;
1724
				case 'bigint':
1725
				case 'mediumint':
1726
					throw new \App\Exceptions\AppException("ERR_NOT_ALLOWED_TYPE||$type||integer,smallint,tinyint");
1727
				case 'integer':
1728
				case 'int':
1729
					if ($data['unsigned']) {
1730
						$range = '4294967295';
1731
					} else {
1732
						$range = '-2147483648,2147483647';
1733
					}
1734
					break;
1735
				case 'smallint':
1736
					if ($data['unsigned']) {
1737
						$range = '65535';
1738
					} else {
1739
						$range = '-32768,32767';
1740
					}
1741
					break;
1742
				case 'tinyint':
1743
					if ($data['unsigned']) {
1744
						$range = '255';
1745
					} else {
1746
						$range = '-128,127';
1747
					}
1748
					break;
1749
				case 'decimal':
1750
					$range = 10 ** (((int) $data['size']) - ((int) $data['scale'])) - 1;
1751
					break;
1752
				default:
1753
					$range = null;
1754
					break;
1755
			}
1756
		}
1757
		return $range;
1758
	}
1759
1760
	/**
1761
	 * Return allowed query operators for field.
1762
	 *
1763
	 * @return string[]
1764
	 */
1765
	public function getQueryOperators(): array
1766
	{
1767
		$operators = $this->getUITypeModel()->getQueryOperators();
1768
		$oper = [];
1769
		foreach ($operators as $op) {
1770
			$label = '';
1771
			if (isset(\App\Condition::STANDARD_OPERATORS[$op])) {
1772
				$label = \App\Condition::STANDARD_OPERATORS[$op];
1773
			} elseif (isset(\App\Condition::DATE_OPERATORS[$op])) {
1774
				$label = \App\Condition::DATE_OPERATORS[$op]['label'];
1775
			}
1776
			$oper[$op] = $label;
1777
		}
1778
		return $oper;
1779
	}
1780
1781
	/**
1782
	 * Return allowed record operators for field.
1783
	 *
1784
	 * @return string[]
1785
	 */
1786
	public function getRecordOperators(): array
1787
	{
1788
		$operators = $this->getUITypeModel()->getRecordOperators();
1789
		$oper = [];
1790
		foreach ($operators as $op) {
1791
			$label = '';
1792
			if (isset(\App\Condition::STANDARD_OPERATORS[$op])) {
1793
				$label = \App\Condition::STANDARD_OPERATORS[$op];
1794
			} elseif (isset(\App\Condition::DATE_OPERATORS[$op])) {
1795
				$label = \App\Condition::DATE_OPERATORS[$op]['label'];
1796
			}
1797
			$oper[$op] = $label;
1798
		}
1799
		return $oper;
1800
	}
1801
1802
	/**
1803
	 * Returns template for operator.
1804
	 *
1805
	 * @param string $operator
1806
	 *
1807
	 * @return string
1808
	 */
1809
	public function getOperatorTemplateName(string $operator)
1810
	{
1811
		if (\in_array($operator, App\Condition::OPERATORS_WITHOUT_VALUES)) {
1812
			return;
1813
		}
1814
		if (\in_array($operator, \App\Condition::FIELD_COMPARISON_OPERATORS)) {
1815
			return 'ConditionBuilder/FieldsListUitype.tpl';
1816
		}
1817
		return $this->getUITypeModel()->getOperatorTemplateName($operator);
1818
	}
1819
1820
	/**
1821
	 * Function to get the field model for condition builder.
1822
	 *
1823
	 * @param string $operator
1824
	 *
1825
	 * @return self
1826
	 */
1827
	public function getConditionBuilderField(string $operator): self
1828
	{
1829
		return $this->getUITypeModel()->getConditionBuilderField($operator);
1830
	}
1831
1832
	/**
1833
	 * Sets data.
1834
	 *
1835
	 * @param array $data
1836
	 *
1837
	 * @return self
1838
	 */
1839
	public function setData(array $data = [])
1840
	{
1841
		foreach ($data as $key => $value) {
1842
			$this->set($key, $value);
1843
		}
1844
		return $this;
1845
	}
1846
1847
	/**
1848
	 * TabIndex last sequence number.
1849
	 *
1850
	 * @var int
1851
	 */
1852
	public static $tabIndexLastSeq = 0;
1853
	/**
1854
	 * TabIndex default sequence number.
1855
	 *
1856
	 * @var int
1857
	 */
1858
	public static $tabIndexDefaultSeq = 0;
1859
1860
	/**
1861
	 * Get TabIndex.
1862
	 *
1863
	 * @return int
1864
	 */
1865
	public function getTabIndex(): int
1866
	{
1867
		$tabindex = 0;
1868
		if (0 !== $this->get('tabindex')) {
1869
			$tabindex = $this->get('tabindex');
1870
		} elseif (self::$tabIndexLastSeq) {
1871
			$tabindex = self::$tabIndexLastSeq;
1872
		}
1873
		return $tabindex + self::$tabIndexDefaultSeq;
1874
	}
1875
1876
	/** {@inheritdoc} */
1877
	public function delete()
1878
	{
1879
		$this->getUITypeModel()->delete();
1880
		Settings_FieldsDependency_Module_Model::removeField($this->getModuleName(), $this->getName());
1881
		\App\Utils\Kanban::deleteField($this->getModuleName(), $this->getName());
1882
		\App\Fields\Picklist::removeDependencyConditionField($this->getModuleName(), $this->getName());
1883
		$this->getModule()->clearCache();
1884
		parent::delete();
1885
	}
1886
}
1887