Issues (3882)

Security Analysis    39 potential vulnerabilities

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  Response Splitting (9)
Response Splitting can be used to send arbitrary responses.
  File Manipulation (2)
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  File Exposure (7)
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Code Injection (13)
Code Injection enables an attacker to execute arbitrary code on the server.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Cross-Site Scripting (8)
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  Header Injection
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

app/Field.php (5 issues)

1
<?php
2
3
namespace App;
4
5
/**
6
 * Field basic class.
7
 *
8
 * @package App
9
 *
10
 * @copyright YetiForce S.A.
11
 * @license   YetiForce Public License 6.5 (licenses/LicenseEN.txt or yetiforce.com)
12
 * @author    Mariusz Krzaczkowski <[email protected]>
13
 * @author    RadosÅ‚aw Skrzypczak <[email protected]>
14
 */
15
class Field
16
{
17
	/** @var string[] Help info views. */
18
	const HELP_INFO_VIEWS = ['LBL_EDIT_VIEW' => 'Edit', 'LBL_DETAIL_VIEW' => 'Detail', 'LBL_QUICK_CREATE_VIEW' => 'QuickCreateAjax'];
19
20
	/** @var array System fields */
21
	const SYSTEM_FIELDS = [
22
		'assigned_user_id' => [
23
			'validationConditions' => ['name'],
24
			'name' => 'assigned_user_id',	'column' => 'smownerid',	'label' => 'Assigned To',	'table' => 'vtiger_crmentity',
25
			'uitype' => 53,	'typeofdata' => 'V~M',	'maximumlength' => 65535,
26
		],
27
		'createdtime' => [
28 5800
			'validationConditions' => ['name'],
29
			'name' => 'createdtime',	'column' => 'createdtime',	'label' => 'Created Time',	'table' => 'vtiger_crmentity',
30 5800
			'uitype' => 70,	'typeofdata' => 'DT~O',	'displaytype' => 2,	'maximumlength' => 65535,
31 5800
		],
32 5789
		'modifiedtime' => [
33
			'validationConditions' => ['name'],
34 19
			'name' => 'modifiedtime',	'column' => 'modifiedtime',	'label' => 'Modified Time',	'table' => 'vtiger_crmentity',
35 19
			'uitype' => 70,	'typeofdata' => 'DT~O',	'displaytype' => 2,	'maximumlength' => 65535,
36 19
		],
37
		'created_user_id' => [
38
			'validationConditions' => ['column'],
39
			'name' => 'created_user_id',	'column' => 'smcreatorid',	'label' => 'Created By',	'table' => 'vtiger_crmentity',
40
			'uitype' => 52,	'typeofdata' => 'V~O',	'displaytype' => 2,	'quickcreate' => 3, 'masseditable' => 0, 'maximumlength' => 65535,
41
		],
42 19
		'modifiedby' => [
43 19
			'validationConditions' => ['name'],
44 19
			'name' => 'modifiedby',	'column' => 'modifiedby',	'label' => 'Last Modified By',	'table' => 'vtiger_crmentity',
45 19
			'uitype' => 52,	'typeofdata' => 'V~O',	'displaytype' => 2,	'quickcreate' => 3, 'masseditable' => 0, 'maximumlength' => 65535,
46 19
		],
47 19
		'shownerid' => [
48
			'validationConditions' => ['name'],
49
			'name' => 'shownerid',	'column' => 'shownerid',	'label' => 'Share with users',	'table' => 'vtiger_crmentity',
50 19
			'uitype' => 120,	'typeofdata' => 'V~O',	'columntype' => 'int(11)', 'maximumlength' => 65535,
51 19
		],
52 18
		'private' => [
53
			'validationConditions' => ['name'],
54 19
			'name' => 'private',	'column' => 'private',	'label' => 'FL_IS_PRIVATE',	'table' => 'vtiger_crmentity',
55 19
			'uitype' => 56,	'typeofdata' => 'C~O',	'columntype' => 'int(11)', 'maximumlength' => '-128,127', 'presence' => 2, 'generatedtype' => 2,
56
		],
57
		'share_externally' => [
58 5800
			'validationConditions' => ['uitype', 'fieldparams'],
59 10
			'name' => 'share_externally',	'column' => 'share_externally',	'label' => 'FL_SHARE_EXTERNALLY',	'defaultvalue' => 0,	'fieldparams' => 1,
60
			'uitype' => 318,	'typeofdata' => 'C~O',	'columntype' => 'tinyint(1)', 'maximumlength' => '-128,127',
61 5795
		],
62 5795
	];
63 27
64
	/**
65
	 * Function gets the list of fields that the user has permissions to.
66 5795
	 *
67
	 * @param int  $tabId    Module ID
68
	 * @param type $readOnly Read/preview only fields
0 ignored issues
show
The type App\type was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
69
	 *
70
	 * @return array
71
	 */
72
	public static function getFieldsPermissions($tabId, $readOnly = true)
73
	{
74
		Log::trace('Entering ' . __METHOD__ . ": $tabId");
75
		if (Cache::has(__METHOD__ . User::getCurrentUserId(), $tabId)) {
76
			$fields = Cache::get(__METHOD__ . User::getCurrentUserId(), $tabId);
77
		} else {
78
			$query = (new \App\Db\Query())
79
				->select([
80
					'vtiger_field.fieldid',
81 12
					'vtiger_field.fieldname',
82
					'vtiger_field.columnname',
83 12
					'vtiger_profile2field.readonly',
84 12
					'vtiger_profile2field.visible',
85 1
				])
86
				->from('vtiger_field')
87 12
				->innerJoin('vtiger_profile2field', 'vtiger_profile2field.fieldid = vtiger_field.fieldid')
88 12
				->where([
89 10
					'vtiger_field.tabid' => (int) $tabId,
90
					'vtiger_profile2field.visible' => 0,
91 9
					'vtiger_field.visible' => 0,
92 1
					'vtiger_field.presence' => [0, 2],
93
				]);
94 9
			$profileList = \App\User::getCurrentUserModel()->getProfiles();
95 9
			if ($profileList) {
96 1
				$query->andWhere(['vtiger_profile2field.profileid' => $profileList]);
97 1
			}
98
			$fields = [];
99 9
			$dataReader = $query->distinct()->createCommand()->query();
100
			while ($row = $dataReader->read()) {
101 9
				if (isset($fields[$row['fieldname']])) {
102 9
					$old = $fields[$row['fieldname']];
103 9
					$row['readonly'] = $old['readonly'] > 0 ? $row['readonly'] : $old['readonly'];
104 9
					$row['visible'] = $old['visible'] > 0 ? $row['visible'] : $old['visible'];
105 9
				}
106 9
				$fields[$row['fieldname']] = $row;
107
			}
108 1
			Cache::save(__METHOD__ . User::getCurrentUserId(), $tabId, $fields);
109 1
		}
110
111
		if ($readOnly) {
112 9
			return $fields;
113
		}
114
		foreach ($fields as $key => $field) {
115 1
			if ($field['readonly']) {
116 1
				unset($fields[$key]);
117
			}
118 1
		}
119
		return $fields;
120 1
	}
121
122
	private static $fieldPermissionCacheRead = [];
123
	private static $fieldPermissionCacheWrite = [];
124
125
	/**
126
	 * Function checks field permissions by field name or field id.
127
	 *
128
	 * @param int|string $tabMix   Module ID or module name
129
	 * @param int|string $fieldMix Field ID or field name
130
	 * @param bool       $readOnly Read/preview only fields
131
	 *
132
	 * @return bool
133
	 */
134
	public static function getFieldPermission($tabMix, $fieldMix, $readOnly = true)
135 1
	{
136
		$tabId = $tabMix;
137 1
		if (!is_numeric($tabMix)) {
138 1
			$tabId = Module::getModuleId($tabMix);
139 1
		}
140
		Log::trace('Entering ' . __METHOD__ . ": $tabId,$fieldMix");
141 1
		if ($readOnly && isset(self::$fieldPermissionCacheRead[$tabId][$fieldMix])) {
142 1
			return self::$fieldPermissionCacheRead[$tabId][$fieldMix];
143 1
		}
144
		if (!$readOnly && isset(self::$fieldPermissionCacheWrite[$tabId][$fieldMix])) {
145 1
			return self::$fieldPermissionCacheWrite[$tabId][$fieldMix];
146 1
		}
147
		$fields = static::getFieldsPermissions($tabId, $readOnly);
0 ignored issues
show
$readOnly of type boolean is incompatible with the type App\type expected by parameter $readOnly of App\Field::getFieldsPermissions(). ( Ignorable by Annotation )

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

147
		$fields = static::getFieldsPermissions($tabId, /** @scrutinizer ignore-type */ $readOnly);
Loading history...
148 1
		if (is_numeric($fieldMix)) {
149 1
			$key = 'fieldid';
150 1
			$fieldMix = (int) $fieldMix;
151 1
		} else {
152 1
			$key = 'fieldname';
153 1
		}
154 1
		foreach ($fields as &$field) {
155
			if ($field[$key] === $fieldMix) {
156 1
				$permission = !($field['visible']);
157 1
				if ($readOnly) {
158
					self::$fieldPermissionCacheRead[$tabId][$fieldMix] = $permission;
159
					self::$columnPermissionCacheRead[$tabId][$field['columnname']] = $permission;
160 1
				} else {
161
					self::$fieldPermissionCacheWrite[$tabId][$fieldMix] = $permission;
162
					self::$columnPermissionCacheWrite[$tabId][$field['columnname']] = $permission;
163 1
				}
164 1
165
				return $permission;
166 1
			}
167
		}
168 1
		if ($readOnly) {
169
			self::$fieldPermissionCacheRead[$tabId][$fieldMix] = false;
170
		} else {
171
			self::$fieldPermissionCacheWrite[$tabId][$fieldMix] = false;
172
		}
173
		return false;
174
	}
175
176
	private static $columnPermissionCacheRead = [];
177
	private static $columnPermissionCacheWrite = [];
178
179 379
	/**
180
	 * Function checks field permissions by column name.
181 379
	 *
182 379
	 * @param int|string $tabMix     Module ID or module name
183 378
	 * @param string     $columnName Field ID or field name
184
	 * @param bool       $readOnly   Read/preview only fields
185 3
	 *
186 3
	 * @return bool
187 3
	 */
188 3
	public static function getColumnPermission($tabMix, $columnName, $readOnly = true)
189 3
	{
190 3
		$tabId = $tabMix;
191 3
		if (!is_numeric($tabMix)) {
192 3
			$tabId = Module::getModuleId($tabMix);
193 3
		}
194 3
		Log::trace('Entering ' . __METHOD__ . ": $tabId,$columnName");
195 3
		if ($readOnly && isset(self::$columnPermissionCacheRead[$tabId][$columnName])) {
196 3
			return self::$columnPermissionCacheRead[$tabId][$columnName];
197 3
		}
198 3
		if (!$readOnly && isset(self::$columnPermissionCacheWrite[$tabId][$columnName])) {
199 3
			return self::$columnPermissionCacheWrite[$tabId][$columnName];
200 3
		}
201
		$fields = static::getFieldsPermissions($tabId, $readOnly);
0 ignored issues
show
$readOnly of type boolean is incompatible with the type App\type expected by parameter $readOnly of App\Field::getFieldsPermissions(). ( Ignorable by Annotation )

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

201
		$fields = static::getFieldsPermissions($tabId, /** @scrutinizer ignore-type */ $readOnly);
Loading history...
202 3
		foreach ($fields as &$field) {
203 3
			if ($field['columnname'] === $columnName) {
204 3
				$permission = !($field['visible']);
205 3
				if ($readOnly) {
206 3
					self::$columnPermissionCacheRead[$tabId][$columnName] = $permission;
207 3
					self::$fieldPermissionCacheRead[$tabId][$field['fieldname']] = $permission;
208 3
				} else {
209
					self::$columnPermissionCacheWrite[$tabId][$columnName] = $permission;
210
					self::$fieldPermissionCacheWrite[$tabId][$field['fieldname']] = $permission;
211
				}
212
213
				return $permission;
214 3
			}
215
		}
216 379
		if ($readOnly) {
217 378
			self::$columnPermissionCacheRead[$tabId][$columnName] = false;
218 323
		} else {
219 323
			self::$columnPermissionCacheWrite[$tabId][$columnName] = false;
220
		}
221
		return false;
222 316
	}
223
224
	/**
225 55
	 * Get related field for module.
226
	 *
227 372
	 * @param bool|string $moduleName
228 371
	 * @param bool|string $forModule
229 371
	 *
230 371
	 * @return array
231 343
	 */
232
	public static function getRelatedFieldForModule($moduleName = false, $forModule = false)
233
	{
234 371
		$key = 'all';
235
		if (Cache::has('getRelatedFieldForModule', $key)) {
236
			$fields = Cache::get('getRelatedFieldForModule', $key);
237 1
		} else {
238
			$db = Db::getInstance();
239
			$wsQuery = (new Db\Query())->select(['vtiger_field.fieldid', 'vtiger_field.uitype', 'vtiger_field.tabid', 'vtiger_field.columnname', 'vtiger_field.fieldname', 'vtiger_field.tablename', 'vtiger_field.fieldlabel', 'vtiger_tab.name', 'relmod' => 'vtiger_ws_referencetype.type', 'type' => new \yii\db\Expression($db->quoteValue(2))])
240
				->from('vtiger_field')
241
				->innerJoin('vtiger_tab', 'vtiger_field.tabid = vtiger_tab.tabid')
242
				->innerJoin('vtiger_ws_fieldtype', 'vtiger_field.uitype = vtiger_ws_fieldtype.uitype')
243
				->innerJoin('vtiger_ws_referencetype', 'vtiger_ws_fieldtype.fieldtypeid = vtiger_ws_referencetype.fieldtypeid')
244
				->where(['vtiger_tab.presence' => 0]);
245
			$fmrQuery = (new Db\Query())->select(['vtiger_field.fieldid', 'vtiger_field.uitype', 'vtiger_field.tabid', 'vtiger_field.columnname', 'vtiger_field.fieldname', 'vtiger_field.tablename', 'vtiger_field.fieldlabel', 'vtiger_tab.name', 'relmod' => 'vtiger_fieldmodulerel.relmodule', 'type' => new \yii\db\Expression($db->quoteValue(1))])
246
				->from('vtiger_field')
247 373
				->innerJoin('vtiger_tab', 'vtiger_field.tabid = vtiger_tab.tabid')
248
				->innerJoin('vtiger_fieldmodulerel', 'vtiger_field.fieldid = vtiger_fieldmodulerel.fieldid')
249 373
				->where(['vtiger_tab.presence' => 0]);
250 1
			$fields = [];
251
			$dataReader = $wsQuery->union($fmrQuery)->createCommand()->query();
252 372
			while ($row = $dataReader->read()) {
253 371
				$fields[$row['name']][$row['relmod']] = $row;
254
			}
255 372
			$query = (new Db\Query())->select(['vtiger_field.fieldid', 'vtiger_field.uitype', 'vtiger_field.tabid', 'vtiger_field.columnname', 'vtiger_field.fieldname', 'vtiger_field.tablename', 'vtiger_field.fieldlabel', 'vtiger_tab.name'])
256 372
				->from('vtiger_field')
257 372
				->innerJoin('vtiger_tab', 'vtiger_field.tabid = vtiger_tab.tabid')
258
				->where(['vtiger_tab.presence' => 0, 'vtiger_field.uitype' => [64, 65, 66, 67, 68]]);
259 372
			$dataReader = $query->createCommand()->query();
260
			while ($row = $dataReader->read()) {
261
				foreach (ModuleHierarchy::getModulesByUitype($row['uitype']) as $module => $value) {
262
					$row['relmod'] = $module;
263
					$row['type'] = 3;
264
					$fields[$row['name']][$row['relmod']] = $row;
265
				}
266
			}
267
			Cache::save('getRelatedFieldForModule', $key, $fields, Cache::LONG);
268
		}
269
		if ($moduleName) {
270 23
			if (isset($fields[$moduleName])) {
271
				if ($forModule) {
272 23
					return $fields[$moduleName][$forModule] ?? [];
273 23
				}
274 22
				return $fields[$moduleName];
275 1
			}
276
			return [];
277 22
		}
278 22
		if ($forModule) {
279
			$rfields = [];
280 2
			foreach ($fields as $moduleName => $forModules) {
281 2
				if (isset($forModules[$forModule])) {
282 2
					$rfields[$moduleName] = $forModules[$forModule];
283 2
				}
284
			}
285
			return $rfields;
286 23
		}
287
		return $fields;
288
	}
289
290
	/**
291
	 * Get fields from relation by relation Id.
292
	 *
293
	 * @param int $relationId
294 58
	 *
295
	 * @return string[]
296 58
	 */
297 25
	public static function getFieldsFromRelation($relationId)
298
	{
299 45
		if (empty($relationId)) {
300 45
			return [];
301
		}
302 45
		if (Cache::has('getFieldsFromRelation', $relationId)) {
303
			$fields = Cache::get('getFieldsFromRelation', $relationId);
304
		} else {
305
			$fields = (new \App\Db\Query())->select(['vtiger_relatedlists_fields.fieldid', 'vtiger_field.fieldname'])->from('vtiger_relatedlists_fields')
306
				->innerJoin('vtiger_field', 'vtiger_field.fieldid = vtiger_relatedlists_fields.fieldid')
307
				->where(['relation_id' => $relationId, 'vtiger_field.presence' => [0, 2]])->orderBy(['vtiger_relatedlists_fields.relation_id' => SORT_ASC, 'vtiger_relatedlists_fields.sequence' => SORT_ASC])
308
				->createCommand()->queryAllByGroup();
309
			Cache::save('getFieldsFromRelation', $relationId, $fields, Cache::LONG);
310
		}
311
		return $fields;
312
	}
313
314
	/**
315
	 * Function to gets module field info.
316
	 *
317
	 * @param int|string $mixed
318
	 * @param int|string $module
319
	 *
320
	 * @return array|null
321
	 */
322
	public static function getFieldInfo($mixed, $module = false)
323
	{
324
		$fieldInfo = false;
325
		if (is_numeric($mixed)) {
326
			if (Cache::has('FieldInfoById', $mixed)) {
327
				return Cache::get('FieldInfoById', $mixed);
328
			}
329
			$fieldInfo = (new \App\Db\Query())
330
				->from('vtiger_field')
331
				->leftJoin('s_#__fields_anonymization', 'vtiger_field.fieldid = s_#__fields_anonymization.field_id')
332
				->where(['vtiger_field.fieldid' => $mixed])->one();
333
			Cache::save('FieldInfoById', $mixed, $fieldInfo, Cache::LONG);
334
		} else {
335
			$fieldsInfo = self::getModuleFieldInfos($module);
336
			if ($fieldsInfo && isset($fieldsInfo[$mixed])) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $fieldsInfo of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
337
				$fieldInfo = $fieldsInfo[$mixed];
338
				Cache::save('FieldInfoById', $fieldInfo['fieldid'], $fieldInfo, Cache::LONG);
339
			}
340
		}
341
		return $fieldInfo;
342
	}
