Passed
Push — developer ( ab47b4...ee9b1a )
by Radosław
18:38
created

Vtiger_Field_Model::getMinValue()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 8
ccs 0
cts 0
cp 0
rs 10
c 0
b 0
f 0
cc 3
nc 2
nop 0
crap 12
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 88:
383
						$fieldDataType = 'mailServer';
384 58
						break;
385
					case 89:
386 68
						$fieldDataType = 'mailFolders';
387
						break;
388 69
					case 98:
389
						$fieldDataType = 'userRole';
390 89
						break;
391
					case 99:
392
						$fieldDataType = 'password';
393
						break;
394
					case 101:
395
						$fieldDataType = 'userReference';
396
						break;
397
					case 115:
398 6
						$fieldDataType = 'picklist';
399
						break;
400 6
					case 117:
401 3
						$fieldDataType = 'currencyList';
402
						break;
403 6
					case 120:
404 1
						$fieldDataType = 'sharedOwner';
405
						break;
406 6
					case 301:
407 5
						$fieldDataType = 'modules';
408 5
						break;
409 5
					case 302:
410 5
						$fieldDataType = 'tree';
411 5
						break;
412 5
					case 303:
413
						$fieldDataType = 'taxes';
414 5
						break;
415 5
					case 304:
416 5
						$fieldDataType = 'inventoryLimit';
417 5
						break;
418 5
					case 305:
419 5
						$fieldDataType = 'multiReferenceValue';
420
						break;
421 6
					case 308:
422 6
						$fieldDataType = 'rangeTime';
423 6
						break;
424 6
					case 309:
425
						$fieldDataType = 'categoryMultipicklist';
426
						break;
427
					case 311:
428 6
						$fieldDataType = 'multiImage';
429
						break;
430 6
					case 312:
431
						$fieldDataType = 'authySecretTotp';
432
						break;
433
					case 313:
434
						$fieldDataType = 'twitter';
435
						break;
436
					case 314:
437
						$fieldDataType = 'multiEmail';
438
						break;
439
					case 315:
440
						$fieldDataType = 'multiDependField';
441
						break;
442
					case 316:
443
						$fieldDataType = 'smtp';
444
						break;
445
					case 317:
446
						$fieldDataType = 'currencyInventory';
447
						break;
448
					case 318:
449
						$fieldDataType = 'serverAccess';
450
						break;
451
					case 319:
452
						$fieldDataType = 'multiDomain';
453
						break;
454
					case 320:
455
						$fieldDataType = 'multiListFields';
456
						break;
457
					case 321:
458
						$fieldDataType = 'multiReference';
459
						break;
460
					case 322:
461
						$fieldDataType = 'mailScannerActions';
462 5851
						break;
463
					case 323:
464 5851
						$fieldDataType = 'mailScannerFields';
465 5827
						break;
466
					case 324:
467 44
						$fieldDataType = 'token';
468
						break;
469
					case 325:
470
						$fieldDataType = 'magentoServer';
471
						break;
472
					case 326:
473
						$fieldDataType = 'meetingUrl';
474
						break;
475
					case 327:
476
						$fieldDataType = 'barcode';
477
						break;
478
					case 328:
479
						$fieldDataType = 'changesJson';
480
						break;
481
					case 329:
482 4
						$fieldDataType = 'iban';
483
						break;
484 4
					case 330:
485
						$fieldDataType = 'multiAttachment';
486
						break;
487
					case 331:
488
						$fieldDataType = 'mapCoordinates';
489
						break;
490
					default:
491
						$fieldsDataType = App\Field::getFieldsTypeFromUIType();
492
						if (isset($fieldsDataType[$uiType])) {
493
							$fieldDataType = $fieldsDataType[$uiType]['fieldtype'];
494 4
						} else {
495
							$fieldTypeArray = explode('~', $this->get('typeofdata'));
496 4
							switch ($fieldTypeArray[0]) {
497
								case 'T':
498
									$fieldDataType = 'time';
499 4
									break;
500 4
								case 'D':
501 4
									$fieldDataType = 'date';
502 4
									break;
503 3
								case 'DT':
504 3
									$fieldDataType = 'datetime';
505
									break;
506 2
								case 'E':
507
									$fieldDataType = 'email';
508 4
									break;
509 1
								case 'N':
510
								case 'NN':
511
									$fieldDataType = 'double';
512 4
									break;
513 3
								case 'P':
514 3
									$fieldDataType = 'password';
515
									break;
516
								case 'I':
517
									$fieldDataType = 'integer';
518
									break;
519
								case 'V':
520
								default:
521
									$fieldDataType = 'string';
522 4
									break;
523
							}
524
						}
