Test Setup Failed
Push — developer ( a4c937...ab86ea )
by Radosław
46:34 queued 28:22
created

Vtiger_Field_Model::getAcceptableLengthRange()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
eloc 12
c 0
b 0
f 0
dl 0
loc 16
rs 9.8666
ccs 0
cts 0
cp 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 array $uiTypeMaxLength = [
29
		106 => '3,64',
30
		120 => 65535,
31
		156 => '3',
32
		360 => '0,99999999'
33
	];
34
35
	/** @var int[] Field maximum length by db type. */
36
	public static array $typesMaxLength = [
37
		'tinytext' => 255,
38
		'text' => 65535,
39
		'mediumtext' => 16777215,
40
		'longtext' => 4294967295,
41
		'blob' => 65535,
42
		'mediumblob' => 16777215,
43
		'longblob' => 4294967295,
44
	];
45
46
	/** @var string Field data type. */
47
	public $fieldDataType;
48
49
	/** @var string[] List of modules the field referenced to. */
50
	public $referenceList;
51
52
	/** @var string[] Picklist values only for custom fields;. */
53
	public $picklistValues;
54
55
	/**
56
	 * TabIndex last sequence number.
57
	 *
58
	 * @var int
59
	 */
60
	public static $tabIndexLastSeq = 0;
61 118
	/**
62
	 * TabIndex default sequence number.
63 118
	 *
64 118
	 * @var int
65
	 */
66 4
	public static $tabIndexDefaultSeq = 0;
67
68
	/** @var Vtiger_Field_Model[] Cache by field id */
69
	protected static $instanceCacheById = [];
70
71
	/** @var Vtiger_Field_Model[][] Cache by module id and field id */
72
	protected static $instanceCacheByName = [];
73
74
	/** @var array Module field info. */
75
	protected $fieldInfo;
76
77 30
	/** @var string Field type. */
78
	protected $fieldType;
79 30
80
	/** @var string Field data type short. */
81 30
	protected $fieldDataTypeShort;
82
	protected $uitype_instance;
83
84
	/** @var bool Is calculate field */
85
	protected $isCalculateField = true;
86
87
	/** @var bool|null Field visibility permissions */
88
	protected $permissions;
89 64
90
	/** @var Vtiger_Base_UIType Vtiger_Base_UIType or UI Type specific model instance */
91 64
	protected $uitypeModel;
92
93
	/** @var bool[] Permissions cache */
94
	protected $permissionsCache = [];
95
96
	public function __update()
97
	{
98
		$dbCommand = \App\Db::getInstance()->createCommand();
99 67
		1 === $this->get('generatedtype') ? $generatedType = 1 : $generatedType = 2;
100
		$dbCommand->update('vtiger_field', ['typeofdata' => $this->get('typeofdata'), 'presence' => $this->get('presence'), 'quickcreate' => $this->get('quickcreate'),
101 67
			'masseditable' => $this->get('masseditable'), 'header_field' => $this->get('header_field'), 'maxlengthtext' => $this->get('maxlengthtext'),
102
			'maxwidthcolumn' => $this->get('maxwidthcolumn'), 'tabindex' => $this->get('tabindex'), 'defaultvalue' => $this->get('defaultvalue'), 'summaryfield' => $this->get('summaryfield'),
103
			'displaytype' => $this->get('displaytype'), 'helpinfo' => $this->get('helpinfo'), 'generatedtype' => $generatedType,
104
			'fieldparams' => $this->get('fieldparams'), 'quickcreatesequence' => $this->get('quicksequence'), 'icon' => $this->get('icon'), 'fieldlabel' => $this->get('label'), 'maximumlength' => $this->get('maximumlength')
105
		], ['fieldid' => $this->get('id')])->execute();
106
		if ($anonymizationTarget = $this->get('anonymizationTarget')) {
107
			$anonymizationTarget = \App\Json::encode($anonymizationTarget);
108
			$exists = (new \App\Db\Query())->from('s_#__fields_anonymization')->where(['field_id' => $this->getId()])->exists();
109 53
			if ($exists) {
110
				$dbCommand->update('s_#__fields_anonymization', ['anonymization_target' => $anonymizationTarget], ['field_id' => $this->getId()])->execute();
111 53
			} else {
112
				$dbCommand->insert('s_#__fields_anonymization', ['field_id' => $this->getId(), 'anonymization_target' => $anonymizationTarget])->execute();
113
			}
114
		} else {
115
			$dbCommand->delete('s_#__fields_anonymization', ['field_id' => $this->getId()])->execute();
116
		}
117
		$this->afterFieldChange();
118
	}