343
344
	/**
345
	 * Function get module field infos.
346
	 *
347
	 * @param int|string $module
348
	 * @param bool       $returnByColumn
349
	 *
350
	 * @return array
351
	 */
352
	public static function getModuleFieldInfos($module, bool $returnByColumn = false): array
353
	{
354
		if (is_numeric($module)) {
355
			$module = Module::getModuleName($module);
356
		}
357
		$cacheName = 'ModuleFieldInfosByName';
358
		if (!Cache::has($cacheName, $module)) {
359
			$dataReader = (new Db\Query())
360
				->from('vtiger_field')
361
				->leftJoin('s_#__fields_anonymization', 'vtiger_field.fieldid = s_#__fields_anonymization.field_id')
362
				->where(['tabid' => Module::getModuleId($module)])
363
				->createCommand()->query();
364
			$fieldInfoByName = $fieldInfoByColumn = [];
365
			while ($row = $dataReader->read()) {
366
				$fieldInfoByName[$row['fieldname']] = $row;
367
				$fieldInfoByColumn[$row['columnname']] = $row;
368
			}
369
			Cache::save($cacheName, $module, $fieldInfoByName);
370
			Cache::save('ModuleFieldInfosByColumn', $module, $fieldInfoByColumn);
371
		}
372
		if ($returnByColumn) {
373
			return Cache::get('ModuleFieldInfosByColumn', $module);
374
		}
375
		return Cache::get($cacheName, $module);
376
	}