525
						break;
526
				}
527
				App\Cache::save('FieldDataType', $cacheName, $fieldDataType);
528
			}
529
			$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...
530
		}
531
		return $this->fieldDataType;
532
	}
533
534
	/**
535
	 * Function to get list of modules the field refernced to.
536
	 *
537
	 * @return string[] list of modules for which field is refered to
538
	 */
539
	public function getReferenceList()
540
	{
541
		if (isset($this->referenceList)) {
542
			return $this->referenceList;
543
		}
544
		if (\App\Cache::has('getReferenceList', $this->getId())) {
545
			return \App\Cache::get('getReferenceList', $this->getId());
546
		}
547
		if (method_exists($this->getUITypeModel(), 'getReferenceList')) {
548
			$list = $this->getUITypeModel()->getReferenceList();
549
		} else {
550
			if (10 === $this->getUIType()) {
551
				$query = (new \App\Db\Query())->select(['module' => 'relmodule'])
552
					->from('vtiger_fieldmodulerel')
553
					->innerJoin('vtiger_tab', 'vtiger_tab.name = vtiger_fieldmodulerel.relmodule')
554
					->where(['fieldid' => $this->getId()])
555
					->andWhere(['<>', 'vtiger_tab.presence', 1])
556
					->orderBy(['sequence' => SORT_ASC]);
557
			} else {
558
				$query = (new \App\Db\Query())->select(['module' => 'vtiger_ws_referencetype.type'])
559
					->from('vtiger_ws_referencetype')
560 16
					->innerJoin('vtiger_ws_fieldtype', 'vtiger_ws_referencetype.fieldtypeid = vtiger_ws_fieldtype.fieldtypeid')
561
					->innerJoin('vtiger_tab', 'vtiger_tab.name = vtiger_ws_referencetype.type')
562 16
					->where(['vtiger_ws_fieldtype.uitype' => $this->getUIType()])
563 16
					->andWhere(['<>', 'vtiger_tab.presence', 1]);
564
			}
565
			$list = [];
566
			foreach ($query->column() as $moduleName) {
567
				if (\App\Privilege::isPermitted($moduleName)) {
568
					$list[] = $moduleName;
569
				}
570
			}
571 17
		}
572
		\App\Cache::save('getReferenceList', $this->getId(), $list);
573 17
		return $list;
574 6
	}
575
576 14
	/**
577 14
	 * Function to check if the field is named field of the module.
578 14
	 *
579
	 * @return bool
580
	 */
581 14
	public function isNameField(): bool
582
	{
583 14
		$moduleModel = $this->getModule();
584
		return $moduleModel && !$this->isReferenceField() && !\in_array($this->getFieldDataType(), ['email', 'url', 'phone']) && \in_array($this->getName(), $moduleModel->getNameFields());
585
	}
586
587
	/**
588
	 * Function to get the UI Type model for the uitype of the current field.
589
	 *
590
	 * @return Vtiger_Base_UIType Vtiger_Base_UIType or UI Type specific model instance
591 11
	 */
592
	public function getUITypeModel(): Vtiger_Base_UIType
593 11
	{
594 3
		if (isset($this->uitypeModel)) {
595
			return $this->uitypeModel;
596 11
		}
597
		return $this->uitypeModel = Vtiger_Base_UIType::getInstanceFromField($this);
598
	}
599
600
	public function isRoleBased()
601
	{
602
		return 15 === $this->get('uitype') || 33 === $this->get('uitype');
603
	}
604 6
605
	/**
606
	 * Function to get all the available picklist values for the current field.
607 6
	 *
608 6
	 * @param bool $skipCheckingRole
609
	 *
610 4
	 * @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...
611
	 */
612 6
	public function getPicklistValues($skipCheckingRole = false)
