Passed
Pull Request — developer (#15265)
by Arkadiusz
20:15
created

Vtiger_Field_Model::getFullName()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
ccs 0
cts 0
cp 0
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 0
crap 6
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.com
10
 * *********************************************************************************** */
11
12
/**
13
 * Vtiger Field Model Class.
14
 */
15
class Vtiger_Field_Model extends vtlib\Field
16
{
17
	protected $fieldType;
18
	protected $fieldDataTypeShort;
19
	protected $uitype_instance;
20
	/**
21
	 * @var string[] List of modules the field referenced to.
22
	 */
23
	public $referenceList;
24
	/**
25
	 * @var string[] Picklist values only for custom fields;.
26
	 */
27
	public $picklistValues;
28
	/**
29
	 * @var bool Is calculate field
30
	 */
31
	protected $isCalculateField = true;
32
	/**
33
	 * @var Vtiger_Base_UIType Vtiger_Base_UIType or UI Type specific model instance
34
	 */
35
	protected $uitypeModel;
36
37
	public static $referenceTypes = ['reference', 'referenceLink', 'referenceProcess', 'referenceSubProcess', 'referenceExtend', 'referenceSubProcessSL'];
38
39
	const REFERENCE_TYPE = 'reference';
40
	const OWNER_TYPE = 'owner';
41
	const CURRENCY_LIST = 'currencyList';
42
	const QUICKCREATE_MANDATORY = 0;
43
	const QUICKCREATE_NOT_ENABLED = 1;
44
	const QUICKCREATE_ENABLED = 2;
45
	const QUICKCREATE_NOT_PERMITTED = 3;
46
	/**
47
	 * Field maximum length by UiType.
48
	 *
49
	 * @var array
50
	 */
51
	public static $uiTypeMaxLength = [
52
		120 => 65535,
53
		106 => '3,64',
54
		156 => '3',
55
	];
56
	/**
57
	 * Field maximum length by db type.
58
	 *
59
	 * @var int[]
60
	 */
61 118
	public static $typesMaxLength = [
62
		'tinytext' => 255,
63 118
		'text' => 65535,
64 118
		'mediumtext' => 16777215,
65
		'longtext' => 4294967295,
66 4
		'blob' => 65535,
67
		'mediumblob' => 16777215,
68
		'longblob' => 4294967295,
69
	];
70
71
	/**
72
	 * Initialize.
73
	 *
74
	 * @param string     $module
75
	 * @param array      $data
76
	 * @param mixed|null $name
77 30
	 *
78
	 * @return \Vtiger_Field_Model
79 30
	 */
80
	public static function init($module = 'Vtiger', $data = [], $name = '')
81 30
	{
82
		$modelClassName = \Vtiger_Loader::getComponentClassName('Model', 'Module', $module);
83
		$moduleInstance = new $modelClassName();
84
		$modelClassName = \Vtiger_Loader::getComponentClassName('Model', 'Field', $module);
85
		$instance = new $modelClassName();
86
		$instance->setModule($moduleInstance);
87
		$instance->setData(array_merge([
88
			'uitype' => 1,
89 64
			'column' => $name,
90
			'name' => $name,
91 64
			'label' => $name,
92
			'displaytype' => 1,
93
			'typeofdata' => 'V~O',
94
			'presence' => 0,
95
			'isReadOnly' => false,
96
			'isEditableReadOnly' => false,
97
		], $data));
98
		return $instance;
99 67
	}
100
101 67
	/**
102
	 * Function to get the value of a given property.
103
	 *
104
	 * @param string $propertyName
105
	 *
106
	 * @return mixed|null
107
	 */
108
	public function get(string $propertyName)
109 53
	{
110
		if (property_exists($this, $propertyName)) {
111 53
			return $this->{$propertyName};
112
		}
113
		return null;
114
	}
115
116
	/**
117
	 * Function which sets value for given name.
118
	 *
119 6
	 * @param string $name  - name for which value need to be assinged
120
	 * @param mixed  $value - values that need to be assigned
121 6
	 *
122
	 * @return Vtiger_Field_Model
123
	 */
124
	public function set(string $name, $value)
125
	{
126
		$this->{$name} = $value;
127
		return $this;
128
	}
129 5813
130
	/**
131 5813
	 * Function to get the Field Id.
132
	 *
133
	 * @return int
134
	 */
135
	public function getId()
136
	{
137
		return $this->id;
138
	}
139 5836
140
	/**
141 5836
	 * Get name.
142
	 *
143
	 * @return string
144
	 */
145
	public function getName()
146
	{
147
		return $this->name;
148
	}
149 37
150
	/**
151 37
	 * Get full name.
152
	 *
153
	 * @return string
154
	 */
155
	public function getFullName()
156
	{
157
		return $this->get('source_field_name') ? "{$this->getName()}:{$this->getModuleName()}:{$this->get('source_field_name')}" : $this->getName();
158
	}
159
160
	/**
161
	 * Get full label translation.
162
	 *
163
	 * @param Vtiger_Module_Model|null $module
164
	 *
165
	 * @return string
166
	 */
167
	public function getFullLabelTranslation(?Vtiger_Module_Model $module = null): string
168
	{
169 16
		$translation = '';
170
		if ($this->get('source_field_name')) {
171 16
			if (!$module) {
172 3
				throw new \App\Exceptions\AppException('ERR_ARGUMENT_DOES_NOT_EXIST');
173 3
			}
174
			$translation = \App\Language::translate($module->getFieldByName($this->get('source_field_name'))->getFieldLabel(), $module->getName()) . ' - ';
175
		}
176 3
		return $translation .= \App\Language::translate($this->getFieldLabel(), $this->getModuleName());
177
	}
178
179 3
	/**
180
	 * Get field name.
181 16
	 *
182
	 * @deprecated Use $this->getName()
183
	 *
184
	 * @return string
185
	 */
186
	public function getFieldName()
187
	{
188
		return $this->name;
189
	}
190
191
	/**
192
	 * Get field label.
193
	 *
194
	 * @return string
195
	 */
196
	public function getFieldLabel()
197
	{
198
		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...
199
	}
200
201 5785
	/**
202
	 * Get table name.
203 5785
	 *
204
	 * @return string
205
	 */
206
	public function getTableName()
207
	{
208
		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...
209
	}
210
211 11
	/**
212
	 * Get column label.
213 11
	 *
214
	 * @return string
215
	 */
216
	public function getColumnName()
217
	{
218
		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...
219
	}
220
221 89
	/**
222
	 * Get ui type.
223 89
	 *
224 69
	 * @return int
225 69
	 */
226
	public function getUIType()
227
	{
228 69
		return $this->uitype;
229
	}
230 69
231 23
	/**
232
	 * Function to retrieve full data.
233 68
	 *
234 68
	 * @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...
235 10
	 */
236 10
	public function getData()
237 68
	{
238
		return get_object_vars($this);
239
	}
240 68
241 7
	/**
242 7
	 * Get module model.
243 66
	 *
244 3
	 * @return Vtiger_Module_Model
245 3
	 */
246 66
	public function getModule()
247 3
	{
248 3
		if (!isset($this->module)) {
249 66
			if (isset($this->block->module)) {
250 7
				$moduleObj = $this->block->module;
251 7
			}
252 66
			//fix for opensource emailTemplate listview break
253 10
			if (empty($moduleObj)) {
254 10
				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...
255 66
			}
256 11
			$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...
257 11
		}
258 66
		return $this->module;
259
	}
260
261 66
	public function setModule($moduleInstance)
262 3
	{
263 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...
264 66
		return $this;
265 3
	}
266 3
267 66
	/**
268 3
	 * Function to retieve display value for a value.
269 3
	 *
270 66
	 * @param mixed                    $value          value which need to be converted to display value
271 3
	 * @param bool|int                 $record
272 3
	 * @param bool|Vtiger_Record_Model $recordInstance
273 66
	 * @param bool                     $rawText
274 3
	 * @param bool|int                 $length         Length of the text
275 3
	 * @param mixed                    $recordModel
276 66
	 *
277 10
	 * @return mixed converted display value
278 10
	 */
279 65
	public function getDisplayValue($value, $record = false, $recordModel = false, $rawText = false, $length = false)
280 65
	{
281 8
		return $this->getUITypeModel()->getDisplayValue($value, $record, $recordModel, $rawText, $length);
282 8
	}
283 65
284 8
	/**
285 8
	 * Function to retrieve display type of a field.
286 65
	 *
287 7
	 * @return int display type of the field
288 7
	 */
289 65
	public function getDisplayType()
290 7
	{
291 7
		return (int) $this->get('displaytype');
292 65
	}
293 7
294 7
	/**
295 65
	 * Function to get the Webservice Field data type.
296 8
	 *
297 8
	 * @return string Data type of the field
298 65
	 */
299 9
	public function getFieldDataType()
300 9
	{
301 65
		if (!isset($this->fieldDataType)) {
302 8
			$uiType = $this->getUIType();
303 8
			if (55 === $uiType) {
304 65
				$cacheName = $uiType . '-' . $this->getName();
305 8
			} else {
306 8
				$cacheName = $uiType . '-' . $this->get('typeofdata');
307 63
			}
308 5
			if (App\Cache::has('FieldDataType', $cacheName)) {
309 5
				$fieldDataType = App\Cache::get('FieldDataType', $cacheName);
310 63
			} else {
311 4
				switch ($uiType) {
312 4
					case 4:
313 63
						$fieldDataType = 'recordNumber';
314 6
						break;
315 6
					case 8:
316 61
						$fieldDataType = 'totalTime';
317 3
						break;
318 3
					case 9:
319 61
						$fieldDataType = 'percentage';
320 6
						break;
321 6
					case 12:
322 59
						$fieldDataType = 'accountName';
323 4
						break;
324 4
					case 27:
325 59
						$fieldDataType = 'fileLocationType';
326 6
						break;
327 6
					case 28:
328 59
						$fieldDataType = 'documentsFileUpload';
329 1
						break;
330 1
					case 31:
331 59
						$fieldDataType = 'theme';
332
						break;
333
					case 32:
334 59
						$fieldDataType = 'languages';
335 7
						break;
336 7
					case 35:
337 59
						$fieldDataType = 'country';
338 3
						break;
339 3
					case 54:
340 59
						$fieldDataType = 'multiowner';
341 4
						break;
342 4
					case 64:
343 59
						$fieldDataType = 'referenceSubProcessSL';
344 4
						break;
345 4
					case 65:
346 58
						$fieldDataType = 'referenceExtend';
347
						break;
348
					case 66:
349
						$fieldDataType = 'referenceProcess';
350 58
						break;
351 58
					case 67:
352 45
						$fieldDataType = 'referenceLink';
353
						break;
354 33
					case 68:
355 33
						$fieldDataType = 'referenceSubProcess';
356 33
						break;
357 5
					case 69:
358 5
						$fieldDataType = 'image';
359 31
						break;
360 14
					case 79:
361 14
					case 80:
362 28
						$fieldDataType = 'datetime';
363 9
						break;
364 9
					case 98:
365 27
						$fieldDataType = 'userRole';
366 8
						break;
367 8
					case 99:
368 27
						$fieldDataType = 'password';
369 26
						break;
370 17
					case 101:
371 17
						$fieldDataType = 'userReference';
372 23
						break;
373
					case 115:
374
						$fieldDataType = 'picklist';
375 23
						break;
376 18
					case 117:
377 18
						$fieldDataType = 'currencyList';
378 19
						break;
379
					case 120:
380 19
						$fieldDataType = 'sharedOwner';
381 19
						break;
382
					case 301:
383
						$fieldDataType = 'modules';
384 58
						break;
385
					case 302:
386 68
						$fieldDataType = 'tree';
387
						break;
388 69
					case 303:
389
						$fieldDataType = 'taxes';
390 89
						break;
391
					case 304:
392
						$fieldDataType = 'inventoryLimit';
393
						break;
394
					case 305:
395
						$fieldDataType = 'multiReferenceValue';
396
						break;
397
					case 308:
398 6
						$fieldDataType = 'rangeTime';
399
						break;
400 6
					case 309:
401 3
						$fieldDataType = 'categoryMultipicklist';
402
						break;
403 6
					case 311:
404 1
						$fieldDataType = 'multiImage';
405
						break;
406 6
					case 312:
407 5
						$fieldDataType = 'authySecretTotp';
408 5
						break;
409 5
					case 313:
410 5
						$fieldDataType = 'twitter';
411 5
						break;
412 5
					case 314:
413
						$fieldDataType = 'multiEmail';
414 5
						break;
415 5
					case 315:
416 5
						$fieldDataType = 'multiDependField';
417 5
						break;
418 5
					case 316:
419 5
						$fieldDataType = 'smtp';
420
						break;
421 6
					case 317:
422 6
						$fieldDataType = 'currencyInventory';
423 6
						break;
424 6
					case 318:
425
						$fieldDataType = 'serverAccess';
426
						break;
427
					case 319:
428 6
						$fieldDataType = 'multiDomain';
429
						break;
430 6
					case 320:
431
						$fieldDataType = 'multiListFields';
432
						break;
433
					case 321:
434
						$fieldDataType = 'multiReference';
435
						break;
436
					case 322:
437
						$fieldDataType = 'mailScannerActions';
438
						break;
439
					case 323:
440
						$fieldDataType = 'mailScannerFields';
441
						break;
442
					case 324:
443
						$fieldDataType = 'token';
444
						break;
445
					case 325:
446
						$fieldDataType = 'magentoServer';
447
						break;
448
					case 326:
449
						$fieldDataType = 'meetingUrl';
450
						break;
451
					case 327:
452
						$fieldDataType = 'barcode';
453
						break;
454
					case 328:
455
						$fieldDataType = 'changesJson';
456
						break;
457
					case 329:
458
						$fieldDataType = 'iban';
459
						break;
460
					default:
461
						$fieldsDataType = App\Field::getFieldsTypeFromUIType();
462 5851
						if (isset($fieldsDataType[$uiType])) {
463
							$fieldDataType = $fieldsDataType[$uiType]['fieldtype'];
464 5851
						} else {
465 5827
							$fieldTypeArray = explode('~', $this->get('typeofdata'));
0 ignored issues
show
Bug introduced by
It seems like $this->get('typeofdata') can also be of type null; however, parameter $string of explode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

465
							$fieldTypeArray = explode('~', /** @scrutinizer ignore-type */ $this->get('typeofdata'));
Loading history...
466
							switch ($fieldTypeArray[0]) {
467 44
								case 'T':
468
									$fieldDataType = 'time';
469
									break;
470
								case 'D':
471
									$fieldDataType = 'date';
472
									break;
473
								case 'DT':
474
									$fieldDataType = 'datetime';
475
									break;
476
								case 'E':
477
									$fieldDataType = 'email';
478
									break;
479
								case 'N':
480
								case 'NN':
481
									$fieldDataType = 'double';
482 4
									break;
483
								case 'P':
484 4
									$fieldDataType = 'password';
485
									break;
486
								case 'I':
487
									$fieldDataType = 'integer';
488
									break;
489
								case 'V':
490
								default:
491
									$fieldDataType = 'string';
492
									break;
493
							}
494 4
						}
495
						break;
496 4
				}
497
				App\Cache::save('FieldDataType', $cacheName, $fieldDataType);
498
			}
499 4
			$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...
500 4
		}
501 4
		return $this->fieldDataType;
502 4
	}
503 3
504 3
	/**
505
	 * Function to get list of modules the field refernced to.
506 2
	 *
507
	 * @return string[] list of modules for which field is refered to
508 4
	 */
509 1
	public function getReferenceList()
510
	{
511
		if (isset($this->referenceList)) {
512 4
			return $this->referenceList;
513 3
		}
514 3
		if (\App\Cache::has('getReferenceList', $this->getId())) {
515
			return \App\Cache::get('getReferenceList', $this->getId());
516
		}
517
		if (method_exists($this->getUITypeModel(), 'getReferenceList')) {
518
			$list = $this->getUITypeModel()->getReferenceList();
519
		} else {
520
			if (10 === $this->getUIType()) {
521
				$query = (new \App\Db\Query())->select(['module' => 'relmodule'])
522 4
					->from('vtiger_fieldmodulerel')
523
					->innerJoin('vtiger_tab', 'vtiger_tab.name = vtiger_fieldmodulerel.relmodule')
524
					->where(['fieldid' => $this->getId()])
525
					->andWhere(['<>', 'vtiger_tab.presence', 1])
526
					->orderBy(['sequence' => SORT_ASC]);
527
			} else {
528
				$query = (new \App\Db\Query())->select(['module' => 'vtiger_ws_referencetype.type'])
529
					->from('vtiger_ws_referencetype')
530
					->innerJoin('vtiger_ws_fieldtype', 'vtiger_ws_referencetype.fieldtypeid = vtiger_ws_fieldtype.fieldtypeid')
531
					->innerJoin('vtiger_tab', 'vtiger_tab.name = vtiger_ws_referencetype.type')
532
					->where(['vtiger_ws_fieldtype.uitype' => $this->getUIType()])
533
					->andWhere(['<>', 'vtiger_tab.presence', 1]);
534
			}
535
			$list = [];
536
			foreach ($query->column() as $moduleName) {
537
				if (\App\Privilege::isPermitted($moduleName)) {
538
					$list[] = $moduleName;
539
				}
540
			}
541
		}
542
		\App\Cache::save('getReferenceList', $this->getId(), $list);
543
		return $list;
544
	}
545
546
	/**
547
	 * Function to check if the field is named field of the module.
548
	 *
549
	 * @return bool
550
	 */
551
	public function isNameField(): bool
552
	{
553
		$moduleModel = $this->getModule();
554
		return $moduleModel && !$this->isReferenceField() && !\in_array($this->getFieldDataType(), ['email', 'url', 'phone']) && \in_array($this->getFieldName(), $moduleModel->getNameFields());
0 ignored issues
show
Deprecated Code introduced by
The function Vtiger_Field_Model::getFieldName() has been deprecated: Use $this->getName() ( Ignorable by Annotation )

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

554
		return $moduleModel && !$this->isReferenceField() && !\in_array($this->getFieldDataType(), ['email', 'url', 'phone']) && \in_array(/** @scrutinizer ignore-deprecated */ $this->getFieldName(), $moduleModel->getNameFields());

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...
555
	}
556
557
	/**
558
	 * Function to get the UI Type model for the uitype of the current field.
559
	 *
560 16
	 * @return Vtiger_Base_UIType Vtiger_Base_UIType or UI Type specific model instance
561
	 */
562 16
	public function getUITypeModel()
563 16
	{
564
		if (isset($this->uitypeModel)) {
565
			return $this->uitypeModel;
566
		}
567
		return $this->uitypeModel = Vtiger_Base_UIType::getInstanceFromField($this);
568
	}
569
570
	public function isRoleBased()
571 17
	{
572
		return 15 === $this->get('uitype') || 33 === $this->get('uitype');
573 17
	}
574 6
575
	/**
576 14
	 * Function to get all the available picklist values for the current field.
577 14
	 *
578 14
	 * @param bool $skipCheckingRole
579
	 *
580
	 * @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...
581 14
	 */
582
	public function getPicklistValues($skipCheckingRole = false)
583 14
	{
584
		if (isset($this->picklistValues)) {
585
			return $this->picklistValues;
586
		}
587
		$fieldDataType = $this->getFieldDataType();
588
		$fieldPickListValues = [];
589
		if ('picklist' === $fieldDataType || 'multipicklist' === $fieldDataType) {
590
			if ($this->isRoleBased() && !$skipCheckingRole) {
591 11
				$picklistValues = \App\Fields\Picklist::getRoleBasedValues($this->getName(), \App\User::getCurrentUserModel()->getRole());
592
			} else {
593 11
				$picklistValues = App\Fields\Picklist::getValuesName($this->getName());
594 3
			}
595
			foreach ($picklistValues as $value) {
596 11
				$fieldPickListValues[$value] = \App\Language::translate($value, $this->getModuleName());
597
			}
598
			// Protection against deleting a value that does not exist on the list
599
			if ('picklist' === $fieldDataType) {
600
				$fieldValue = $this->get('fieldvalue');
601
				if (!empty($fieldValue) && !isset($fieldPickListValues[$fieldValue])) {
602
					$fieldPickListValues[$fieldValue] = \App\Language::translate($fieldValue, $this->getModuleName());
603
					$this->set('isEditableReadOnly', true);
604 6
				}
605
			}
606
		} elseif (method_exists($this->getUITypeModel(), 'getPicklistValues')) {
607 6
			$fieldPickListValues = $this->getUITypeModel()->getPicklistValues();
608 6
		}
609
		return $fieldPickListValues;
610 4
	}
611
612 6
	/**
613
	 * Function to get all the available picklist values for the current field.
614
	 *
615
	 * @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...
616
	 */
617
	public function getModulesListValues()
618
	{
619
		$allModules = \vtlib\Functions::getAllModules(true, false, 0);
620
		$modules = [];
621
		foreach ($allModules as $module) {
622
			$modules[$module['tabid']] = [
623
				'name' => $module['name'],
624
				'label' => App\Language::translate($module['name'], $module['name']),
625
			];
626
		}
627
		return $modules;
628
	}
629
630
	public static function showDisplayTypeList()
631
	{
632
		return [
633
			1 => 'LBL_DISPLAY_TYPE_1',
634
			2 => 'LBL_DISPLAY_TYPE_2',
635
			3 => 'LBL_DISPLAY_TYPE_3',
636
			4 => 'LBL_DISPLAY_TYPE_4',
637
			//5 => 'LBL_DISPLAY_TYPE_5',
638
			10 => 'LBL_DISPLAY_TYPE_10',
639
		];
640
	}
641
642
	/**
643
	 * Function to check if the current field is mandatory or not.
644
	 *
645
	 * @return bool
646
	 */
647
	public function isMandatory()
648
	{
649
		if ($this->get('isMandatory')) {
650
			return $this->get('isMandatory');
651
		}
652
		$typeOfData = explode('~', $this->get('typeofdata'));
0 ignored issues
show
Bug introduced by
It seems like $this->get('typeofdata') can also be of type null; however, parameter $string of explode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

652
		$typeOfData = explode('~', /** @scrutinizer ignore-type */ $this->get('typeofdata'));
Loading history...
653
		return isset($typeOfData[1]) && 'M' === $typeOfData[1];
654
	}
655
656
	/**
657
	 * Function to get the field type.
658
	 *
659
	 * @return string type of the field
660
	 */
661
	public function getFieldType()
662
	{
663
		if (isset($this->fieldType)) {
664
			return $this->fieldType;
665
		}
666
		$fieldTypeArray = explode('~', $this->get('typeofdata'));
0 ignored issues
show
Bug introduced by
It seems like $this->get('typeofdata') can also be of type null; however, parameter $string of explode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

666
		$fieldTypeArray = explode('~', /** @scrutinizer ignore-type */ $this->get('typeofdata'));
Loading history...
667
		$fieldTypeArray = array_shift($fieldTypeArray);
668
		if ('reference' === $this->getFieldDataType()) {
669
			$fieldTypeArray = 'V';
670
		} else {
671
			$fieldTypeArray = \vtlib\Functions::transformFieldTypeOfData($this->get('table'), $this->get('column'), $fieldTypeArray);
672
		}
673
		return $this->fieldType = $fieldTypeArray;
674
	}
675
676
	/**
677
	 * Function to check if the field is shown in detail view.
678
	 *
679
	 * @return bool
680
	 */
681
	public function isViewEnabled()
682
	{
683
		if (4 === $this->getDisplayType() || \in_array($this->get('presence'), [1, 3])) {
684
			return false;
685
		}
686
		return $this->getPermissions();
687
	}
688
689
	/**
690
	 * Function to check if the field is shown in detail view.
691
	 *
692
	 * @return bool
693
	 */
694 16
	public function isViewable()
695
	{
696 16
		if (
697 16
			!$this->isViewEnabled() || !$this->isActiveReference()
698 16
			|| ((306 === $this->get('uitype') || 307 === $this->get('uitype') || 311 === $this->get('uitype') || 312 === $this->get('uitype')) && 2 === $this->getDisplayType())
699
		) {
700
			return false;
701 16
		}
702
		return true;
703
	}
704
705
	/**
706
	 * Function to check if the field is export table.
707
	 *
708
	 * @return bool
709
	 */
710
	public function isExportTable()
711
	{
712
		return $this->isViewable();
713
	}
714
715
	/**
716
	 * Function to check if the field is shown in detail view.
717
	 *
718
	 * @return bool
719 6
	 */
720
	public function isViewableInDetailView()
721 6
	{
722
		if (!$this->isViewable() || 3 === $this->getDisplayType() || 5 === $this->getDisplayType()) {
723
			return false;
724 6
		}
725
		return true;
726
	}
727
728
	/**
729
	 * Function to check whether the current field is writable.
730
	 *
731
	 * @return bool
732
	 */
733
	public function isWritable()
734
	{
735
		$displayType = $this->get('displaytype');
736
		if (!$this->isViewEnabled() || 4 === $displayType || 5 === $displayType
737
			|| 0 === strcasecmp($this->getFieldDataType(), 'autogenerated')
738
			|| 0 === strcasecmp($this->getFieldDataType(), 'id')
739
			|| true === $this->isReadOnly()
740
			|| !$this->getUITypeModel()->isWritable()) {
741
			return false;
742 48
		}
743
		return true;
744 48
	}
745 48
746 48
	/**
747 48
	 * Function to check whether the current field is editable.
748 48
	 *
749
	 * @return bool
750 48
	 */
751
	public function isEditable()
752
	{
753
		$displayType = $this->get('displaytype');
754
		if (!$this->isWritable() || (1 !== $displayType && 10 !== $displayType) || true === $this->isReadOnly()) {
755
			return false;
756
		}
757
		return true;
758
	}
759
760
	/**
761
	 * Function to check whether field is ajax editable.
762
	 *
763
	 * @return bool
764
	 */
765
	public function isAjaxEditable()
766
	{
767
		$ajaxRestrictedFields = [72, 12, 101];
768
		return !(10 === (int) $this->get('displaytype') || $this->isReferenceField() || !$this->getUITypeModel()->isAjaxEditable() || !$this->isEditable() || \in_array($this->get('uitype'), $ajaxRestrictedFields));
769
	}
770
771
	public function isEditableReadOnly()
772
	{
773
		if (null !== $this->get('isEditableReadOnly')) {
774
			return $this->get('isEditableReadOnly');
775
		}
776
		if (10 === (int) $this->get('displaytype')) {
777
			return true;
778
		}
779
		return false;
780
	}
781
782
	/**
783
	 * Function to check whether the current field is read-only.
784
	 *
785
	 * @return bool
786
	 */
787
	public function isReadOnly(): bool
788
	{
789
		if (isset($this->isReadOnly)) {
790
			return $this->isReadOnly;
791
		}
792
		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...
793
	}
794
795
	public function isQuickCreateEnabled()
796
	{
797
		$moduleModel = $this->getModule();
798
		$quickCreate = $this->get('quickcreate');
799
		if ((self::QUICKCREATE_MANDATORY == $quickCreate || self::QUICKCREATE_ENABLED == $quickCreate || $this->isMandatory()) && method_exists($moduleModel, 'isQuickCreateSupported') && $moduleModel->isQuickCreateSupported()) {
800
			return true;
801
		}
802
		return false;
803
	}
804
805
	/**
806
	 * Function to check whether summary field or not.
807
	 *
808
	 * @return bool true/false
809
	 */
810
	public function isSummaryField()
811
	{
812
		return ($this->get('summaryfield')) ? true : false;
813
	}
814
815
	/**
816
	 * Function to check whether the current reference field is active.
817
	 *
818
	 * @return bool
819
	 */
820
	public function isActiveReference()
821
	{
822
		if ('reference' === $this->getFieldDataType() && empty($this->getReferenceList())) {
823
			return false;
824
		}
825
		return true;
826
	}
827
828
	/**
829
	 * If the field is sortable in ListView.
830 16
	 */
831
	public function isListviewSortable()
832 16
	{
833 16
		return !$this->get('fromOutsideList') && $this->getUITypeModel()->isListviewSortable();
834 16
	}
835 16
836 16
	/**
837 16
	 * Static Function to get the instance fo Vtiger Field Model from a given vtlib\Field object.
838 16
	 *
839 16
	 * @param vtlib\Field $fieldObj - vtlib field object
840 16
	 *
841 16
	 * @return Vtiger_Field_Model instance
842 16
	 */
843 16
	public static function getInstanceFromFieldObject(vtlib\Field $fieldObj)
844 16
	{
845 16
		$objectProperties = get_object_vars($fieldObj);
846
		$className = Vtiger_Loader::getComponentClassName('Model', 'Field', $fieldObj->getModuleName());
847 16
		$fieldModel = new $className();
848 16
		foreach ($objectProperties as $properName => $propertyValue) {
849 16
			$fieldModel->{$properName} = $propertyValue;
850 16
		}
851 16
		return $fieldModel;
852 16
	}
853 16
854 16
	/**
855 16
	 * Function to get the custom view column name transformation of the field for a date field used in date filters.
856 16
	 *
857 16
	 * @return string - tablename:columnname:fieldname:module_fieldlabel
858
	 */
859
	public function getCVDateFilterColumnName()
860
	{
861
		$moduleName = $this->getModuleName();
862
		$tableName = $this->get('table');
863
		$columnName = $this->get('column');
864
		$fieldName = $this->get('name');
865 16
		$fieldLabel = $this->get('label');
866 16
867
		$escapedFieldLabel = str_replace(' ', '_', $fieldLabel);
868
		$moduleFieldLabel = $moduleName . '_' . $escapedFieldLabel;
869 16
870
		return $tableName . ':' . $columnName . ':' . $fieldName . ':' . $moduleFieldLabel;
871
	}
872 16
873
	/**
874
	 * Function to get value for customview.
875
	 *
876
	 * @param string $sourceFieldName
877 16
	 *
878 16
	 * @throws \Exception
879 16
	 *
880
	 * @return string
881
	 */
882
	public function getCustomViewSelectColumnName(string $sourceFieldName = '')
883
	{
884
		return "{$this->get('name')}:{$this->getModuleName()}" . ($sourceFieldName ? ":{$sourceFieldName}" : '');
885
	}
886
887
	/**
888
	 * Function to get the custom view column name transformation of the field.
889
	 *
890
	 * @return string - tablename:columnname:fieldname:module_fieldlabel:fieldtype
891
	 */
892
	public function getCustomViewColumnName()
893
	{
894
		$moduleName = $this->getModuleName();
895
		$tableName = $this->get('table');
896 16
		$columnName = $this->get('column');
897
		$fieldName = $this->get('name');
898
		$fieldLabel = $this->get('label');
899
		$typeOfData = $this->get('typeofdata');
900
		$fieldTypeOfData = explode('~', $typeOfData);
0 ignored issues
show
Bug introduced by
It seems like $typeOfData can also be of type null; however, parameter $string of explode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

900
		$fieldTypeOfData = explode('~', /** @scrutinizer ignore-type */ $typeOfData);
Loading history...
901
		$fieldTypeOfData = $fieldTypeOfData[0];
902 16
		//Special condition need for reference field as they should be treated as string field
903 16
		if ('reference' === $this->getFieldDataType()) {
904
			$fieldTypeOfData = 'V';
905
		} else {
906 16
			$fieldTypeOfData = \vtlib\Functions::transformFieldTypeOfData($tableName, $columnName, $fieldTypeOfData);
907
		}
908
		$escapedFieldLabel = str_replace(' ', '_', $fieldLabel);
909
		$moduleFieldLabel = "{$moduleName}_{$escapedFieldLabel}";
910
911
		return "$tableName:$columnName:$fieldName:$moduleFieldLabel:$fieldTypeOfData";
912
	}
913
914
	/**
915
	 * This is set from Workflow Record Structure, since workflow expects the field name
916
	 * in a different format in its filter. Eg: for module field its fieldname and for reference
917
	 * fields its reference_field_name : (reference_module_name) field - salesorder_id: (SalesOrder) subject.
918
	 *
919
	 * @return string
920 16
	 */
921 6
	public function getWorkFlowFilterColumnName()
922 6
	{
923 6
		return $this->get('workflow_columnname');
924 6
	}
925 10
926 10
	/**
927 10
	 * Function to get the field details.
928 10
	 *
929 10
	 * @return array - array of field values
930
	 */
931
	public function getFieldInfo()
932
	{
933 16
		$this->fieldInfo['name'] = $this->get('name');
0 ignored issues
show
Bug Best Practice introduced by
The property fieldInfo does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
934
		$this->fieldInfo['label'] = App\Language::translate($this->get('label'), $this->getModuleName());
935
		$fieldDataType = $this->getFieldDataType();
936
		$this->fieldInfo['type'] = $fieldDataType;
937
		$this->fieldInfo['mandatory'] = $this->isMandatory();
938
		$this->fieldInfo['defaultvalue'] = $this->getDefaultFieldValue();
939
		$this->fieldInfo['presence'] = $this->isActiveField();
940
		$this->fieldInfo['quickcreate'] = $this->isQuickCreateEnabled();
941
		$this->fieldInfo['masseditable'] = $this->isMassEditable();
942
		$this->fieldInfo['header_field'] = $this->getHeaderField();
943
		$this->fieldInfo['maxlengthtext'] = $this->get('maxlengthtext');
944
		$this->fieldInfo['maximumlength'] = $this->get('maximumlength');
945
		$this->fieldInfo['maxwidthcolumn'] = $this->get('maxwidthcolumn');
946
		$this->fieldInfo['tabindex'] = $this->get('tabindex');
947
		$this->fieldInfo['fieldtype'] = explode('~', $this->get('typeofdata'))[0] ?? '';
0 ignored issues
show
Bug introduced by
It seems like $this->get('typeofdata') can also be of type null; however, parameter $string of explode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

947
		$this->fieldInfo['fieldtype'] = explode('~', /** @scrutinizer ignore-type */ $this->get('typeofdata'))[0] ?? '';
Loading history...
948
		$currentUser = \App\User::getCurrentUserModel();
949
		switch ($fieldDataType) {
950
			case 'picklist':
951
			case 'multipicklist':
952
			case 'multiowner':
953
			case 'multiReferenceValue':
954
			case 'inventoryLimit':
955
			case 'languages':
956
			case 'currencyList':
957
			case 'fileLocationType':
958
			case 'taxes':
959
			case 'multiListFields':
960
			case 'mailScannerFields':
961
			case 'country':
962
				$this->fieldInfo['picklistvalues'] = $this->getPicklistValues() ?: [];
963
				break;
964
			case 'date':
965
			case 'datetime':
966
				$this->fieldInfo['date-format'] = $currentUser->getDetail('date_format');
967
				break;
968 25
			case 'time':
969
				$this->fieldInfo['time-format'] = $currentUser->getDetail('hour_format');
970 25
				break;
971 5
			case 'currency':
972
				$this->fieldInfo['currency_symbol'] = $currentUser->getDetail('currency_symbol');
973 23
				$this->fieldInfo['decimal_separator'] = $currentUser->getDetail('currency_decimal_separator');
974 23
				$this->fieldInfo['group_separator'] = $currentUser->getDetail('currency_grouping_separator');
975 23
				break;
976 23
			case 'owner':
977
			case 'userCreator':
978
			case 'sharedOwner':
979 23
				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

979
				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...
980 23
					$userList = \App\Fields\Owner::getInstance($this->getModuleName(), $currentUser)->getAccessibleUsers('', $fieldDataType);
981 23
					$groupList = \App\Fields\Owner::getInstance($this->getModuleName(), $currentUser)->getAccessibleGroups('', $fieldDataType);
982 23
					$pickListValues = [];
983 23
					$pickListValues[\App\Language::translate('LBL_USERS', $this->getModuleName())] = $userList;
984 23
					$pickListValues[\App\Language::translate('LBL_GROUPS', $this->getModuleName())] = $groupList;
985
					$this->fieldInfo['picklistvalues'] = $pickListValues;
986 23
					if (App\Config::performance('SEARCH_OWNERS_BY_AJAX')) {
987 23
						$this->fieldInfo['searchOperator'] = 'e';
988
					}
989
				} else {
990
					if ('owner' === $fieldDataType) {
991
						$this->fieldInfo['searchOperator'] = 'e';
992
					}
993
				}
994
				break;
995
			case 'modules':
996
				foreach ($this->getModulesListValues() as $module) {
997
					$modulesList[$module['name']] = $module['label'];
998 28
				}
999
				$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 996. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
1000 28
				break;
1001 28
			case 'categoryMultipicklist':
1002 7
			case 'tree':
1003
				$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

1003
				$this->fieldInfo['picklistvalues'] = \App\Fields\Tree::getPicklistValue(/** @scrutinizer ignore-type */ $this->getFieldParams(), $this->getModuleName());
Loading history...
1004 28
				$this->fieldInfo['treetemplate'] = $this->getFieldParams();
1005 21
				$this->fieldInfo['modulename'] = $this->getModuleName();
1006 21
				break;
1007
			case 'email':
1008
				if (\App\Config::security('EMAIL_FIELD_RESTRICTED_DOMAINS_ACTIVE') && !empty(\App\Config::security('EMAIL_FIELD_RESTRICTED_DOMAINS_VALUES'))) {
1009
					$validate = false;
1010
					if (empty(\App\Config::security('EMAIL_FIELD_RESTRICTED_DOMAINS_ALLOWED')) || \in_array($this->getModuleName(), \App\Config::security('EMAIL_FIELD_RESTRICTED_DOMAINS_ALLOWED'))) {
1011 28
						$validate = true;
1012 28
					}
1013
					if (\in_array($this->getModuleName(), \App\Config::security('EMAIL_FIELD_RESTRICTED_DOMAINS_EXCLUDED'))) {
1014
						$validate = false;
1015
					}
1016
					if ($validate) {
1017
						$this->fieldInfo['restrictedDomains'] = \App\Config::security('EMAIL_FIELD_RESTRICTED_DOMAINS_VALUES');
1018
					}
1019
				}
1020
				break;
1021
			case 'multiImage':
1022
				$params = $this->getFieldParams();
1023
				$this->fieldInfo['limit'] = $params['limit'] ?? Vtiger_MultiImage_File::$defaultLimit;
1024
				$this->fieldInfo['formats'] = $params['formats'] ?? \App\Fields\File::$allowedFormats['image'];
1025
				break;
1026
			case 'image':
1027
				$params = $this->getFieldParams();
1028
				$this->fieldInfo['limit'] = $params['limit'] ?? Vtiger_Image_UIType::$defaultLimit;
1029
				$this->fieldInfo['formats'] = $params['formats'] ?? \App\Fields\File::$allowedFormats['image'];
1030
				break;
1031
			default:
1032
				break;
1033
		}
1034
		return $this->fieldInfo;
1035
	}
1036
1037
	public function setFieldInfo($fieldInfo)
1038
	{
1039
		$this->fieldInfo = $fieldInfo;
0 ignored issues
show
Bug Best Practice introduced by
The property fieldInfo does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
1040
	}
1041
1042
	/**
1043
	 * Function to get the advanced filter option names by Field type.
1044
	 *
1045
	 * @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...
1046
	 */
1047
	public static function getAdvancedFilterOpsByFieldType()
1048
	{
1049
		return [
1050
			'V' => ['e', 'n', 's', 'ew', 'c', 'k', 'y', 'ny', 'om', 'wr', 'nwr'],
1051
			'N' => ['e', 'n', 'l', 'g', 'm', 'h', 'y', 'ny'],
1052
			'T' => ['e', 'n', 'l', 'g', 'm', 'h', 'bw', 'b', 'a', 'y', 'ny'],
1053
			'I' => ['e', 'n', 'l', 'g', 'm', 'h', 'y', 'ny'],
1054
			'C' => ['e', 'n', 'y', 'ny'],
1055
			'D' => ['e', 'n', 'bw', 'b', 'a', 'y', 'ny'],
1056
			'DT' => ['e', 'n', 'bw', 'b', 'a', 'y', 'ny'],
1057
			'NN' => ['e', 'n', 'l', 'g', 'm', 'h', 'y', 'ny'],
1058
			'E' => ['e', 'n', 's', 'ew', 'c', 'k', 'y', 'ny'],
1059
		];
1060
	}
1061
1062
	/**
1063
	 * Function to retrieve field model for specific block and module.
1064
	 *
1065
	 * @param vtlib\ModuleBasic $moduleModel
1066
	 *
1067
	 * @return Vtiger_Field_Model[][]
1068
	 */
1069
	public static function getAllForModule(vtlib\ModuleBasic $moduleModel)
1070
	{
1071
		if (\App\Cache::staticHas('ModuleFields', $moduleModel->id)) {
1072
			return \App\Cache::staticGet('ModuleFields', $moduleModel->id);
1073
		}
1074
		$fieldModelList = [];
0 ignored issues
show
Unused Code introduced by
The assignment to $fieldModelList is dead and can be removed.
Loading history...
1075
		$fieldObjects = parent::getAllForModule($moduleModel);
1076
		$fieldModelList = [];
1077
		if (!\is_array($fieldObjects)) {
0 ignored issues
show
introduced by
The condition is_array($fieldObjects) is always false.
Loading history...
1078
			$fieldObjects = [];
1079
		}
1080
		foreach ($fieldObjects as &$fieldObject) {
1081
			$fieldModelObject = self::getInstanceFromFieldObject($fieldObject);
1082
			$block = $fieldModelObject->get('block') ? $fieldModelObject->get('block')->id : 0;
1083
			$fieldModelList[$block][] = $fieldModelObject;
1084
			Vtiger_Cache::set('field-' . $moduleModel->getId(), $fieldModelObject->getId(), $fieldModelObject);
1085
			Vtiger_Cache::set('field-' . $moduleModel->getId(), $fieldModelObject->getName(), $fieldModelObject);
1086
		}
1087
		\App\Cache::staticSave('ModuleFields', $moduleModel->id, $fieldModelList);
1088
		return $fieldModelList;
1089
	}
1090
1091
	/**
1092
	 * Function to get instance.
1093
	 *
1094
	 * @param string|int                $value  - fieldname or fieldid
1095
	 * @param Vtiger_Module_Model|false $module - optional - module instance
1096
	 *
1097
	 * @return Vtiger_Field_Model|false
1098
	 */
1099
	public static function getInstance($value, $module = false)
1100
	{
1101
		$fieldObject = null;
1102
		if ($module) {
1103
			$fieldObject = Vtiger_Cache::get('field-' . $module->getId(), $value);
1104
		}
1105
		if (!$fieldObject) {
1106
			$fieldObject = parent::getInstance($value, $module);
0 ignored issues
show
Bug introduced by
It seems like $module can also be of type false; however, parameter $moduleInstance of vtlib\Field::getInstance() does only seem to accept vtlib\Module, maybe add an additional type check? ( Ignorable by Annotation )

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

1106
			$fieldObject = parent::getInstance($value, /** @scrutinizer ignore-type */ $module);
Loading history...
1107
			if ($module) {
1108
				Vtiger_Cache::set('field-' . $module->getId(), $value, $fieldObject);
1109
			}
1110
		}
1111
		if ($fieldObject) {
1112
			return self::getInstanceFromFieldObject($fieldObject);
1113
		}
1114
		return false;
1115
	}
1116
1117
	/**
1118
	 * Returns instance of field.
1119
	 *
1120
	 * @param array|string $fieldInfo
1121
	 *
1122
	 * @return bool|\Vtiger_Field_Model|\vtlib\Field|null
1123
	 */
1124
	public static function getInstanceFromFilter($fieldInfo)
1125
	{
1126
		if (\is_string($fieldInfo)) {
1127
			$fieldInfo = array_combine(['field_name', 'module_name', 'source_field_name'], array_pad(explode(':', $fieldInfo), 3, false));
1128
		}
1129
		return static::getInstance($fieldInfo['field_name'], Vtiger_Module_Model::getInstance($fieldInfo['module_name']));
1130
	}
1131
1132
	/**
1133
	 * Function checks if the current Field is Read/Write.
1134
	 *
1135
	 * @return bool
1136
	 */
1137
	public function getProfileReadWritePermission()
1138
	{
1139
		return $this->getPermissions(false);
1140
	}
1141
1142
	/**
1143
	 * Function returns Client Side Validators name.
1144
	 *
1145
	 * @return <Array> [name=>Name of the Validator, params=>Extra Parameters]
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...
1146
	 */
1147
	public function getValidator()
1148
	{
1149
		$validator = [];
1150
		$fieldName = $this->getName();
1151
		switch ($fieldName) {
1152
			case 'birthday':
1153
				$funcName = ['name' => 'lessThanToday'];
1154
				$validator[] = $funcName;
1155
				break;
1156
			case 'targetenddate':
1157
			case 'actualenddate':
1158
			case 'enddate':
1159
				$funcName = ['name' => 'greaterThanDependentField',
1160
					'params' => ['startdate'], ];
1161
				$validator[] = $funcName;
1162
				break;
1163
			case 'startdate':
1164
				if ('Project' === $this->getModule()->get('name')) {
1165
					$params = ['targetenddate'];
1166
				} else {
1167
					//for project task
1168
					$params = ['enddate'];
1169
				}
1170
				$funcName = ['name' => 'lessThanDependentField',
1171
					'params' => $params, ];
1172
				$validator[] = $funcName;
1173
				break;
1174
			case 'expiry_date':
1175
			case 'due_date':
1176
				$funcName = ['name' => 'greaterThanDependentField',
1177
					'params' => ['start_date'], ];
1178
				$validator[] = $funcName;
1179
				break;
1180
			case 'sales_end_date':
1181
				$funcName = ['name' => 'greaterThanDependentField',
1182
					'params' => ['sales_start_date'], ];
1183
				$validator[] = $funcName;
1184
				break;
1185
			case 'sales_start_date':
1186
				$funcName = ['name' => 'lessThanDependentField',
1187
					'params' => ['sales_end_date'], ];
1188
				$validator[] = $funcName;
1189
				break;
1190
			case 'qty_per_unit':
1191
			case 'qtyindemand':
1192
			case 'hours':
1193
			case 'days':
1194
				$funcName = ['name' => 'PositiveNumber'];
1195
				$validator[] = $funcName;
1196
				break;
1197
			case 'employees':
1198
				$funcName = ['name' => 'WholeNumber'];
1199
				$validator[] = $funcName;
1200
				break;
1201 29
			case 'related_to':
1202
				$funcName = ['name' => 'ReferenceField'];
1203 29
				$validator[] = $funcName;
1204
				break;
1205
			//SRecurringOrders field sepecial validators
1206
			case 'end_period':
1207
				$funcName1 = ['name' => 'greaterThanDependentField',
1208
					'params' => ['start_period'], ];
1209
				$validator[] = $funcName1;
1210
				$funcName2 = ['name' => 'lessThanDependentField',
1211
					'params' => ['duedate'], ];
1212
				$validator[] = $funcName2;
1213
1214
			// no break
1215
			case 'start_period':
1216
				$funcName = ['name' => 'lessThanDependentField',
1217
					'params' => ['end_period'], ];
1218
				$validator[] = $funcName;
1219
				break;
1220
			default:
1221
				break;
1222
		}
1223
		return $validator;
1224
	}
1225
1226 11
	/**
1227
	 * Function to retrieve display value in edit view.
1228 11
	 *
1229
	 * @param mixed               $value
1230
	 * @param Vtiger_Record_Model $recordModel
1231
	 *
1232
	 * @return mixed
1233
	 */
1234
	public function getEditViewDisplayValue($value, $recordModel = false)
1235
	{
1236
		return $this->getUITypeModel()->getEditViewDisplayValue($value, $recordModel);
0 ignored issues
show
Bug introduced by
It seems like $recordModel can also be of type false; however, parameter $recordModel of Vtiger_Base_UIType::getEditViewDisplayValue() does only seem to accept Vtiger_Record_Model, maybe add an additional type check? ( Ignorable by Annotation )

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

1236
		return $this->getUITypeModel()->getEditViewDisplayValue($value, /** @scrutinizer ignore-type */ $recordModel);
Loading history...
1237
	}
1238
1239
	/**
1240
	 * Function to retrieve user value in edit view.
1241
	 *
1242
	 * @param mixed               $value
1243
	 * @param Vtiger_Record_Model $recordModel
1244
	 *
1245
	 * @return mixed
1246
	 */
1247
	public function getEditViewValue($value, $recordModel = false)
1248
	{
1249
		return $this->getUITypeModel()->getEditViewValue($value, $recordModel);
0 ignored issues
show
Bug introduced by
It seems like $recordModel can also be of type false; however, parameter $recordModel of Vtiger_Base_UIType::getEditViewValue() does only seem to accept Vtiger_Record_Model, maybe add an additional type check? ( Ignorable by Annotation )

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

1249
		return $this->getUITypeModel()->getEditViewValue($value, /** @scrutinizer ignore-type */ $recordModel);
Loading history...
1250
	}
1251
1252
	/**
1253
	 * Function to get Display value for RelatedList.
1254
	 *
1255
	 * @param string $value
1256
	 *
1257
	 * @return string
1258
	 */
1259
	public function getRelatedListDisplayValue($value)
1260
	{
1261
		return $this->getUITypeModel()->getRelatedListDisplayValue($value);
1262 21
	}
1263
1264 21
	/**
1265
	 * Function to get Default Field Value.
1266
	 *
1267
	 * @throws \Exception
1268
	 *
1269
	 * @return mixed
1270
	 */
1271
	public function getDefaultFieldValue()
1272 18
	{
1273
		return $this->getUITypeModel()->getDefaultValue();
1274 18
	}
1275
1276 18
	/**
1277
	 * Function whcih will get the databse insert value format from user format.
1278
	 *
1279 16
	 * @param type  $value       in user format
1280
	 * @param mixed $recordModel
1281 16
	 *
1282
	 * @return type
1283
	 */
1284
	public function getDBValue($value, $recordModel = false)
1285
	{
1286
		return $this->getUITypeModel()->getDBValue($value, $recordModel);
0 ignored issues
show
Bug introduced by
It seems like $recordModel can also be of type false; however, parameter $recordModel of Vtiger_Base_UIType::getDBValue() does only seem to accept Vtiger_Record_Model, maybe add an additional type check? ( Ignorable by Annotation )

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

1286
		return $this->getUITypeModel()->getDBValue($value, /** @scrutinizer ignore-type */ $recordModel);
Loading history...
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...
1287
	}
1288
1289
	/**
1290
	 * Function to get visibilty permissions of a Field.
1291
	 *
1292
	 * @param bool $readOnly
1293
	 *
1294
	 * @return bool
1295
	 */
1296 16
	public function getPermissions($readOnly = true)
1297
	{
1298 16
		return \App\Field::getFieldPermission($this->getModuleId(), $this->getName(), $readOnly);
1299
	}
1300
1301
	public function __update()
1302
	{
1303
		$dbCommand = \App\Db::getInstance()->createCommand();
1304
		1 === $this->get('generatedtype') ? $generatedType = 1 : $generatedType = 2;
1305
		$dbCommand->update('vtiger_field', ['typeofdata' => $this->get('typeofdata'), 'presence' => $this->get('presence'), 'quickcreate' => $this->get('quickcreate'),
1306
			'masseditable' => $this->get('masseditable'), 'header_field' => $this->get('header_field'), 'maxlengthtext' => $this->get('maxlengthtext'),
1307
			'maxwidthcolumn' => $this->get('maxwidthcolumn'), 'tabindex' => $this->get('tabindex'), 'defaultvalue' => $this->get('defaultvalue'), 'summaryfield' => $this->get('summaryfield'),
1308
			'displaytype' => $this->get('displaytype'), 'helpinfo' => $this->get('helpinfo'), 'generatedtype' => $generatedType,
1309
			'fieldparams' => $this->get('fieldparams'), 'quickcreatesequence' => $this->get('quicksequence'), 'icon' => $this->get('icon'),
1310
		], ['fieldid' => $this->get('id')])->execute();
1311
		if ($anonymizationTarget = $this->get('anonymizationTarget')) {
1312
			$anonymizationTarget = \App\Json::encode($anonymizationTarget);
1313
			$execute = $dbCommand->update('s_#__fields_anonymization', ['anonymization_target' => $anonymizationTarget], ['field_id' => $this->getId()])->execute();
1314
			if (!$execute) {
1315
				$dbCommand->insert('s_#__fields_anonymization', ['field_id' => $this->getId(), 'anonymization_target' => $anonymizationTarget])->execute();
1316
			}
1317
		} else {
1318
			$dbCommand->delete('s_#__fields_anonymization', ['field_id' => $this->getId()])->execute();
1319
		}
1320
		App\Cache::clear();
1321
	}
1322
1323
	public function updateTypeofDataFromMandatory($mandatoryValue = 'O')
1324
	{
1325
		$mandatoryValue = strtoupper($mandatoryValue);
1326
		$supportedMandatoryLiterals = ['O', 'M'];
1327
		if (!\in_array($mandatoryValue, $supportedMandatoryLiterals)) {
1328
			return;
1329
		}
1330
		$typeOfData = $this->get('typeofdata');
1331
		$components = explode('~', $typeOfData);
0 ignored issues
show
Bug introduced by
It seems like $typeOfData can also be of type null; however, parameter $string of explode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

1331
		$components = explode('~', /** @scrutinizer ignore-type */ $typeOfData);
Loading history...
1332
		$components[1] = $mandatoryValue;
1333
		$this->set('typeofdata', implode('~', $components));
1334
1335
		return $this;
1336
	}
1337
1338 10
	public function isCustomField()
1339
	{
1340 10
		return 2 == $this->generatedtype;
1341
	}
1342
1343
	public function hasDefaultValue()
1344
	{
1345
		return !empty($this->defaultvalue);
1346
	}
1347
1348
	public function isActiveField()
1349
	{
1350
		return \in_array($this->get('presence'), [0, 2]);
1351
	}
1352
1353
	public function isMassEditable()
1354
	{
1355
		return 1 == $this->masseditable;
1356
	}
1357
1358
	public function isHeaderField()
1359
	{
1360
		return !empty($this->header_field);
1361
	}
1362
1363
	/**
1364
	 * Gets header field data.
1365
	 *
1366
	 * @throws \App\Exceptions\AppException
1367
	 *
1368
	 * @return mixed
1369
	 */
1370
	public function getHeaderField()
1371
	{
1372
		return !empty($this->header_field) ? \App\Json::decode($this->header_field) : [];
1373
	}
1374
1375
	/**
1376
	 * Gets header field value.
1377
	 *
1378
	 * @param string $type
1379
	 * @param mixed  $default
1380
	 *
1381
	 * @throws \App\Exceptions\AppException
1382
	 *
1383
	 * @return mixed
1384
	 */
1385
	public function getHeaderValue(string $type, $default = '')
1386
	{
1387
		return $this->getHeaderField()[$type] ?? $default;
1388
	}
1389
1390
	/**
1391
	 * Function which will check if empty piclist option should be given.
1392
	 *
1393
	 * @return bool
1394
	 */
1395
	public function isEmptyPicklistOptionAllowed()
1396 17
	{
1397
		if (method_exists($this->getUITypeModel(), 'isEmptyPicklistOptionAllowed')) {
1398 17
			return $this->getUITypeModel()->isEmptyPicklistOptionAllowed();
1399 17
		}
1400 17
		return true;
1401 17
	}
1402 16
1403
	/**
1404
	 * Check if it is a tree field.
1405 1
	 *
1406
	 * @return bool
1407
	 */
1408
	public function isTreeField(): bool
1409
	{
1410
		return \in_array($this->getFieldDataType(), ['tree', 'categoryMultipicklist']);
1411
	}
1412
1413
	public function isReferenceField()
1414
	{
1415
		return \in_array($this->getFieldDataType(), self::$referenceTypes);
1416
	}
1417
1418
	public function isOwnerField()
1419
	{
1420
		return (self::OWNER_TYPE == $this->getFieldDataType()) ? true : false;
1421
	}
1422
1423 19
	/**
1424
	 * Is summation field.
1425 19
	 *
1426 19
	 * @return bool
1427 19
	 */
1428
	public function isCalculateField()
1429
	{
1430 19
		return $this->isCalculateField && !$this->get('fromOutsideList') && (\in_array($this->getUIType(), [71, 7, 317, 8]) || \in_array($this->getFieldDataType(), ['integer', 'double']));
1431 19
	}
1432 19
1433
	/**
1434
	 * Function returns field instance for field ID.
1435
	 *
1436
	 * @param int $fieldId
1437
	 * @param int $moduleTabId
1438
	 *
1439
	 * @return \Vtiger_Field_Model
1440
	 */
1441
	public static function getInstanceFromFieldId($fieldId, $moduleTabId = false)
1442
	{
1443 19
		$fieldModel = Vtiger_Cache::get('FieldModel', $fieldId);
1444
		if ($fieldModel) {
1445
			return $fieldModel;
1446
		}
1447
		$field = \App\Field::getFieldInfo($fieldId);
1448
		$className = Vtiger_Loader::getComponentClassName('Model', 'Field', \App\Module::getModuleName($field['tabid']));
1449
		$fieldModel = new $className();
1450
		$fieldModel->initialize($field, $field['tabid']);
1451
		Vtiger_Cache::set('FieldModel', $fieldId, $fieldModel);
1452
		return $fieldModel;
1453 21
	}
1454
1455 21
	public function getWithDefaultValue()
1456 21
	{
1457
		$defaultValue = $this->getDefaultFieldValue();
1458
		$recordValue = $this->get('fieldvalue');
1459 21
		if (empty($recordValue) && !$defaultValue) {
1460 21
			$this->set('fieldvalue', $defaultValue);
1461 2
		}
1462
		return $this;
1463 19
	}
1464 19
1465
	/**
1466
	 * Get field params.
1467 19
	 *
1468 19
	 * @return array
1469 19
	 */
1470 8
	public function getFieldParams()
1471 11
	{
1472 2
		if (!\is_array($this->get('fieldparams')) && \App\Json::isJson($this->get('fieldparams'))) {
1473 1
			return \App\Json::decode($this->get('fieldparams'));
1474
		}
1475 1
		return $this->get('fieldparams') ?: [];
1476 9
	}
1477
1478
	/**
1479
	 * Get field icon.
1480
	 *
1481 9
	 * @param string $place
1482 2
	 *
1483
	 * @return array
1484
	 */
1485 2
	public function getIcon(string $place = ''): array
1486 7
	{
1487 3
		$icon = [];
1488 4
		if (\is_array($this->get('icon'))) {
1489 4
			$icon = $this->get('icon');
1490
		} elseif (\App\Json::isJson($this->get('icon'))) {
1491
			$icon = \App\Json::decode($this->get('icon'));
1492
		}
1493
		if ($place && isset($icon['place']) && !\in_array($place, $icon['place'])) {
1494
			$icon = [];
1495
		}
1496
		return $icon;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $icon 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...
1497
	}
1498
1499
	/**
1500
	 * Get anonymization target.
1501
	 *
1502
	 * @see \App\Anonymization::getTypes()
1503
	 *
1504
	 * @return int[]
1505
	 */
1506
	public function getAnonymizationTarget(): array
1507
	{
1508
		if (\is_string($this->get('anonymizationTarget'))) {
1509
			$this->set('anonymizationTarget', \App\Json::decode($this->get('anonymizationTarget')));
1510
		}
1511
		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...
1512
	}
1513
1514
	/**
1515
	 * Get maximum value.
1516
	 *
1517
	 * @return string|null
1518
	 */
1519
	public function getMaxValue(): ?string
1520
	{
1521
		if (($maximumLength = $this->get('maximumlength')) && false !== strpos($maximumLength, ',')) {
1522
			$maximumLength = explode(',', $maximumLength)[1];
1523
		}
1524
		return $maximumLength;
1525
	}
1526
1527
	public function isActiveSearchView()
1528
	{
1529
		if ($this->get('fromOutsideList') || $this->get('searchLockedFields')) {
1530
			return false;
1531
		}
1532
		return $this->getUITypeModel()->isActiveSearchView();
1533
	}
1534
1535
	/**
1536
	 * Empty value search in view.
1537
	 *
1538
	 * @return bool
1539
	 */
1540
	public function searchLockedEmptyFields(): bool
1541
	{
1542
		return empty($this->get('searchLockedEmptyFields'));
1543
	}
1544
1545
	/**
1546
	 * Function returns info about field structure in database.
1547
	 *
1548
	 * @param bool $returnString
1549
	 *
1550
	 * @return array|string
1551
	 */
1552
	public function getDBColumnType($returnString = true)
1553
	{
1554
		$db = \App\Db::getInstance();
1555
		$tableSchema = $db->getSchema()->getTableSchema($this->getTableName(), true);
1556
		if (empty($tableSchema)) {
1557
			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...
1558
		}
1559
		$columnSchema = $tableSchema->getColumn($this->getColumnName());
1560
		$data = get_object_vars($columnSchema);
1561
		if ($returnString) {
1562
			$string = $data['type'];
1563
			if ($data['size']) {
1564
				if ('decimal' === $data['type']) {
1565
					$string .= '(' . $data['size'] . ',' . $data['scale'] . ')';
1566
				} else {
1567
					$string .= '(' . $data['size'] . ')';
1568
				}
1569
			}
1570
			return $string;
1571
		}
1572
		return $data;
1573
	}
1574
1575
	/**
1576
	 * Function to get range of values.
1577
	 *
1578
	 * @throws \App\Exceptions\AppException
1579
	 *
1580
	 * @return string|null
1581
	 */
1582
	public function getRangeValues()
1583
	{
1584
		$uiTypeModel = $this->getUITypeModel();
1585
		if (method_exists($uiTypeModel, 'getRangeValues')) {
1586
			return $uiTypeModel->getRangeValues();
1587
		}
1588
		$allowedTypes = $uiTypeModel->getAllowedColumnTypes();
1589
		if (null === $allowedTypes) {
0 ignored issues
show
introduced by
The condition null === $allowedTypes is always false.
Loading history...
1590
			return;
1591
		}
1592
		$data = $this->getDBColumnType(false);
1593
		if (!\in_array($data['type'], $allowedTypes)) {
1594
			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

1594
			throw new \App\Exceptions\AppException('ERR_NOT_ALLOWED_TYPE||' . $data['type'] . '||' . /** @scrutinizer ignore-type */ print_r($allowedTypes, true));
Loading history...
1595
		}
1596
		preg_match('/^([\w\-]+)/i', $data['dbType'], $matches);
1597
		$type = $matches[1] ?? $data['type'];
1598
		$uitype = $this->getUIType();
1599
		if (isset(self::$uiTypeMaxLength[$uitype])) {
1600
			$range = self::$uiTypeMaxLength[$uitype];
1601
		} elseif (isset(self::$typesMaxLength[$type])) {
1602
			$range = self::$typesMaxLength[$type];
1603
		} else {
1604
			switch ($type) {
1605
				case 'binary':
1606
				case 'string':
1607
				case 'varchar':
1608
				case 'varbinary':
1609
					$range = (int) $data['size'];
1610
					break;
1611
				case 'bigint':
1612
				case 'mediumint':
1613
					throw new \App\Exceptions\AppException("ERR_NOT_ALLOWED_TYPE||$type||integer,smallint,tinyint");
1614
				case 'integer':
1615
				case 'int':
1616
					if ($data['unsigned']) {
1617
						$range = '4294967295';
1618
					} else {
1619
						$range = '-2147483648,2147483647';
1620
					}
1621
					break;
1622
				case 'smallint':
1623
					if ($data['unsigned']) {
1624
						$range = '65535';
1625
					} else {
1626
						$range = '-32768,32767';
1627
					}
1628
					break;
1629
				case 'tinyint':
1630
					if ($data['unsigned']) {
1631
						$range = '255';
1632
					} else {
1633
						$range = '-128,127';
1634
					}
1635
					break;
1636
				case 'decimal':
1637
					$range = 10 ** (((int) $data['size']) - ((int) $data['scale'])) - 1;
1638
					break;
1639
				default:
1640
					$range = null;
1641
					break;
1642
			}
1643
		}
1644
		return $range;
1645
	}
1646
1647
	/**
1648
	 * Return allowed query operators for field.
1649
	 *
1650
	 * @return string[]
1651
	 */
1652
	public function getQueryOperators(): array
1653
	{
1654
		$operators = $this->getUITypeModel()->getQueryOperators();
1655
		$oper = [];
1656
		foreach ($operators as $op) {
1657
			$label = '';
1658
			if (isset(\App\Condition::STANDARD_OPERATORS[$op])) {
1659
				$label = \App\Condition::STANDARD_OPERATORS[$op];
1660
			}
1661
			if (isset(\App\Condition::DATE_OPERATORS[$op])) {
1662
				$label = \App\Condition::DATE_OPERATORS[$op]['label'];
1663
			}
1664
			$oper[$op] = $label;
1665
		}
1666
		return $oper;
1667
	}
1668
1669
	/**
1670
	 * Return allowed record operators for field.
1671
	 *
1672
	 * @return string[]
1673
	 */
1674
	public function getRecordOperators(): array
1675
	{
1676
		$operators = $this->getUITypeModel()->getRecordOperators();
1677
		$oper = [];
1678
		foreach ($operators as $op) {
1679
			$label = '';
1680
			if (isset(\App\Condition::STANDARD_OPERATORS[$op])) {
1681
				$label = \App\Condition::STANDARD_OPERATORS[$op];
1682
			}
1683
			if (isset(\App\Condition::DATE_OPERATORS[$op])) {
1684
				$label = \App\Condition::DATE_OPERATORS[$op]['label'];
1685
			}
1686
			$oper[$op] = $label;
1687
		}
1688
		return $oper;
1689
	}
1690
1691
	/**
1692
	 * Returns template for operator.
1693
	 *
1694
	 * @param string $operator
1695
	 *
1696
	 * @return string
1697
	 */
1698
	public function getOperatorTemplateName(string $operator)
1699
	{
1700
		if (\in_array($operator, App\Condition::OPERATORS_WITHOUT_VALUES + array_keys(App\Condition::DATE_OPERATORS))) {
1701
			return;
1702
		}
1703
		return $this->getUITypeModel()->getOperatorTemplateName($operator);
1704
	}
1705
1706
	/**
1707
	 * Function to get the field model for condition builder.
1708
	 *
1709
	 * @param string $operator
1710
	 *
1711
	 * @return self
1712
	 */
1713
	public function getConditionBuilderField(string $operator): self
1714
	{
1715
		return $this->getUITypeModel()->getConditionBuilderField($operator);
1716
	}
1717
1718
	/**
1719
	 * Sets data.
1720
	 *
1721
	 * @param array $data
1722
	 *
1723
	 * @return self
1724
	 */
1725
	public function setData(array $data = [])
1726
	{
1727
		foreach ($data as $key => $value) {
1728
			$this->set($key, $value);
1729
		}
1730
		return $this;
1731
	}
1732
1733
	/**
1734
	 * TabIndex last sequence number.
1735
	 *
1736
	 * @var int
1737
	 */
1738
	public static $tabIndexLastSeq = 0;
1739
	/**
1740
	 * TabIndex default sequence number.
1741
	 *
1742
	 * @var int
1743
	 */
1744
	public static $tabIndexDefaultSeq = 0;
1745
1746
	/**
1747
	 * Get TabIndex.
1748
	 *
1749
	 * @return int
1750
	 */
1751
	public function getTabIndex(): int
1752
	{
1753
		$tabindex = 0;
1754
		if (0 !== $this->get('tabindex')) {
1755
			$tabindex = $this->get('tabindex');
1756
		} elseif (self::$tabIndexLastSeq) {
1757
			$tabindex = self::$tabIndexLastSeq;
1758
		}
1759
		return $tabindex + self::$tabIndexDefaultSeq;
1760
	}
1761
}
1762