119 6
120
	/**
121 6
	 * Initialize.
122
	 *
123
	 * @param string     $module
124
	 * @param array      $data
125
	 * @param mixed|null $name
126
	 *
127
	 * @return \Vtiger_Field_Model
128
	 */
129 5813
	public static function init($module = 'Vtiger', $data = [], $name = '')
130
	{
131 5813
		if (\App\Module::getModuleId($module)) {
132
			$moduleModel = Vtiger_Module_Model::getInstance($module);
133
		} else {
134
			$modelClassName = \Vtiger_Loader::getComponentClassName('Model', 'Module', $module);
135
			$moduleModel = new $modelClassName();
136
		}
137
		$modelClassName = \Vtiger_Loader::getComponentClassName('Model', 'Field', $module);
138
		$instance = new $modelClassName();
139 5836
		$instance->setModule($moduleModel);
140
		$instance->setData(array_merge([
141 5836
			'uitype' => 1,
142
			'column' => $name,
143
			'name' => $name,
144
			'label' => $name,
145
			'displaytype' => 1,
146
			'typeofdata' => 'V~O',
147
			'presence' => 0,
148
			'isReadOnly' => false,
149 37
			'isEditableReadOnly' => false,
150
		], $data));
151 37
		return $instance;
152
	}
153
154
	/**
155
	 * Function to get the value of a given property.
156
	 *
157
	 * @param string $propertyName
158
	 *
159
	 * @return mixed|null
160
	 */
161
	public function get(string $propertyName)
162
	{
163
		if (property_exists($this, $propertyName)) {
164
			return $this->{$propertyName};
165
		}
166
		return null;
167
	}
168
169 16
	/**
170
	 * Function which sets value for given name.
171 16
	 *
172 3
	 * @param string $name  - name for which value need to be assinged
173 3
	 * @param mixed  $value - values that need to be assigned
174
	 *
175
	 * @return Vtiger_Field_Model
176 3
	 */
177
	public function set(string $name, $value)
178
	{
179 3
		$this->{$name} = $value;
180
		return $this;
181 16
	}
182
183
	/**
184
	 * Function to get the Field Id.
185
	 *
186
	 * @return int
187
	 */
188
	public function getId()
189
	{
190
		return $this->id;
191
	}
192
193
	/**
194
	 * Get name.
195
	 *
196
	 * @return string
197
	 */
198
	public function getName()
199
	{
200
		return $this->name;
201 5785
	}
202
203 5785
	/**
204
	 * Get full name.
205
	 *
206
	 * @return string
207
	 */
208
	public function getFullName()
209
	{
210
		return $this->get('source_field_name') ? "{$this->getName()}:{$this->getModuleName()}:{$this->get('source_field_name')}" : $this->getName();
211 11
	}
212
213 11
	/**
214
	 * Get full label translation.
215
	 *
216
	 * @param Vtiger_Module_Model|null $module
217
	 *
218
	 * @return string
219
	 */
220
	public function getFullLabelTranslation(?Vtiger_Module_Model $module = null): string