613
	{
614
		if (isset($this->picklistValues)) {
615
			return $this->picklistValues;
616
		}
617
		$fieldDataType = $this->getFieldDataType();
618
		$fieldPickListValues = [];
619
		if ('picklist' === $fieldDataType || 'multipicklist' === $fieldDataType) {
620
			if ($this->isRoleBased() && !$skipCheckingRole) {
621
				$picklistValues = \App\Fields\Picklist::getRoleBasedValues($this->getName(), \App\User::getCurrentUserModel()->getRole());
622
			} else {
623
				$picklistValues = App\Fields\Picklist::getValuesName($this->getName());
624
			}
625
			foreach ($picklistValues as $value) {
626
				$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

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

998
		$this->fieldInfo['label'] = App\Language::translate($this->get('label'), $this->getModuleName(), /** @scrutinizer ignore-type */ false, false);
Loading history...
999
		$fieldDataType = $this->getFieldDataType();
1000 28
		$this->fieldInfo['type'] = $fieldDataType;
1001 28
		$this->fieldInfo['mandatory'] = $this->isMandatory();
1002 7
		$this->fieldInfo['defaultvalue'] = $this->getDefaultFieldValue();
1003
		$this->fieldInfo['presence'] = $this->isActiveField();
1004 28
		$this->fieldInfo['quickcreate'] = $this->isQuickCreateEnabled();
1005 21
		$this->fieldInfo['masseditable'] = $this->isMassEditable();
1006 21
		$this->fieldInfo['header_field'] = $this->getHeaderField();
1007
		$this->fieldInfo['maxlengthtext'] = $this->get('maxlengthtext');
1008
		$this->fieldInfo['maximumlength'] = $this->get('maximumlength');
1009
		$this->fieldInfo['maxwidthcolumn'] = $this->get('maxwidthcolumn');
1010
		$this->fieldInfo['tabindex'] = $this->get('tabindex');
1011 28
		$this->fieldInfo['fieldtype'] = explode('~', $this->get('typeofdata'))[0] ?? '';
1012 28
		$currentUser = \App\User::getCurrentUserModel();
1013
		switch ($fieldDataType) {
1014
			case 'picklist':
1015
			case 'multipicklist':
1016
			case 'multiowner':
1017
			case 'multiReferenceValue':
1018
			case 'inventoryLimit':
1019
			case 'languages':
1020
			case 'currencyList':
1021
			case 'fileLocationType':
1022
			case 'taxes':
1023
			case 'multiListFields':
1024
			case 'mailScannerFields':
1025
			case 'country':
1026
				$this->fieldInfo['picklistvalues'] = $this->getPicklistValues() ?: [];
1027
				break;
1028
			case 'date':
1029
			case 'datetime':
1030
				$this->fieldInfo['date-format'] = $currentUser->getDetail('date_format');
1031
				break;
1032
			case 'time':
1033
				$this->fieldInfo['time-format'] = $currentUser->getDetail('hour_format');
1034
				break;
1035
			case 'currency':
1036
				$this->fieldInfo['currency_symbol'] = $currentUser->getDetail('currency_symbol');
1037
				$this->fieldInfo['decimal_separator'] = $currentUser->getDetail('currency_decimal_separator');
1038
				$this->fieldInfo['group_separator'] = $currentUser->getDetail('currency_grouping_separator');
1039
				break;
1040
			case 'owner':
1041
			case 'userCreator':
1042
			case 'sharedOwner':
1043
				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

1043
				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...
1044
					$userList = \App\Fields\Owner::getInstance($this->getModuleName(), $currentUser)->getAccessibleUsers('', $fieldDataType);
1045
					$groupList = \App\Fields\Owner::getInstance($this->getModuleName(), $currentUser)->getAccessibleGroups('', $fieldDataType);
1046
					$pickListValues = [];
1047
					$pickListValues[\App\Language::translate('LBL_USERS', $this->getModuleName())] = $userList;
1048
					$pickListValues[\App\Language::translate('LBL_GROUPS', $this->getModuleName())] = $groupList;
1049
					$this->fieldInfo['picklistvalues'] = $pickListValues;
1050
					if (App\Config::performance('SEARCH_OWNERS_BY_AJAX')) {
1051
						$this->fieldInfo['searchOperator'] = 'e';
1052
					}
1053
				} else {
1054
					if ('owner' === $fieldDataType) {
1055
						$this->fieldInfo['searchOperator'] = 'e';
1056
					}
1057
				}
1058
				break;
1059
			case 'modules':
1060
				foreach ($this->getModulesListValues() as $module) {
1061
					$modulesList[$module['name']] = $module['label'];
1062
				}
1063
				$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 1060. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
1064
				break;
1065
			case 'categoryMultipicklist':
1066
			case 'tree':
1067
				$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

1067
				$this->fieldInfo['picklistvalues'] = \App\Fields\Tree::getPicklistValue(/** @scrutinizer ignore-type */ $this->getFieldParams(), $this->getModuleName());
Loading history...
1068
				$this->fieldInfo['treetemplate'] = $this->getFieldParams();
1069
				$this->fieldInfo['modulename'] = $this->getModuleName();
1070
				break;
1071
			case 'email':
1072
				if (\App\Config::security('EMAIL_FIELD_RESTRICTED_DOMAINS_ACTIVE') && !empty(\App\Config::security('EMAIL_FIELD_RESTRICTED_DOMAINS_VALUES'))) {
1073
					$validate = false;
1074
					if (empty(\App\Config::security('EMAIL_FIELD_RESTRICTED_DOMAINS_ALLOWED')) || \in_array($this->getModuleName(), \App\Config::security('EMAIL_FIELD_RESTRICTED_DOMAINS_ALLOWED'))) {
1075
						$validate = true;
1076
					}
1077
					if (\in_array($this->getModuleName(), \App\Config::security('EMAIL_FIELD_RESTRICTED_DOMAINS_EXCLUDED'))) {
1078
						$validate = false;
1079
					}
1080
					if ($validate) {
1081
						$this->fieldInfo['restrictedDomains'] = \App\Config::security('EMAIL_FIELD_RESTRICTED_DOMAINS_VALUES');
1082
					}
1083
				}
1084
				break;
1085
			default:
1086
				break;
1087
		}
1088
1089
		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...
1090
	}
1091
1092
	/**
1093
	 * Set field info.
1094
	 *
1095
	 * @param array $fieldInfo
1096
	 *
1097
	 * @return $this
1098
	 */
1099
	public function setFieldInfo(array $fieldInfo)
1100
	{
1101
		$this->fieldInfo = $fieldInfo;
1102
1103
		return $this;
1104
	}
1105
1106
	/**
1107
	 * Function to get the advanced filter option names by Field type.
1108
	 *
1109
	 * @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...
1110
	 */
1111
	public static function getAdvancedFilterOpsByFieldType()
1112
	{
1113
		return [
1114
			'V' => ['e', 'n', 's', 'ew', 'c', 'k', 'y', 'ny', 'om', 'wr', 'nwr'],
1115
			'N' => ['e', 'n', 'l', 'g', 'm', 'h', 'y', 'ny'],
1116
			'T' => ['e', 'n', 'l', 'g', 'm', 'h', 'bw', 'b', 'a', 'y', 'ny'],
1117
			'I' => ['e', 'n', 'l', 'g', 'm', 'h', 'y', 'ny'],
1118
			'C' => ['e', 'n', 'y', 'ny'],
1119
			'D' => ['e', 'n', 'bw', 'b', 'a', 'y', 'ny'],
1120
			'DT' => ['e', 'n', 'bw', 'b', 'a', 'y', 'ny'],
1121
			'NN' => ['e', 'n', 'l', 'g', 'm', 'h', 'y', 'ny'],
1122
			'E' => ['e', 'n', 's', 'ew', 'c', 'k', 'y', 'ny'],
1123
		];
1124
	}
1125
1126
	/**
1127
	 * Function to retrieve field model for specific block and module.
1128
	 *
1129
	 * @param vtlib\ModuleBasic $moduleModel
1130
	 *
1131
	 * @return Vtiger_Field_Model[][]
1132
	 */
1133
	public static function getAllForModule(vtlib\ModuleBasic $moduleModel)
1134
	{
1135
		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

1135
		if (\App\Cache::staticHas('ModuleFields', /** @scrutinizer ignore-type */ $moduleModel->id)) {
Loading history...
1136
			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

1136
			return \App\Cache::staticGet('ModuleFields', /** @scrutinizer ignore-type */ $moduleModel->id);
Loading history...
1137
		}
1138
		$fieldModelList = [];
0 ignored issues
show
Unused Code introduced by
The assignment to $fieldModelList is dead and can be removed.
Loading history...
1139
		$fieldObjects = parent::getAllForModule($moduleModel);
1140
		$fieldModelList = [];
1141
		if (!\is_array($fieldObjects)) {
0 ignored issues
show
introduced by
The condition is_array($fieldObjects) is always false.
Loading history...
1142
			$fieldObjects = [];
1143
		}
1144
		foreach ($fieldObjects as &$fieldObject) {
1145
			$fieldModel = self::getInstanceFromFieldObject($fieldObject);
1146
			$block = $fieldModel->get('block') ? $fieldModel->get('block')->id : 0;
1147
			$fieldModelList[$block][] = $fieldModel;
1148
			self::$instanceCacheById[$fieldModel->getId()] = $fieldModel;
1149
			self::$instanceCacheByName[$moduleModel->getId()][$fieldModel->getName()] = $fieldModel;
1150
		}
1151
		\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

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

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