Test Setup Failed
Push — developer ( 2d5ded...9fe426 )
by Radosław
23:27 queued 05:00
created

setSourceModule()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 2
c 1
b 0
f 0
dl 0
loc 4
ccs 0
cts 1
cp 0
rs 10
cc 1
nc 1
nop 1
crap 2
1
<?php
2
3
/**
4
 * Module Class for MappedFields Settings.
5
 *
6
 * @copyright YetiForce S.A.
7
 * @license   YetiForce Public License 5.0 (licenses/LicenseEN.txt or yetiforce.com)
8
 * @author    Radosław Skrzypczak <[email protected]>
9
 */
10
class Settings_MappedFields_Module_Model extends Settings_Vtiger_Module_Model
11
{
12
	public $baseTable = 'a_yf_mapped_config';
13
	public $mappingTable = 'a_yf_mapped_fields';
14
	public $baseIndex = 'id';
15
	public $mappingIndex = 'mappedid';
16
	public $listFields = [
17
		'tabid' => 'LBL_MODULE',
18
		'reltabid' => 'LBL_REL_MODULE',
19
		'status' => 'LBL_STATUS',
20
	];
21
	public static $allFields = [
22
		'tabid',
23
		'reltabid',
24
		'status',
25
		'conditions',
26
		'permissions',
27
		'params',
28
	];
29
	public static $step1Fields = ['status', 'tabid', 'reltabid'];
30
	public static $step2Fields = ['source', 'target', 'default', 'type'];
31
	public static $step3Fields = ['conditions'];
32
	public static $step4Fields = ['permissions'];
33
	/**
34
	 * @var array Validator for fields
35
	 */
36
	public static $validatorFields = [
37
		'status' => 'Integer',
38
		'tabid' => 'Integer',
39
		'reltabid' => 'Integer',
40
		'permissions' => ['Text'],
41
	];
42
	public $name = 'MappedFields';
43
	public $parent = 'Settings';
44
	/** @var Settings_MappedFields_Module_Model Mapping record */
45
	protected $record;
46
	/** @var Vtiger_Module_Model Source module */
47
	private $sourceModule;
48
49
	public function getCreateRecordUrl()
50
	{
51
		return 'index.php?module=MappedFields&parent=Settings&view=Edit';
52
	}
53
54
	public function getImportViewUrl()
55
	{
56
		return 'index.php?module=MappedFields&parent=Settings&view=Import';
57
	}
58
59
	public function getRecord()
60
	{
61
		return $this->record;
62
	}
63
64
	/**
65
	 * Function to get the Module/Tab id.
66
	 *
67
	 * @return <Number>
0 ignored issues
show
Documentation Bug introduced by
The doc comment <Number> at position 0 could not be parsed: Unknown type name '<' at position 0 in <Number>.
Loading history...
68
	 */
69
	public function getId()
70
	{
71
		return \App\Module::getModuleId($this->getSourceModule()->getName());
72
	}
73
74
	public static function getFieldsByStep($step = 1)
75
	{
76
		switch ($step) {
77
			case 4:
78
				return self::$step4Fields;
79
			case 3:
80
				return self::$step3Fields;
81
			case 2:
82
				return self::$step2Fields;
83
			case 1:
84
			default:
85
				return self::$step1Fields;
86
		}
87
	}
88
89
	/**
90
	 * Function to get the Restricted Ui Types.
91
	 *
92
	 * @return <array> Restricted ui types
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...
93
	 */
94
	public function getRestrictedUitypes()
95
	{
96
		return [4, 51, 52, 57, 58, 69, 70];
97
	}
98
99
	/**
100
	 * Function to get the Restricted Ui Types.
101
	 *
102
	 * @return <array> Restricted ui types
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...
103
	 */
104
	public function getRecordId()
105
	{
106
		return $this->record->getId();
107
	}
108
109
	public static function getSupportedModules()
110
	{
111
		$restrictedModules = ['OSSMailView', 'ModComments'];
112
		$moduleModels = Vtiger_Module_Model::getAll([0, 2]);
113
		$supportedModuleModels = [];
114
		foreach ($moduleModels as $tabId => $moduleModel) {
115
			if ($moduleModel->isEntityModule() && !\in_array($moduleModel->getName(), $restrictedModules)) {
116
				$supportedModuleModels[$tabId] = $moduleModel;
117
			}
118
		}
119
		return $supportedModuleModels;
120
	}
121
122
	/**
123
	 * Function to get instance.
124
	 *
125
	 * @param mixed $moduleName
126
	 *
127
	 * @return Settings_MappedFields_Module_Model
128
	 */
129
	public static function getCleanInstance($moduleName = 'Vtiger')
130
	{
131
		\App\Log::trace('Entering ' . __METHOD__ . '(' . $moduleName . ') method ...');
132
		$handlerClass = Vtiger_Loader::getComponentClassName('Model', 'MappedFields', $moduleName);
133
		$mf = new $handlerClass();
134
		$data = [];
135
		$fields = self::getFieldsByStep();
136
		foreach ($fields as $field) {
137
			$data[$field] = '';
138
		}
139
		$mf->setData($data);
140
		$instance = new self();
141
		$instance->record = $mf;
142
		\App\Log::trace('Exiting ' . __METHOD__ . ' method ...');
143
144
		return $instance;
145
	}
146
147
	/**
148
	 * Function to get the value for a given key.
149
	 *
150
	 * @param $key
151
	 *
152
	 * @return Value for the given key
153
	 */
154
	public function get($key)
155
	{
156
		return $this->record->get($key);
157
	}
158
159
	/**
160
	 * Function to get instance of module.
161
	 *
162
	 * @param string $moduleName
163
	 *
164
	 * @return Settings_MappedFields_Module_Model|null
165
	 */
166
	public static function getInstance($moduleName = 'Settings:Vtiger')
167
	{
168
		$instance = null;
169
		$moduleModel = Vtiger_Module_Model::getInstance($moduleName);
170
		if ($moduleModel) {
0 ignored issues
show
introduced by
$moduleModel is of type Vtiger_Module_Model, thus it always evaluated to true.
Loading history...
171
			$instance = new self();
172
			$instance->setSourceModule($moduleModel);
173
		}
174
175
		return $instance;
176
	}
177
178
	/**
179
	 * Set source module model.
180
	 *
181
	 * @param Vtiger_Module_Model $moduleModel
182
	 *
183
	 * @return $this
184
	 */
185
	public function setSourceModule(Vtiger_Module_Model $moduleModel)
186
	{
187
		$this->sourceModule = $moduleModel;
188
		return $this;
189
	}
190
191
	/**
192
	 * Get source module model.
193
	 *
194
	 * @return Vtiger_Module_Model
195
	 */
196
	public function getSourceModule()
197
	{
198
		return $this->sourceModule;
199
	}
200
201
	public static function getInstanceById($recordId, $moduleName = 'Vtiger')
202
	{
203
		\App\Log::trace('Entering ' . __METHOD__ . '(' . $recordId . ',' . $moduleName . ') method ...');
204
		$instance = new self();
205
		$instance->record = Vtiger_MappedFields_Model::getInstanceById($recordId, $moduleName);
0 ignored issues
show
Documentation Bug introduced by
It seems like Vtiger_MappedFields_Mode...$recordId, $moduleName) can also be of type false. However, the property $record is declared as type Settings_MappedFields_Module_Model. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
206
		\App\Log::trace('Exiting ' . __METHOD__ . ' method ...');
207
208
		return $instance;
209
	}
