Vtiger_Field_Model::getTabIndex()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
eloc 6
dl 0
loc 9
ccs 0
cts 0
cp 0
rs 10
c 0
b 0
f 0
cc 3
nc 3
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
	/** @var array Module field info. */
54
	protected $fieldInfo;
55
56
	/** @var string Field type. */
57
	protected $fieldType;
58
59
	/** @var string Field data type. */
60
	public $fieldDataType;
61 118
62
	/** @var string Field data type short. */
63 118
	protected $fieldDataTypeShort;
64 118
	protected $uitype_instance;
65
66 4
	/** @var string[] List of modules the field referenced to. */
67
	public $referenceList;
68
69
	/** @var string[] Picklist values only for custom fields;. */
70
	public $picklistValues;
71
72
	/** @var bool Is calculate field */
73
	protected $isCalculateField = true;
74
75
	/** @var bool|null Field visibility permissions */
76
	protected $permissions;
77 30
78
	/** @var Vtiger_Base_UIType Vtiger_Base_UIType or UI Type specific model instance */
79 30
	protected $uitypeModel;
80
81 30
	/** @var bool[] Permissions cache */
82
	protected $permissionsCache = [];
83
84
	/**
85
	 * Initialize.
86
	 *
87
	 * @param string     $module
88
	 * @param array      $data
89 64
	 * @param mixed|null $name
90
	 *
91 64
	 * @return \Vtiger_Field_Model
92
	 */
93
	public static function init($module = 'Vtiger', $data = [], $name = '')
94
	{
95
		if (\App\Module::getModuleId($module)) {
96
			$moduleModel = Vtiger_Module_Model::getInstance($module);
97
		} else {
98
			$modelClassName = \Vtiger_Loader::getComponentClassName('Model', 'Module', $module);
99 67
			$moduleModel = new $modelClassName();
100
		}
101 67
		$modelClassName = \Vtiger_Loader::getComponentClassName('Model', 'Field', $module);
102
		$instance = new $modelClassName();
103
		$instance->setModule($moduleModel);
104
		$instance->setData(array_merge([
105
			'uitype' => 1,
106
			'column' => $name,
107
			'name' => $name,
108
			'label' => $name,
109 53
			'displaytype' => 1,
110
			'typeofdata' => 'V~O',
111 53
			'presence' => 0,
112
			'isReadOnly' => false,
113
			'isEditableReadOnly' => false,
114
		], $data));
115
		return $instance;
116
	}
117
118
	/**
119 6
	 * Function to get the value of a given property.
120
	 *
121 6
	 * @param string $propertyName
122
	 *
123
	 * @return mixed|null
124
	 */
125
	public function get(string $propertyName)
126
	{
127
		if (property_exists($this, $propertyName)) {
128
			return $this->{$propertyName};
129 5813
		}
130
		return null;
131 5813
	}
132
133
	/**
134
	 * Function which sets value for given name.
135
	 *
136
	 * @param string $name  - name for which value need to be assinged
137
	 * @param mixed  $value - values that need to be assigned
138
	 *
139 5836
	 * @return Vtiger_Field_Model
140
	 */
141 5836
	public function set(string $name, $value)
142
	{
143
		$this->{$name} = $value;
144
		return $this;
145
	}
146
147
	/**
148
	 * Function to get the Field Id.
149 37
	 *
150
	 * @return int
151 37
	 */
152
	public function getId()
153
	{
154
		return $this->id;
155
	}
156
157
	/**
158
	 * Get name.
159
	 *
160
	 * @return string
161
	 */
162
	public function getName()
163
	{
164
		return $this->name;
165
	}
166
167
	/**
168
	 * Get full name.
169 16
	 *
170
	 * @return string
171 16
	 */
172 3
	public function getFullName()
173 3
	{
174
		return $this->get('source_field_name') ? "{$this->getName()}:{$this->getModuleName()}:{$this->get('source_field_name')}" : $this->getName();
175
	}
176 3
177
	/**
178
	 * Get full label translation.
179 3
	 *
180
	 * @param Vtiger_Module_Model|null $module
181 16
	 *
182
	 * @return string
183
	 */
184
	public function getFullLabelTranslation(?Vtiger_Module_Model $module = null): string
185
	{
186
		$translation = '';
187
		if ($this->get('source_field_name') && !$this->get('isLabelCustomized')) {
188
			if (!$module) {
189
				throw new \App\Exceptions\AppException('ERR_ARGUMENT_DOES_NOT_EXIST');
190
			}
191
			$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

191
			$translation = \App\Language::translate($module->getFieldByName($this->get('source_field_name'))->getFieldLabel(), /** @scrutinizer ignore-type */ $module->getName()) . ' - ';
Loading history...
Deprecated Code introduced by
The function Vtiger_Field_Model::getFieldLabel() has been deprecated: 7.0 Use $this->getLabel() ( Ignorable by Annotation )

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

191
			$translation = \App\Language::translate(/** @scrutinizer ignore-deprecated */ $module->getFieldByName($this->get('source_field_name'))->getFieldLabel(), $module->getName()) . ' - ';

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
192
		}
193
		return $translation .= \App\Language::translate($this->getFieldLabel(), $this->getModuleName());
0 ignored issues
show
Deprecated Code introduced by
The function Vtiger_Field_Model::getFieldLabel() has been deprecated: 7.0 Use $this->getLabel() ( Ignorable by Annotation )

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

193
		return $translation .= \App\Language::translate(/** @scrutinizer ignore-deprecated */ $this->getFieldLabel(), $this->getModuleName());

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

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

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

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

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

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

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

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

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

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