221 89
	{
222
		$translation = '';
223 89
		if ($this->get('source_field_name') && !$this->get('isLabelCustomized')) {
224 69
			if (!$module) {
225 69
				throw new \App\Exceptions\AppException('ERR_ARGUMENT_DOES_NOT_EXIST');
226
			}
227
			$translation = \App\Language::translate($module->getFieldByName($this->get('source_field_name'))->getFieldLabel(), $module->getName()) . ' - ';
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

227
			$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...
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

227
			$translation = \App\Language::translate($module->getFieldByName($this->get('source_field_name'))->getFieldLabel(), /** @scrutinizer ignore-type */ $module->getName()) . ' - ';
Loading history...
228 69
		}
229
		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

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

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

1069
		$this->fieldInfo['label'] = App\Language::translate($this->get('label'), $this->getModuleName(), /** @scrutinizer ignore-type */ false, false);
Loading history...
1070
		$fieldDataType = $this->getFieldDataType();
1071
		$this->fieldInfo['type'] = $fieldDataType;
1072
		$this->fieldInfo['mandatory'] = $this->isMandatory();
1073
		$this->fieldInfo['defaultvalue'] = $this->getDefaultFieldValue();
1074
		$this->fieldInfo['presence'] = $this->isActiveField();
1075
		$this->fieldInfo['quickcreate'] = $this->isQuickCreateEnabled();
1076
		$this->fieldInfo['masseditable'] = $this->isMassEditable();
1077
		$this->fieldInfo['header_field'] = $this->getHeaderField();
1078
		$this->fieldInfo['maxlengthtext'] = $this->get('maxlengthtext');
1079
		$this->fieldInfo['maximumlength'] = $this->get('maximumlength');
1080
		$this->fieldInfo['maxwidthcolumn'] = $this->get('maxwidthcolumn');
1081
		$this->fieldInfo['tabindex'] = $this->get('tabindex');
1082
		$this->fieldInfo['fieldtype'] = explode('~', $this->get('typeofdata'))[0] ?? '';
1083
		$currentUser = \App\User::getCurrentUserModel();
1084
		switch ($fieldDataType) {
1085
			case 'picklist':
1086
			case 'multipicklist':
1087
			case 'multipicklistTags':
1088
			case 'multiowner':
1089
			case 'multiReferenceValue':
1090
			case 'inventoryLimit':
1091
			case 'languages':
1092
			case 'currencyList':
1093
			case 'fileLocationType':
1094
			case 'taxes':
1095
			case 'multiListFields':
1096
			case 'mailScannerFields':
1097
			case 'country':
1098
				$this->fieldInfo['picklistvalues'] = $this->getPicklistValues() ?: [];
1099
				break;
1100
			case 'date':
1101
			case 'datetime':
1102
				$this->fieldInfo['date-format'] = $currentUser->getDetail('date_format');
1103
				break;
1104
			case 'time':
1105
				$this->fieldInfo['time-format'] = $currentUser->getDetail('hour_format');
1106
				break;
1107
			case 'currency':
1108
				$this->fieldInfo['currency_symbol'] = $currentUser->getDetail('currency_symbol');
1109
				$this->fieldInfo['decimal_separator'] = $currentUser->getDetail('currency_decimal_separator');
1110
				$this->fieldInfo['group_separator'] = $currentUser->getDetail('currency_grouping_separator');
1111
				break;
1112
			case 'owner':
1113
			case 'userCreator':
1114
			case 'sharedOwner':
1115
				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

1115
				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...
1116
					$userList = \App\Fields\Owner::getInstance($this->getModuleName(), $currentUser)->getAccessibleUsers('', $fieldDataType);
1117
					$groupList = \App\Fields\Owner::getInstance($this->getModuleName(), $currentUser)->getAccessibleGroups('', $fieldDataType);
1118
					$pickListValues = [];
1119
					$pickListValues[\App\Language::translate('LBL_USERS', $this->getModuleName())] = $userList;
1120
					$pickListValues[\App\Language::translate('LBL_GROUPS', $this->getModuleName())] = $groupList;
1121
					$this->fieldInfo['picklistvalues'] = $pickListValues;
1122
					if (App\Config::performance('SEARCH_OWNERS_BY_AJAX')) {
1123
						$this->fieldInfo['searchOperator'] = 'e';
1124
					}
1125
				} else {
1126
					if ('owner' === $fieldDataType) {
1127
						$this->fieldInfo['searchOperator'] = 'e';
1128
					}
1129
				}
1130
				break;
1131
			case 'modules':
1132
				foreach ($this->getModulesListValues() as $module) {
1133
					$modulesList[$module['name']] = $module['label'];
1134
				}
1135
				$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 1132. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
1136
				break;
1137
			case 'categoryMultipicklist':
1138
			case 'tree':
1139
				$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

1139
				$this->fieldInfo['picklistvalues'] = \App\Fields\Tree::getPicklistValue(/** @scrutinizer ignore-type */ $this->getFieldParams(), $this->getModuleName());
Loading history...
1140
				$this->fieldInfo['treetemplate'] = $this->getFieldParams();
1141
				$this->fieldInfo['modulename'] = $this->getModuleName();
1142
				break;
1143
			case 'email':
1144
				if (\App\Config::security('EMAIL_FIELD_RESTRICTED_DOMAINS_ACTIVE') && !empty(\App\Config::security('EMAIL_FIELD_RESTRICTED_DOMAINS_VALUES'))) {
1145
					$validate = false;
1146
					if (empty(\App\Config::security('EMAIL_FIELD_RESTRICTED_DOMAINS_ALLOWED')) || \in_array($this->getModuleName(), \App\Config::security('EMAIL_FIELD_RESTRICTED_DOMAINS_ALLOWED'))) {
1147
						$validate = true;
1148
					}
1149
					if (\in_array($this->getModuleName(), \App\Config::security('EMAIL_FIELD_RESTRICTED_DOMAINS_EXCLUDED'))) {
1150
						$validate = false;
1151
					}
1152
					if ($validate) {
1153
						$this->fieldInfo['restrictedDomains'] = \App\Config::security('EMAIL_FIELD_RESTRICTED_DOMAINS_VALUES');
1154
					}
1155
				}
1156
				break;
1157
			default:
1158
				break;
1159
		}