377
378
	/**
379
	 * Function get module field infos by presence.
380
	 *
381
	 * @param int|string $module
382
	 * @param array      $presence
383
	 *
384
	 * @return array
385
	 */
386
	public static function getModuleFieldInfosByPresence($module, array $presence = ['0', '2']): array
387
	{
388
		$moduleFields = [];
389
		$fieldsInfo = self::getModuleFieldInfos($module);
390
		foreach ($fieldsInfo as $fieldInfo) {
391
			if (\in_array($fieldInfo['presence'], $presence)) {
392
				$moduleFields[$fieldInfo['fieldname']] = $fieldInfo;
393
			}
394
		}
395
		return $moduleFields;
396
	}
397
398
	/**
399
	 * Get fields type from uitype.
400
	 *
401
	 * @return array
402
	 */
403
	public static function getFieldsTypeFromUIType()
404
	{
405
		if (Cache::has('getFieldsTypeFromUIType', '')) {
406
			return Cache::get('getFieldsTypeFromUIType', '');
407
		}
408
		$fieldTypeMapping = (new Db\Query())->from('vtiger_ws_fieldtype')->indexBy('uitype')->all();
409
		Cache::save('getFieldsTypeFromUIType', '', $fieldTypeMapping, Cache::LONG);
410
411
		return $fieldTypeMapping;
412
	}