210
211
	/**
212
	 * Function to get mapping details.
213
	 *
214
	 * @return <Array> list of mapping details
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...
215
	 */
216
	public function getMapping()
217
	{
218
		return $this->record->getMapping();
219
	}
220
221
	/**
222
	 * Function to set mapping details.
223
	 *
224
	 * @param mixed $mapp
225
	 *
226
	 * @return instance
0 ignored issues
show
Bug introduced by
The type instance 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...
227
	 */
228
	public function setMapping($mapp = [])
229
	{
230
		$this->record->setMapping($mapp);
231
232
		return $this;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this returns the type Settings_MappedFields_Module_Model which is incompatible with the documented return type instance.
Loading history...
233
	}
234
235
	/**
236
	 * Function to set mapping details.
237
	 *
238
	 * @return instance
239
	 */
240
	public static function getSpecialFields()
241
	{
242
		$fields = ['id' => ['name' => 'id', 'id' => 'id', 'fieldDataType' => 'reference', 'label' => 'LBL_SELF_ID', 'typeofdata' => 'SELF']];
243
		$models = [];
244
		foreach ($fields as $fieldName => $data) {
245
			$fieldInstane = Settings_MappedFields_Field_Model::fromArray($data);
246
			$models[$fieldName] = $fieldInstane;
247
		}
248
		return $models;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $models returns the type array which is incompatible with the documented return type instance.
Loading history...
249
	}
250
251
	/**
252
	 * Function returns fields of module.
253
	 *
254
	 * @param mixed $source
255
	 *
256
	 * @return vtlib\Field[]
257
	 */
258
	public function getFields($source = false)