1160
1161
		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...
1162
	}
1163
1164
	/**
1165
	 * Set field info.
1166
	 *
1167
	 * @param array $fieldInfo
1168
	 *
1169
	 * @return $this
1170
	 */
1171
	public function setFieldInfo(array $fieldInfo)
1172
	{
1173
		$this->fieldInfo = $fieldInfo;
1174
1175
		return $this;
1176
	}
1177
1178
	/**
1179
	 * Function to get the advanced filter option names by Field type.
1180
	 *
1181
	 * @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...
1182
	 */
1183
	public static function getAdvancedFilterOpsByFieldType()
1184
	{
1185
		return [
1186
			'V' => ['e', 'n', 's', 'ew', 'c', 'k', 'y', 'ny', 'om', 'wr', 'nwr'],
1187
			'N' => ['e', 'n', 'l', 'g', 'm', 'h', 'y', 'ny'],
1188
			'T' => ['e', 'n', 'l', 'g', 'm', 'h', 'bw', 'b', 'a', 'y', 'ny'],
1189
			'I' => ['e', 'n', 'l', 'g', 'm', 'h', 'y', 'ny'],
1190
			'C' => ['e', 'n', 'y', 'ny'],
1191
			'D' => ['e', 'n', 'bw', 'b', 'a', 'y', 'ny'],
1192
			'DT' => ['e', 'n', 'bw', 'b', 'a', 'y', 'ny'],
1193
			'NN' => ['e', 'n', 'l', 'g', 'm', 'h', 'y', 'ny'],
1194
			'E' => ['e', 'n', 's', 'ew', 'c', 'k', 'y', 'ny'],
1195
		];
1196
	}
1197
1198
	/**
1199
	 * Function to retrieve field model for specific block and module.
1200
	 *
1201 29
	 * @param vtlib\ModuleBasic $moduleModel
1202
	 *
1203 29
	 * @return Vtiger_Field_Model[][]
1204
	 */
1205
	public static function getAllForModule(vtlib\ModuleBasic $moduleModel)