413
414
	/**
415
	 * Get quick changer fields.
416
	 *
417
	 * @param int $tabId
418
	 *
419
	 * @return array
420
	 */
421
	public static function getQuickChangerFields(int $tabId): array
422
	{
423
		if (Cache::has('getQuickChangerFields', $tabId)) {
424
			return Cache::get('getQuickChangerFields', $tabId);
425
		}
426
		$dataReader = (new Db\Query())->from('s_#__record_quick_changer')->where(['tabid' => $tabId])->createCommand()->query();
427
		$rows = [];
428
		while ($row = $dataReader->read()) {
429
			$row['conditions'] = Json::decode($row['conditions']);
430
			$row['values'] = Json::decode($row['values']);
431
			$rows[$row['id']] = $row;
432
		}
433
		Cache::save('getQuickChangerFields', $tabId, $rows, Cache::LONG);
434
		return $rows;
435
	}
436
437
	/**
438
	 * Check quick changer conditions.
439
	 *
440
	 * @param array                $field
441
	 * @param \Vtiger_Record_Model $recordModel
442
	 *
443
	 * @return void
444
	 */
445
	public static function checkQuickChangerConditions(array $field, \Vtiger_Record_Model $recordModel)
446
	{
447
		$return = false;
448
		foreach ($field['conditions'] as $fieldName => $value) {
449
			if ($recordModel->get($fieldName) !== $value) {
450
				$status = 1;
451
			}
452
		}
453
		if (!isset($status)) {
454
			$fields = $recordModel->getModule()->getFields();
455
			foreach ($field['values'] as $fieldName => $value) {
456
				if (isset($fields[$fieldName]) && $fields[$fieldName]->isEditable()) {
457
					$return = true;
458
				}
459
			}
460
		}
461
		return $return;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $return returns the type boolean which is incompatible with the documented return type void.
Loading history...
462
	}
463
464
	/**
465
	 * Get a list of custom default values for a given field type in the WebservicePremium API.
466
	 *
467
	 * @param \Vtiger_Field_Model $fieldModel
468
	 *
469
	 * @return string[]
470
	 */
471
	public static function getCustomListForDefaultValue(\Vtiger_Field_Model $fieldModel): array
472
	{
473
		if ($fieldModel->isReferenceField()) {
474
			return [
475
				'loggedContact' => \App\Language::translate('LBL_LOGGED_CONTACT', 'Settings:LayoutEditor'),
476
				'accountOnContact' => \App\Language::translate('LBL_ACCOUNT_ON_CONTACT', 'Settings:LayoutEditor'),
477
				'accountLoggedContact' => \App\Language::translate('LBL_ACCOUNT_LOGGED_CONTACT', 'Settings:LayoutEditor'),
478
			];
479
		}
480
		return [];
481
	}
482
}
483