259
	{
260
		$moduleModel = $this->sourceModule;
261
		$fields = [];
262
		foreach ($moduleModel->getFields() as $fieldName => $fieldModel) {
263
			if ($fieldModel->isActiveField() && !(false === $source && !($fieldModel->isEditable() && !\in_array($fieldModel->getUIType(), $this->getRestrictedUitypes())))) {
264
				$blockName = $fieldModel->getBlockName();
265
				if (!$blockName) {
266
					$blockName = 'LBL_NOT_ASSIGNET_TO_BLOCK';
267
				}
268
				$fields[$blockName][$fieldModel->getId()] = Settings_MappedFields_Field_Model::getInstanceFromWebserviceFieldObject($fieldModel);
269
			}
270
		}
271
		if ($source) {
272
			foreach ($this->getSpecialFields() as $fieldName => $fieldInstance) {
273
				$fields['LBL_NOT_ASSIGNET_TO_BLOCK'][$fieldName] = $fieldInstance;
274
			}
275
		}
276
277
		if ($moduleModel->isInventory()) {
278
			$inventoryModel = Vtiger_Inventory_Model::getInstance($this->getSourceModule()->getName());
0 ignored issues
show
Bug introduced by
$this->getSourceModule()->getName() of type boolean is incompatible with the type string expected by parameter $moduleName of Vtiger_Inventory_Model::getInstance(). ( Ignorable by Annotation )

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

278
			$inventoryModel = Vtiger_Inventory_Model::getInstance(/** @scrutinizer ignore-type */ $this->getSourceModule()->getName());
Loading history...
279
			$blockName = 'LBL_ADVANCED_BLOCK';
280
			foreach ($inventoryModel->getFields() as $field) {
281
				$fields[$blockName][$field->getColumnName()] = Settings_MappedFields_Field_Model::getInstanceFromInventoryFieldObject($field);
282
			}
283
		}
284
285
		return $fields;
286
	}
287
288
	public function deleteMapping($mappedIds)
289
	{
290
		\App\Log::trace('Entering ' . __METHOD__ . '() method ...');
291
		if (!\is_array($mappedIds)) {
292
			$mappedIds = [$mappedIds];
293
		}
294
		\App\Db::getInstance()->createCommand()->delete($this->mappingTable, [$this->mappingIndex => $mappedIds])
295
			->execute();
296
		\App\Log::trace('Exiting ' . __METHOD__ . ' method ...');
297
	}
298
299
	public function delete()
300
	{
301
		\App\Cache::delete('MappedFieldsTemplatesByModule', \App\Module::getModuleName($this->record->get('tabid')));
0 ignored issues
show
Bug introduced by
$this->record->get('tabid') of type Value is incompatible with the type integer expected by parameter $tabId of App\Module::getModuleName(). ( Ignorable by Annotation )

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

301
		\App\Cache::delete('MappedFieldsTemplatesByModule', \App\Module::getModuleName(/** @scrutinizer ignore-type */ $this->record->get('tabid')));
Loading history...
302
		return \App\Db::getInstance()->createCommand()->delete($this->baseTable, [$this->baseIndex => $this->getRecordId()])
303
			->execute();
304
	}
305
306
	public function importsAllowed()
307
	{
308
		return (new \App\Db\Query())->from($this->baseTable)
309
			->where(['tabid' => $this->get('tabid'), 'reltabid' => $this->get('reltabid')])
310
			->count();
311
	}
312
313
	public function save($saveMapping = false)
314
	{
315
		\App\Log::trace('Entering ' . __METHOD__ . '(' . $saveMapping . ') method ...');
316
		$db = \App\Db::getInstance();
317
		$fields = self::$allFields;
318
		$params = [];
319
		foreach ($fields as $field) {
320
			$value = $this->record->get($field);
321
			if (\in_array($field, ['conditions', 'params'])) {
322
				$params[$field] = \App\Json::encode($value);
323
			} elseif (\is_array($value)) {
324
				$params[$field] = implode(',', $value);
325
			} else {
326
				$params[$field] = $value;
327
			}
328
		}
329
		if (!$this->getRecordId()) {
330
			$db->createCommand()->insert($this->baseTable, $params)->execute();
331
			$this->record->set('id', $db->getLastInsertID($this->baseTable . '_id_seq'));
332
		} else {
333
			$db->createCommand()->update($this->baseTable, $params, [$this->baseIndex => $this->getRecordId()])->execute();
334
		}
335
		if ($saveMapping) {
336
			$stepFields = self::getFieldsByStep(2);
337
			$this->deleteMapping($this->getRecordId());
338
			foreach ($this->getMapping() as $mapp) {
339
				$params = [];
340
				$params[$this->mappingIndex] = $this->getRecordId();
341
				foreach ($stepFields as $name) {
342
					if (isset($mapp[$name])) {
343
						$params[$name] = $mapp[$name];
344
					}
345
				}
346
				if (!empty($params['source']) && !empty($params['target'])) {
347
					$db->createCommand()->insert($this->mappingTable, $params)->execute();
348
				}
349
			}
350
		}
351
		\App\Cache::delete('MappedFieldsTemplatesByModule', \App\Module::getModuleName($this->record->get('tabid')));
0 ignored issues
show
Bug introduced by
$this->record->get('tabid') of type Value is incompatible with the type integer expected by parameter $tabId of App\Module::getModuleName(). ( Ignorable by Annotation )

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

351
		\App\Cache::delete('MappedFieldsTemplatesByModule', \App\Module::getModuleName(/** @scrutinizer ignore-type */ $this->record->get('tabid')));
Loading history...
352
		\App\Log::trace('Exiting ' . __METHOD__ . ' method ...');
353
354
		return $this->getRecordId();
355
	}