1206
	{
1207
		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

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

1208
			return \App\Cache::staticGet('ModuleFields', /** @scrutinizer ignore-type */ $moduleModel->id);
Loading history...
1209
		}
1210
		$fieldModelList = [];
0 ignored issues
show
Unused Code introduced by
The assignment to $fieldModelList is dead and can be removed.
Loading history...
1211
		$fieldObjects = parent::getAllForModule($moduleModel);
1212
		$fieldModelList = [];
1213
		if (!\is_array($fieldObjects)) {
0 ignored issues
show
introduced by
The condition is_array($fieldObjects) is always false.
Loading history...
1214
			$fieldObjects = [];
1215
		}
1216
		foreach ($fieldObjects as &$fieldObject) {
1217
			$fieldModel = self::getInstanceFromFieldObject($fieldObject);
1218
			$block = $fieldModel->get('block') ? $fieldModel->get('block')->id : 0;
1219
			$fieldModelList[$block][] = $fieldModel;
1220
			self::$instanceCacheById[$fieldModel->getId()] = $fieldModel;
1221
			self::$instanceCacheByName[$moduleModel->getId()][$fieldModel->getName()] = $fieldModel;
1222
		}
1223
		\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

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

1787
			throw new \App\Exceptions\AppException('ERR_NOT_ALLOWED_TYPE||' . $data['type'] . '||' . /** @scrutinizer ignore-type */ print_r($allowedTypes, true));
Loading history...
1788
		}
1789
		preg_match('/^([\w\-]+)/i', $data['dbType'], $matches);
1790
		$type = $matches[1] ?? $data['type'];
1791
		$uitype = $this->getUIType();
1792
		if (isset(self::$uiTypeMaxLength[$uitype])) {
1793
			$range = self::$uiTypeMaxLength[$uitype];
1794
		} elseif (isset(self::$typesMaxLength[$type])) {
1795
			$range = self::$typesMaxLength[$type];
1796
		} else {
1797
			switch ($type) {
1798
				case 'binary':
1799
				case 'string':
1800
				case 'varchar':
1801
				case 'varbinary':
1802
					$range = (int) $data['size'];
1803
					break;
1804
				case 'bigint':
1805
				case 'mediumint':
1806
					throw new \App\Exceptions\AppException("ERR_NOT_ALLOWED_TYPE||$type||integer,smallint,tinyint");
1807
				case 'integer':
1808
				case 'int':
1809
					if ($data['unsigned']) {
1810
						$range = '4294967295';
1811
					} else {
1812
						$range = '-2147483648,2147483647';
1813
					}
1814
					break;
1815
				case 'smallint':
1816
					if ($data['unsigned']) {
1817
						$range = '65535';
1818
					} else {
1819
						$range = '-32768,32767';
1820
					}
1821
					break;
1822
				case 'tinyint':
1823
					if ($data['unsigned']) {
1824
						$range = '255';
1825
					} else {
1826
						$range = '-128,127';
1827
					}
1828
					break;
1829
				case 'decimal':
1830
					$range = 10 ** (((int) $data['size']) - ((int) $data['scale'])) - 1;
1831
					break;
1832
				default:
1833
					$range = null;
1834
					break;
1835
			}
1836
		}
1837
		return $range;
1838
	}
1839
1840
	/**
1841
	 * Return allowed query operators for field.
1842
	 *
1843
	 * @return string[]
1844
	 */
1845
	public function getQueryOperatorLabels(): array
1846
	{
1847
		return \App\Condition::getOperatorLabels($this->getUITypeModel()->getQueryOperators());
1848
	}
1849
1850
	/**
1851
	 * Gets record operator labels.
1852
	 *
1853
	 * @return string[]
1854
	 */
1855
	public function getRecordOperatorLabels(): array
1856
	{
1857
		return \App\Condition::getOperatorLabels($this->getUITypeModel()->getRecordOperators());
1858
	}
