Passed
Push — developer ( 762b64...a1cff0 )
by Radosław
20:19
created

Vtiger_Basic_InventoryField::getQueryOperators()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
ccs 1
cts 1
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 1
1
<?php
2
3
/**
4
 * Inventory Basic Field Class.
5
 *
6
 * @package   InventoryField
7
 *
8
 * @copyright YetiForce S.A.
9
 * @license   YetiForce Public License 5.0 (licenses/LicenseEN.txt or yetiforce.com)
10
 * @author    Mariusz Krzaczkowski <[email protected]>
11
 * @author    Radosław Skrzypczak <[email protected]>
12
 */
13
class Vtiger_Basic_InventoryField extends \App\Base
14
{
15
	/**
16
	 * Field visible everywhere.
17
	 */
18
	private const FIELD_VISIBLE_EVERYWHERE = 0;
19
	/**
20
	 * Field visible in detail view.
21
	 */
22
	private const FIELD_VISIBLE_IN_DETAIL = 2;
23
	/**
24
	 * Field hidden.
25
	 */
26
	private const FIELD_HIDDEN = 5;
27
	/**
28
	 * Field read-only.
29
	 */
30
	private const FIELD_READONLY = 10;
31
32
	protected $columnName = '';
33
	protected $moduleName = '';
34
35
	protected $type;
36
	protected $colSpan = 10;
37
	protected $defaultValue = '';
38
	protected $params = [];
39
	protected $dbType = 'string';
40
	protected $customColumn = [];
41
	protected $summationValue = false;
42
	protected $onlyOne = true;
43
	protected $displayType = self::FIELD_VISIBLE_EVERYWHERE;
44
	protected $displayTypeBase = [
45
		self::FIELD_VISIBLE_EVERYWHERE => 'LBL_DISPLAYTYPE_ALL',
46
		self::FIELD_VISIBLE_IN_DETAIL => 'LBL_DISPLAYTYPE_ONLY_DETAIL',
47
		self::FIELD_HIDDEN => 'LBL_DISPLAYTYPE_HIDDEN',
48
		self::FIELD_READONLY => 'LBL_DISPLAYTYPE_READONLY'
49
	];
50
	protected $blocks = [1];
51
	protected $fieldDataType = 'inventory';
52
	protected $maximumLength = 255;
53
	protected $defaultLabel = '';
54
	protected $purifyType = '';
55
	protected $customPurifyType = [];
56
	protected $customMaximumLength = [];
57
	/** @var array Default values for custom fields */
58
	protected $customDefault = [];
59
	/** @var bool Field is synchronized */
60
	protected $sync = false;
61
	/** @var array List of changes */
62
	protected $changes = [];
63
	/** @var bool Search allowed */
64
	protected $searchable = false;
65
	/** @var array Operators for query {@see \App\Condition::STANDARD_OPERATORS} */
66
	protected $queryOperators = ['e', 'n', 'y', 'ny'];
67 2
	/** @var array Operators for record conditions {@see \App\Condition::STANDARD_OPERATORS} */
68
	protected $recordOperators = ['e', 'n', 'y', 'ny'];
69 2
70 2
	/**
71 2
	 * Gets inventory field instance.
72
	 *
73 2
	 * @param string      $moduleName
74 2
	 * @param string|null $type
75 2
	 *
76 2
	 * @throws \App\Exceptions\AppException
77
	 *
78 2
	 * @return self
79
	 */
80
	public static function getInstance(string $moduleName, ?string $type = 'Basic')
81
	{
82
		$cacheName = "{$moduleName}:{$type}";
83
		if (\App\Cache::has(__METHOD__, $cacheName)) {
84
			$instance = \App\Cache::get(__METHOD__, $cacheName);
85
		} else {
86 2
			$className = Vtiger_Loader::getComponentClassName('InventoryField', $type, $moduleName);
87
			$instance = new $className();
88 2
			$instance->setModuleName($moduleName);
89
			\App\Cache::save(__METHOD__, $cacheName, $instance);
90
		}
91
		return clone $instance;
92
	}
93
94
	/**
95
	 * Function returns module name.
96
	 *
97
	 * @return string
98 2
	 */
99
	public function getModuleName(): string
100 2
	{
101 2
		return $this->moduleName;
102
	}
103
104
	/**
105
	 * Function to get the Id.
106
	 *
107
	 * @return int Field ID
108
	 */
109
	public function getId(): int
110
	{
111
		return (int) $this->get('id');
112
	}
113
114
	/**
115
	 * Sets module name.
116
	 *
117
	 * @param string $moduleName
118
	 *
119
	 * @return \Vtiger_Basic_InventoryField
120
	 */
121
	public function setModuleName(string $moduleName): self
122
	{
123
		$this->moduleName = $moduleName;
124
		return $this;
125
	}
126
127
	/**
128
	 * Getting onlyOne field.
129
	 *
130
	 * @return bool
131
	 */
132
	public function isOnlyOne()
133
	{
134
		return $this->onlyOne;
135
	}
136
137
	public function getBlocks()
138 2
	{
139
		return $this->blocks;
140 2
	}
141 2
142
	/**
143 2
	 * Getting database-type of field.
144 2
	 *
145
	 * @return string|yii\db\ColumnSchemaBuilder dbType
146
	 */
147
	public function getDBType()
148
	{
149
		$columnCriteria = $this->dbType;
150
		if (\is_array($columnCriteria)) {
0 ignored issues
show
introduced by
The condition is_array($columnCriteria) is always false.
Loading history...
151
			[$type, $length, $default, $unsigned] = array_pad($columnCriteria, 4, null);
152
			$columnCriteria = \App\Db::getInstance()->getSchema()->createColumnSchemaBuilder($type, $length);
153
			if (null !== $default) {
154
				$columnCriteria->defaultValue($default);
155
			}
156
			if (null !== $unsigned) {
157 2
				$columnCriteria->unsigned();
158
			}
159 2
		}
160
161
		return $columnCriteria;
162
	}
163
164
	/**
165
	 * Gets value for save.
166
	 *
167
	 * @param array  $item
168
	 * @param bool   $userFormat
169
	 * @param string $column
170
	 *
171
	 * @return mixed
172
	 */
173
	public function getValueForSave(array $item, bool $userFormat = false, string $column = null)
174
	{
175
		if (null === $column) {
176
			$column = $this->getColumnName();
177
		}
178
		$value = $item[$column] ?? null;
179
		return $userFormat ? $this->getDBValue($value) : $value;
180
	}
181
182
	/**
183
	 * Getting all params field.
184
	 *
185
	 * @return array
186
	 */
187
	public function getParams()
188
	{
189
		return $this->params;
190
	}
191
192
	/**
193
	 * Get params value.
194
	 *
195
	 * @return array
196
	 */
197
	public function getParamsConfig()
198
	{
199
		return $this->get('params') ? \App\Json::decode($this->get('params')) : [];
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->get('param...et('params')) : array() also could return the type string which is incompatible with the documented return type array.
Loading history...
200
	}
201
202
	/**
203
	 * Get the configuration parameter value for the specified key.
204
	 *
205
	 * @param string $key
206
	 *
207
	 * @return mixed
208
	 */
209
	public function getParamConfig(string $key)
210
	{
211
		return $this->getParamsConfig()[$key] ?? null;
212
	}
213
214
	/**
215
	 * Getting all values display Type.
216
	 *
217
	 * @return array
218
	 */
219
	public function displayTypeBase()
220
	{
221
		return $this->displayTypeBase;
222
	}
223
224
	/**
225
	 * Gets display type.
226
	 *
227
	 * @return int
228
	 */
229
	public function getDisplayType(): int
230
	{
231
		return $this->has('displaytype') ? $this->get('displaytype') : $this->displayType;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->has('displ...') : $this->displayType could return the type null which is incompatible with the type-hinted return integer. Consider adding an additional type-check to rule them out.
Loading history...
232
	}
233
234
	public function getColSpan()
235
	{
236
		return $this->has('colspan') ? $this->get('colspan') : $this->colSpan;
237
	}
238
239
	public function getRangeValues()
240
	{
241
		return $this->maximumLength;
242
	}
243
244
	/**
245
	 * The function determines whether sorting on this field is allowed.
246
	 *
247 1
	 * @return bool
248
	 */
249 1
	public function isSearchable(): bool
250
	{
251
		return $this->searchable && \in_array(1, $this->getBlocks());
252
	}
253
254
	/**
255
	 * Gets full field name for conditions.
256
	 *
257 2
	 * @return string
258
	 */
259 2
	public function getSearchName(): string
260
	{
261
		return "{$this->getColumnName()}:{$this->getModuleName()}:INVENTORY";
262
	}
263
264
	/**
265
	 * Return allowed query operators for field.
266
	 *
267 2
	 * @return string[]
268
	 */
269 2
	public function getQueryOperators(): array
270
	{
271
		return $this->queryOperators;
272 2
	}
273
274 2
	/**
275
	 * Return allowed record operators for field.
276
	 *
277 1
	 * @return string[]
278
	 */
279 1
	public function getRecordOperators(): array
280
	{
281
		return $this->recordOperators;
282
	}
283
284
	/**
285
	 * Gets query operator labels.
286
	 *
287
	 * @return string[]
288
	 */
289
	public function getQueryOperatorLabels(): array
290
	{
291
		return \App\Condition::getOperatorLabels($this->getQueryOperators());
292
	}
293
294
	/**
295
	 * Gets record operator labels.
296
	 *
297
	 * @return string[]
298
	 */
299
	public function getRecordOperatorLabels(): array
300
	{
301
		return \App\Condition::getOperatorLabels($this->getRecordOperators());
302
	}
303
304
	/**
305
	 * Returns template for operator.
306
	 *
307
	 * @param string $operator
308
	 *
309
	 * @return string
310
	 */
311
	public function getOperatorTemplateName(string $operator = '')
312
	{
313
		return 'ConditionBuilder/Base.tpl';
314
	}
315
316
	/**
317
	 * Function to get the DB Insert Value, for the current field type with given User Value for condition builder.
318
	 *
319
	 * @param mixed  $value
320
	 * @param string $operator
321
	 *
322
	 * @return string
323
	 */
324
	public function getDbConditionBuilderValue($value, string $operator)
325
	{
326
		$this->validate($value, $this->getColumnName(), true);
327
		return $this->getDBValue($value);
328
	}
329
330
	/**
331
	 * Function to get the field model for condition builder.
332
	 *
333
	 * @param string $operator
334
	 *
335
	 * @return $this
336
	 */
337
	public function getConditionBuilderField(string $operator)
338
	{
339
		return $this;
340
	}
341
342
	/**
343
	 * Get template name for edit.
344
	 *
345
	 * @return string
346
	 */
347
	public function getEditTemplateName()
348
	{
349
		return 'inventoryTypes/Base.tpl';
350
	}
351
352
	/**
353
	 * Getting template name.
354
	 *
355
	 * @param string $view
356
	 * @param string $moduleName
357
	 *
358
	 * @return string templateName
359
	 */
360
	public function getTemplateName($view, $moduleName)
361
	{
362
		$tpl = $view . $this->type . '.tpl';
363
		$dirs = [
364
			$filename = \App\Layout::getActiveLayout() . DIRECTORY_SEPARATOR . 'modules' . DIRECTORY_SEPARATOR . $moduleName,
0 ignored issues
show
Unused Code introduced by
The assignment to $filename is dead and can be removed.
Loading history...
365
			$filename = \App\Layout::getActiveLayout() . DIRECTORY_SEPARATOR . 'modules' . DIRECTORY_SEPARATOR . 'Vtiger',
366
			$filename = Vtiger_Viewer::getDefaultLayoutName() . DIRECTORY_SEPARATOR . 'modules' . DIRECTORY_SEPARATOR . $moduleName,
367
			$filename = Vtiger_Viewer::getDefaultLayoutName() . DIRECTORY_SEPARATOR . 'modules' . DIRECTORY_SEPARATOR . 'Vtiger',
368
		];
369
		if (\App\Config::performance('LOAD_CUSTOM_FILES')) {
370
			$loaderDirs[] = 'custom/layouts/';
0 ignored issues
show
Comprehensibility Best Practice introduced by
$loaderDirs was never initialized. Although not strictly required by PHP, it is generally a good practice to add $loaderDirs = array(); before regardless.
Loading history...
371
		}
372
		$loaderDirs[] = 'layouts' . DIRECTORY_SEPARATOR;
373
		foreach ($dirs as $dir) {
374
			foreach ($loaderDirs as $loaderDir) {
375
				$filename = $loaderDir . $dir . DIRECTORY_SEPARATOR . 'inventoryfields' . DIRECTORY_SEPARATOR . $tpl;
376
				if (is_file($filename)) {
377
					return $tpl;
378
				}
379
			}
380
		}
381
382
		return $view . 'Base' . '.tpl';
383
	}
384
385
	/**
386
	 * Getting default label.
387 2
	 *
388
	 * @return string defaultLabel
389 2
	 */
390 2
	public function getDefaultLabel()
391 2
	{
392 2
		return $this->defaultLabel;
393
	}
394
395 2
	/**
396
	 * Getting field type.
397
	 *
398
	 * @return string
399
	 */
400
	public function getType()
401
	{
402
		return $this->type;
403
	}
404
405
	/**
406
	 * Getting column name.
407 1
	 *
408
	 * @return string columnName
409 1
	 */
410 1
	public function getColumnName()
411 1
	{
412 1
		return $this->has('columnname') ? $this->get('columnname') : $this->columnName;
413 1
	}
414 1
415
	/**
416 1
	 * Getting field name.
417
	 *
418
	 * @return string field name
419
	 */
420
	public function getName(): string
421
	{
422
		return $this->getColumnName();
423
	}
424
425
	/**
426
	 * Get label.
427
	 *
428
	 * @return string
429
	 */
430
	public function getLabel(): string
431
	{
432 2
		return $this->get('label');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->get('label') could return the type null which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
433
	}
434 2
435
	/**
436
	 * Getting column name.
437
	 *
438
	 * @return array customColumn
439
	 */
440
	public function getCustomColumn()
441
	{
442
		$columns = [];
443
		$schame = \App\Db::getInstance()->getSchema();
444
		foreach ($this->customColumn as $name => $columnCriteria) {
445
			if (\is_array($columnCriteria)) {
446
				[$type, $length, $default, $unsigned] = array_pad($columnCriteria, 4, null);
447 2
				$columnCriteria = $schame->createColumnSchemaBuilder($type, $length);
448
				if (null !== $default) {
449 2
					$columnCriteria->defaultValue($default);
450
				}
451
				if (null !== $unsigned) {
452 2
					$columnCriteria->unsigned();
453
				}
454
			}
455 2
			$columns[$name] = $columnCriteria;
456
		}
457
458
		return $columns;
459
	}
460
461
	/**
462
	 * Check if the field is summed up.
463
	 *
464
	 * @return bool
465
	 */
466
	public function isSummary(): bool
467
	{
468
		return $this->summationValue;
469
	}
470
471
	/**
472
	 * Check if summary enabled.
473
	 *
474
	 * @return bool
475
	 */
476
	public function isSummaryEnabled(): bool
477
	{
478
		return $this->isSummary() && 1 === (int) ($this->getParamConfig('summary_enabled') ?? 1);
479
	}
480
481
	/**
482
	 * Gets default value by field.
483
	 *
484
	 * @param string $columnName
485
	 *
486
	 * @return mixed
487
	 */
488
	public function getDefaultValue(string $columnName = '')
489
	{
490
		if (!$columnName || $columnName === $this->getColumnName()) {
491 2
			$value = $this->has('defaultvalue') ? $this->get('defaultvalue') : $this->defaultValue;
492
		} else {
493 2
			$value = $this->customDefault[$columnName] ?? '';
494 2
		}
495 2
496 2
		return $value;
497 2
	}
498
499 2
	/**
500 2
	 * Getting value to display.
501 2
	 *
502 2
	 * @param mixed $value
503 2
	 * @param array $rowData
504 2
	 * @param bool  $rawText
505 2
	 *
506
	 * @return string
507
	 */
508 2
	public function getDisplayValue($value, array $rowData = [], bool $rawText = false)
509
	{
510
		return $value ? \App\Purifier::encodeHtml($value) : '';
511
	}
512
513
	/**
514
	 * Function to get the list value in display view.
515 1
	 *
516
	 * @param mixed $value
517 1
	 * @param array $rowData
518
	 * @param bool  $rawText
519
	 *
520
	 * @return mixed
521
	 */
522
	public function getListViewDisplayValue($value, array $rowData = [], bool $rawText = false)
523
	{
524
		return $this->getDisplayValue($value, $rowData, $rawText);
525
	}
526
527
	/**
528
	 * Get value for Edit view.
529
	 *
530
	 * @param array  $itemData
531
	 * @param string $column
532
	 *
533
	 * @return string|int
534
	 */
535
	public function getEditValue(array $itemData, string $column = '')
536
	{
537
		if (!$column) {
538
			$column = $this->getColumnName();
539
		}
540
		$value = '';
541
		if (isset($itemData[$column])) {
542
			$value = $itemData[$column];
543
		} elseif (($default = \App\Config::module($this->getModuleName(), 'defaultInventoryData', [])[$column] ?? null) !== null) {
544
			$value = $default;
545
		} elseif ($column === $this->getColumnName()) {
546
			$value = $this->getDefaultValue();
547
		}
548
549
		return $value;
550
	}
551
552
	/**
553
	 * Function to check if the current field is mandatory or not.
554
	 *
555
	 * @return bool
556
	 */
557
	public function isMandatory()
558
	{
559
		return true;
560
	}
561
562
	/**
563
	 * Function to check whether the current field is visible.
564
	 *
565
	 * @return bool
566
	 */
567
	public function isVisible()
568
	{
569
		return self::FIELD_HIDDEN !== $this->get('displaytype');
570
	}
571
572
	/**
573
	 * Function to check if field is visible in detail view.
574
	 *
575
	 * @return bool
576
	 */
577
	public function isVisibleInDetail()
578
	{
579
		return \in_array($this->get('displaytype'), [self::FIELD_VISIBLE_EVERYWHERE, self::FIELD_READONLY, self::FIELD_VISIBLE_IN_DETAIL]);
580
	}
581
582
	/**
583
	 * Function to check whether the current field is editable.
584
	 *
585
	 * @return bool
586
	 */
587
	public function isEditable(): bool
588
	{
589
		return \in_array($this->get('displaytype'), [self::FIELD_VISIBLE_EVERYWHERE, self::FIELD_READONLY]);
590
	}
591
592
	/**
593
	 * Function checks if the field is read-only.
594
	 *
595
	 * @return bool
596
	 */
597
	public function isReadOnly()
598
	{
599
		return self::FIELD_READONLY === $this->get('displaytype');
600
	}
601
602
	/** {@inheritdoc} */
603
	public function set($key, $value, $register = false)
604
	{
605
		if ($this->getId() && !\in_array($key, ['id']) && (\array_key_exists($key, $this->value) && $this->value[$key] != $value)) {
606
			$this->changes[$key] = $this->get($key);
607
		}
608
		return parent::set($key, $value);
609
	}
610
611
	/**
612
	 * Sum the field value for each row.
613
	 *
614
	 * @param array    $data
615
	 * @param int|null $groupId
616
	 *
617
	 * @return int|float
618
	 */
619
	public function getSummaryValuesFromData($data, ?int $groupId = null)
620
	{
621
		$sum = 0;
622
		if (\is_array($data)) {
0 ignored issues
show
introduced by
The condition is_array($data) is always true.
Loading history...
623
			foreach ($data as $row) {
624
				if (null !== $groupId && $groupId !== $row['groupid'] ?? -1) {
625
					continue;
626
				}
627
				$sum += $row[$this->getColumnName()];
628
			}
629
		}
630
		return $sum;
631
	}
632
633
	/**
634
	 * Gets relation field.
635
	 *
636
	 * @param string $related
637
	 *
638
	 * @throws \App\Exceptions\AppException
639
	 *
640
	 * @return bool|\Vtiger_Field_Model
641
	 */
642
	public function getMapDetail(string $related)
643
	{
644
		$inventory = Vtiger_Inventory_Model::getInstance($this->getModuleName());
645
		$fields = $inventory->getAutoCompleteFields();
646
		$field = false;
647
		if ($mapDetail = $fields[$related][$this->getColumnName()] ?? false) {
648
			$moduleModel = Vtiger_Module_Model::getInstance($related);
649
			$field = Vtiger_Field_Model::getInstance($mapDetail['field'], $moduleModel);
650
		}
651
		return $field;
652
	}
653
654
	public function getFieldDataType()
655
	{
656
		return $this->fieldDataType;
657
	}
658
659
	/**
660
	 * Gets database value.
661
	 *
662
	 * @param mixed       $value
663
	 * @param string|null $name
664
	 *
665
	 * @return mixed
666
	 */
667
	public function getDBValue($value, ?string $name = '')
668
	{
669
		return $value;
670
	}
671
672
	/**
673
	 * Verification of data.
674
	 *
675
	 * @param mixed  $value
676
	 * @param string $columnName
677
	 * @param bool   $isUserFormat
678
	 * @param mixed  $originalValue
679
	 *
680
	 * @throws \App\Exceptions\Security
681
	 */
682
	public function validate($value, string $columnName, bool $isUserFormat, $originalValue = null)
683
	{
684
		if (!is_numeric($value) && (\is_string($value) && $value !== strip_tags($value))) {
685
			throw new \App\Exceptions\Security('ERR_ILLEGAL_FIELD_VALUE||' . ($columnName ?? $this->getColumnName()) . '||' . $this->getModuleName() . '||' . $value, 406);
686
		}
687
		if (App\TextUtils::getTextLength($value) > $this->maximumLength) {
688
			throw new \App\Exceptions\Security('ERR_VALUE_IS_TOO_LONG||' . ($columnName ?? $this->getColumnName()) . '||' . $this->getModuleName() . '||' . $value, 406);
689
		}
690
	}
691
692
	/**
693
	 * Sets default data config.
694
	 *
695
	 * @return $this
696
	 */
697
	public function setDefaultDataConfig()
698
	{
699
		$this->set('columnname', $this->columnName)
700
			->set('label', $this->defaultLabel)
701
			->set('presence', 0)
702
			->set('defaultvalue', $this->defaultValue)
703
			->set('displaytype', $this->displayType)
704
			->set('invtype', $this->type)
705
			->set('block', current($this->blocks))
706
			->set('colspan', $this->colSpan);
707
708
		return $this;
709
	}
710
711
	/**
712
	 * Field required to make an entry.
713
	 *
714
	 * @return bool
715
	 */
716
	public function isRequired()
717
	{
718
		return false;
719
	}
720
721
	/**
722
	 * Sets value data.
723
	 *
724
	 * @param \Vtiger_Record_Model $recordModel
725
	 * @param array                $item
726
	 * @param bool                 $userFormat
727
	 *
728
	 * @throws \App\Exceptions\AppException
729
	 * @throws \App\Exceptions\Security
730
	 */
731
	public function setValueToRecord(Vtiger_Record_Model $recordModel, array $item, bool $userFormat)
732
	{
733
		$column = $this->getColumnName();
734
		$baseValue = $item[$column] ?? null;
735
		$value = $this->getValueForSave($item, $userFormat, $column);
736
		if ($userFormat && $baseValue) {
737
			$baseValue = $this->getDBValue($baseValue, $column);
738
		}
739
		$this->validate($value, $column, false, $baseValue);
740
741
		$itemId = $item['id'];
742
		$addToChanges = !$recordModel->isNew() && is_numeric($itemId) && !$this->compare($value, $recordModel->getInventoryData()[$itemId][$column] ?? '', $column);
743
		$recordModel->setInventoryItemPart($itemId, $column, $value, $addToChanges);
744
		if ($customColumn = $this->getCustomColumn()) {
745
			foreach (array_keys($customColumn) as $column) {
746
				$value = $this->getValueForSave($item, $userFormat, $column);
747
				$this->validate($value, $column, false);
748
				$addToChanges = !$recordModel->isNew() && is_numeric($itemId) && !$this->compare($value, $recordModel->getInventoryData()[$itemId][$column] ?? '', $column);
749
				$recordModel->setInventoryItemPart($itemId, $column, $value, $addToChanges);
750
			}
751
		}
752
	}
753
754
	/**
755
	 * Compare two values.
756
	 *
757
	 * @param mixed  $value
758
	 * @param mixed  $prevValue
759
	 * @param string $column
760
	 *
761
	 * @return bool
762
	 */
763
	public function compare($value, $prevValue, string $column): bool
764
	{
765
		return (string) $value === (string) $prevValue;
766
	}
767
768
	/**
769
	 * Gets purify type.
770
	 *
771
	 * @return array
772
	 */
773
	public function getPurifyType()
774
	{
775
		return [$this->getColumnName() => $this->purifyType] + $this->customPurifyType;
776
	}
777
778
	/**
779
	 * Get information about field.
780
	 *
781
	 * @return array
782
	 */
783
	public function getFieldInfo(): array
784
	{
785
		return [
786
			'maximumlength' => $this->maximumLength
787
		];
788
	}
789
790
	/**
791
	 * Get maximum length by column.
792
	 *
793
	 * @param string $columnName
794
	 *
795
	 * @return int|string
796
	 */
797
	public function getMaximumLengthByColumn(string $columnName)
798
	{
799
		if ($columnName === $this->getColumnName()) {
800
			$value = $this->maximumLength;
801
		} else {
802
			$value = $this->customMaximumLength[$columnName] ?? '';
803
		}
804
805
		return $value;
806
	}
807
808
	/**
809
	 * Get pervious value by field.
810
	 *
811
	 * @param string $fieldName
812
	 *
813
	 * @return mixed
814
	 */
815
	public function getPreviousValue(string $fieldName = '')
816
	{
817
		return $fieldName ? ($this->changes[$fieldName] ?? null) : $this->changes;
818
	}
819
820
	/**
821
	 * Check if the field is synchronized.
822
	 *
823
	 * @return bool
824
	 */
825
	public function isSync(): bool
826
	{
827
		return $this->sync;
828
	}
829
830
	/**
831
	 * Gets config fields data.
832
	 *
833
	 * @return array
834
	 */
835
	public function getConfigFieldsData(): array
836
	{
837
		$row = [
838
			'invtype' => [
839
				'name' => 'invtype',
840
				'column' => 'invtype',
841
				'uitype' => 1,
842
				'label' => 'LBL_NAME_FIELD',
843
				'maximumlength' => '30',
844
				'typeofdata' => 'V~M',
845
				'purifyType' => \App\Purifier::STANDARD,
846
				'isEditableReadOnly' => true,
847
			],
848
			'label' => [
849
				'name' => 'label',
850
				'label' => 'LBL_LABEL_NAME',
851
				'uitype' => 1,
852
				'maximumlength' => '50',
853
				'typeofdata' => 'V~M',
854
				'purifyType' => \App\Purifier::TEXT,
855
			],
856
			'displaytype' => [
857
				'name' => 'displaytype',
858
				'label' => 'LBL_DISPLAY_TYPE',
859
				'uitype' => 16,
860
				'maximumlength' => '127',
861
				'typeofdata' => 'V~M',
862
				'purifyType' => \App\Purifier::INTEGER,
863
				'picklistValues' => [],
864
			],
865
			'colspan' => [
866
				'name' => 'colspan',
867
				'label' => 'LBL_COLSPAN',
868
				'uitype' => 7,
869
				'maximumlength' => '0,100',
870
				'typeofdata' => 'N~M',
871
				'purifyType' => \App\Purifier::INTEGER,
872
				'tooltip' => 'LBL_MAX_WIDTH_COLUMN_INFO'
873
			]
874
		];
875
876
		$qualifiedModuleName = 'Settings:LayoutEditor';
877
		foreach ($this->displayTypeBase() as $key => $value) {
878
			$row['displaytype']['picklistValues'][$key] = \App\Language::translate($value, $qualifiedModuleName);
879
		}
880
881
		if ($this->isSummary()) {
882
			$row['summary_enabled'] = [
883
				'name' => 'summary_enabled',
884
				'label' => 'LBL_INV_SUMMARY_ENABLED',
885
				'uitype' => 56,
886
				'maximumlength' => '1',
887
				'typeofdata' => 'C~O',
888
				'purifyType' => \App\Purifier::INTEGER,
889
				'defaultvalue' => 1
890
			];
891
		}
892
893
		return $row;
894
	}
895
896
	/**
897
	 * Gets config fields.
898
	 *
899
	 * @return Vtiger_Field_Model[]
900
	 */
901
	public function getConfigFields(): array
902
	{
903
		$module = 'LayoutEditor';
904
		$fields = [];
905
		foreach ($this->getConfigFieldsData() as $name => $data) {
906
			$fieldModel = \Vtiger_Field_Model::init($module, $data, $name);
907
			if (null !== $this->get($name)) {
908
				$fieldModel->set('fieldvalue', $this->get($name));
909
			} elseif (isset($this->getParamsConfig()[$name])) {
910
				$fieldModel->set('fieldvalue', $this->getParamsConfig()[$name]);
911
			} elseif (property_exists($this, $name) && null !== $this->{$name} && '' !== $this->{$name}) {
912
				$fieldModel->set('fieldvalue', $this->{$name});
913
			} elseif (($default = $fieldModel->get('defaultvalue')) !== null) {
914
				$fieldModel->set('fieldvalue', $default);
915
			}
916
			$fields[$name] = $fieldModel;
917
		}
918
919
		return $fields;
920
	}
921
922
	/**
923
	 * Gets config field.
924
	 *
925
	 * @param string $key
926
	 *
927
	 * @return Vtiger_Field_Model|null
928
	 */
929
	public function getConfigField(string $key): ?Vtiger_Field_Model
930
	{
931
		return $this->getConfigFields()[$key] ?? null;
932
	}
933
}
934