356
357
	/**
358
	 * Function transforms Advance filter to workflow conditions.
359
	 */
360
	public function transformAdvanceFilterToWorkFlowFilter()
361
	{
362
		\App\Log::trace('Entering ' . __METHOD__ . '() method ...');
363
		$conditions = $this->get('conditions');
364
		$wfCondition = [];
365
		if (!empty($conditions)) {
366
			foreach ($conditions as $index => $condition) {
367
				$columns = $condition['columns'];
368
				if ('1' == $index && empty($columns)) {
369
					$wfCondition[] = ['fieldname' => '', 'operation' => '', 'value' => '', 'valuetype' => '',
370
						'joincondition' => '', 'groupid' => '0', ];
371
				}
372
				if (!empty($columns) && \is_array($columns)) {
373
					foreach ($columns as $column) {
374
						$wfCondition[] = ['fieldname' => $column['columnname'], 'operation' => $column['comparator'],
375
							'value' => $column['value'], 'valuetype' => $column['valuetype'], 'joincondition' => $column['column_condition'],
376
							'groupjoin' => $condition['condition'] ?? '', 'groupid' => $column['groupid'], ];
377
					}
378
				}
379
			}
380
		}
381
		$this->getRecord()->set('conditions', $wfCondition);
382
		\App\Log::trace('Exiting ' . __METHOD__ . ' method ...');
383
	}
384
385
	public function import($qualifiedModuleName = false)
386
	{
387
		$id = '';
388
		$fileInstance = \App\Fields\File::loadFromRequest($_FILES['imported_xml']);
389
		if (!$fileInstance->validate() || 'xml' !== $fileInstance->getExtension(true)) {
390
			$message = 'LBL_UPLOAD_ERROR';
391
		} else {
392
			[$id, $message] = $this->importDataFromXML($fileInstance->getPath());
393
		}
394
		return ['id' => $id, 'message' => \App\Language::translate($message, $qualifiedModuleName)];
395
	}
396
397
	public function importDataFromXML($uploadedXml)
398
	{
399
		$combine = ['tabid' => 'source', 'reltabid' => 'target'];
400
		$instances = [];
401
		$i = 0;
402
		$mapping = [];
403
		$xml = simplexml_load_file($uploadedXml);
404
		foreach ($xml as $fieldsKey => $fieldsValue) {
405
			if (\array_key_exists($fieldsKey, $combine)) {
406
				$value = (int) \App\Module::getModuleId((string) $fieldsValue);
407
				if (empty($value)) {
408
					break;
409
				}
410
				$instances[$combine[$fieldsKey]] = Vtiger_Module_Model::getInstance((string) $fieldsValue);
411
			} elseif ('fields' === $fieldsKey) {
412
				foreach ($fieldsValue as $fieldValue) {
413
					foreach ($fieldValue as $columnKey => $columnValue) {
414
						$columnKey = (string) $columnKey;
415
						$columnValue = (string) $columnValue;
416
						if (\in_array($columnKey, ['default', 'type'])) {
417
							$mapping[$i][$columnKey] = 'default' === $columnKey ? \App\Purifier::purify($columnValue) : $columnValue;
418
							continue;
419
						}
420
						$fieldObject = Settings_MappedFields_Field_Model::getInstance($columnValue, $instances[$columnKey], $mapping[$i]['type']);
421
						if (!$fieldObject) {
422
							continue;
423
						}
424
						$mapping[$i][$columnKey] = $fieldObject->getId();
425
					}
426
					++$i;
427
				}
428
				continue;
429
			} else {
430
				$value = (string) $fieldsValue;
431
			}
432
			$this->getRecord()->set($fieldsKey, $value);
433
		}
434
		$tabid = $this->getRecord()->get('tabid');
435
		$reltabid = $this->getRecord()->get('reltabid');
436
		if (empty($tabid) || empty($reltabid)) {
437
			$id = null;
438
			$message = 'LBL_MODULE_NOT_EXIST';
439
		} elseif (!$this->importsAllowed()) {
440
			$this->setMapping($mapping);
441
			$this->save(true);
442
			$message = 'LBL_IMPORT_OK';
443
			$id = $this->getRecordId();
444
		} else {
445
			$id = null;
446
			$message = 'LBL_NO_PERMISSION_TO_IMPORT';
447
		}
448
		return [$id, $message];
449
	}
450
}
451