1859
1860
	/**
1861
	 * Returns template for operator.
1862
	 *
1863
	 * @param string $operator
1864
	 *
1865
	 * @return string
1866
	 */
1867
	public function getOperatorTemplateName(string $operator)
1868
	{
1869
		if (\in_array($operator, App\Condition::OPERATORS_WITHOUT_VALUES)) {
1870
			return;
1871
		}
1872
		if (\in_array($operator, \App\Condition::FIELD_COMPARISON_OPERATORS)) {
1873
			return 'ConditionBuilder/FieldsListUitype.tpl';
1874
		}
1875
		return $this->getUITypeModel()->getOperatorTemplateName($operator);
1876
	}
1877
1878
	/**
1879
	 * Function to get the field model for condition builder.
1880
	 *
1881
	 * @param string $operator
1882
	 *
1883
	 * @return self
1884
	 */
1885
	public function getConditionBuilderField(string $operator): self
1886
	{
1887
		return $this->getUITypeModel()->getConditionBuilderField($operator);
1888
	}
1889
1890
	/**
1891
	 * Sets data.
1892
	 *
1893
	 * @param array $data
1894
	 *
1895
	 * @return self
1896
	 */
1897
	public function setData(array $data = [])
1898
	{
1899
		foreach ($data as $key => $value) {
1900
			$this->set($key, $value);
1901
		}
1902
		return $this;
1903
	}
1904
1905
	/**
1906
	 * Get TabIndex.
1907
	 *
1908
	 * @return int
1909
	 */
1910
	public function getTabIndex(): int
1911
	{
1912
		$tabindex = 0;
1913
		if (0 !== $this->get('tabindex')) {
1914
			$tabindex = $this->get('tabindex');
1915
		} elseif (self::$tabIndexLastSeq) {
1916
			$tabindex = self::$tabIndexLastSeq;
1917
		}
1918
		return $tabindex + self::$tabIndexDefaultSeq;
1919
	}
1920
1921
	/** {@inheritdoc} */
1922
	public function delete()
1923
	{
1924
		$this->getUITypeModel()->delete();
1925
		Settings_FieldsDependency_Module_Model::removeField($this->getModuleName(), $this->getName());
1926
		\App\Utils\Kanban::deleteField($this->getModuleName(), $this->getName());
1927
		\App\Fields\Picklist::removeDependencyConditionField($this->getModuleName(), $this->getName());
1928
		$this->getModule()->clearCache();
1929
		parent::delete();
1930
	}
1931
1932
	/**
1933
	 * Method is responsible for ensuring the validity of the length of a specific uitype.
1934
	 *
1935
	 * @param int|bool $newMinValue
1936
	 * @param int      $newMaxValue
1937
	 *
1938
	 * @return bool
1939
	 */
1940
	public function validateMaximumLength($newMinValue, int $newMaxValue): bool
1941
	{
1942
		$fieldRangeValue = $this->getAcceptableLengthRange();
1943
1944
		return $newMinValue < $newMaxValue
1945
			  && $fieldRangeValue['min'] <= $newMinValue
1946
			  && $fieldRangeValue['max'] >= $newMaxValue;
1947
	}
1948
1949
	/**
1950
	 * Get acceptable field type length range.
1951
	 *
1952
	 * @return array
1953
	 */
1954
	public function getAcceptableLengthRange(): array
1955
	{
1956
		$minAceptableLength = 1;
1957
		if ('string' === $this->getFieldDataType()) {
1958
			$maxAceeptableLength = 255;
1959
		} else {
1960
			$rangeValue = $this->getRangeValues();
1961
			if (false !== strpos($rangeValue, ',')) {
1962
				$explodedRange = explode(',', $rangeValue);
1963
				$minAceptableLength = $explodedRange[0];
1964
				$maxAceeptableLength = $explodedRange[1];
1965
			} else {
1966
				$maxAceeptableLength = $rangeValue;
1967
			}
1968
		}
1969
		return ['min' => $minAceptableLength, 'max' => $maxAceeptableLength];
1970
	}
1971
}
1972