RecordConverter   F
last analyzed

Complexity

Total Complexity 142

Size/Duplication

Total Lines 714
Duplicated Lines 0 %

Test Coverage

Coverage 51.06%

Importance

Changes 0
Metric Value
wmc 142
eloc 267
dl 0
loc 714
ccs 120
cts 235
cp 0.5106
rs 2
c 0
b 0
f 0

29 Methods

Rating   Name   Duplication   Size   Complexity  
C getModuleConverters() 0 29 12
A saveChanges() 0 13 3
A processInventoryMapping() 0 7 5
A processToEdit() 0 11 5
A isPermitted() 0 5 4
A getDestinyModules() 0 10 3
A getInstanceById() 0 15 3
A getRecordModelsWithoutMerge() 0 16 5
A process() 0 14 3
A checkFieldMappingFields() 0 6 4
A getId() 0 3 1
A initFieldValuesByUser() 0 9 6
C initInventoryValuesByUser() 0 45 17
B initInventoryValuesAuto() 0 36 11
A getQuery() 0 14 4
B isAvailable() 0 20 8
A processFieldMapping() 0 6 3
A getRecordsGroupBy() 0 13 4
A setFieldsMapCanExecute() 0 3 5
A initFieldValuesAuto() 0 10 5
B checkIfDuplicateRecordExists() 0 22 9
A setInvMapCanExecute() 0 3 3
A isActive() 0 3 1
A getGroupRecords() 0 5 1
A getMappingFields() 0 11 3
A getQueryForDuplicate() 0 5 1
A init() 0 11 5
A initDestinyModuleValues() 0 6 2
A checkFieldMergeExist() 0 11 6

How to fix   Complexity   

Complex Class

Complex classes like RecordConverter often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use RecordConverter, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * RecordConverter class.
5
 *
6
 * @package App
7
 *
8
 * @copyright YetiForce S.A.
9
 * @license   YetiForce Public License 6.5 (licenses/LicenseEN.txt or yetiforce.com)
10
 * @author    Adrian Kon <[email protected]>
11
 * @author    Mariusz Krzaczkowski <[email protected]>
12
 * @author    Radosław Skrzypczak <[email protected]>
13
 */
14
15
namespace App;
16
17
/**
18
 * Class RecordConverter.
19
 */
20
class RecordConverter extends Base
21
{
22
	/** @var int Field to mapping */
23
	const FIELD_TO_MAPPING = 1;
24
25
	/**
26
	 * Source module name.
27
	 *
28
	 * @var string
29
	 */
30
	public $sourceModule = '';
31
32
	/**
33
	 * Source module model.
34
	 *
35
	 * @var \Vtiger_Module_Model
36
	 */
37
	public $sourceModuleModel;
38
39
	/**
40
	 * Destiny module name.
41
	 *
42
	 * @var string
43
	 */
44
	public $destinyModule = '';
45
46
	/**
47
	 * Destiny module model.
48
	 *
49
	 * @var \Vtiger_Module_Model
50
	 */
51
	public $destinyModuleModel;
52
53
	/**
54
	 * Record models of created records.
55
	 *
56
	 * @var \Vtiger_Record_Model[]
57
	 */
58
	public $cleanRecordModels = [];
59
60
	/**
61
	 * Source record models.
62
	 *
63
	 * @var \Vtiger_Record_Model[]
64
	 */
65
	public $recordModels = [];
66
67
	/**
68
	 * Convert field mapping.
69
	 *
70
	 * @var array|string
71
	 */
72
	public $fieldMapping;
73
74
	/**
75
	 * Convert inventory mapping.
76
	 *
77
	 * @var array|string
78
	 */
79
	public $inventoryMapping;
80
81
	/**
82
	 * Contains values from text parser.
83
	 *
84
	 * @var array
85
	 */
86
	public $textParserValues = [];
87
88
	/**
89
	 * Source module inventory fields.
90
	 *
91
	 * @var array
92
	 */
93
	public $sourceInvFields = [];
94
95
	/**
96
	 * Destiny module inventory fields.
97
	 *
98
	 * @var array
99
	 */
100
	public $destinyInvFields = [];
101
102
	/**
103
	 * Variable determines the possibility of fields mapping.
104
	 *
105
	 * @var bool
106
	 */
107
	public $fieldMappingExecute = false;
108
109
	/**
110
	 * Variable determines the possibility of inventory fields mapping.
111
	 *
112
	 * @var bool
113
	 */
114
	public $inventoryMappingExecute = false;
115
116
	/**
117
	 * Created records ids.
118
	 *
119
	 * @var int[]
120
	 */
121
	public $createdRecords = [];
122
123
	/**
124
	 * @var string
125
	 */
126
	public $error = '';
127
128
	/**
129
	 * Variable determines the type of group records.
130
	 *
131
	 * @var bool
132
	 */
133
	public $groupRecordConvert = false;
134
135
	/**
136
	 * Variable determines if merge field exist.
137
	 *
138
	 * @var bool
139
	 */
140
	public $isFieldMergeExists = false;
141
142
	/**
143
	 * Function to get the instance of the record converter model.
144
	 *
145
	 * @param int    $id
146 1
	 * @param string $moduleName
147
	 *
148 1
	 * @return \self
0 ignored issues
show
Bug introduced by
The type self 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...
149 1
	 */
150
	public static function getInstanceById(int $id, string $moduleName = ''): self
151
	{
152 1
		$query = (new Db\Query())->from('a_#__record_converter')->where(['id' => $id]);
153 1
		if ($moduleName) {
154 1
			$query->andWhere(['source_module' => Module::getModuleId($moduleName)]);
155 1
		}
156
		$row = $query->one(Db::getInstance('admin'));
157
		$self = new self();
158
		if ($row) {
159
			$self->setData($row);
160 1
		} else {
161
			Log::error("Could not find record converter id: $id module name: $moduleName");
162
			throw new Exceptions\AppException('ERR_NOT_FOUND_RECORD_CONVERTER|' . $id);
163
		}
164
		return $self;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $self returns the type App\RecordConverter which is incompatible with the documented return type self.
Loading history...
165
	}
166
167
	/**
168
	 * Function check if convert for module and view exist.
169
	 *
170
	 * @param int|string $moduleName
171 1
	 * @param string     $view
172
	 *
173 1
	 * @return bool
174
	 */
175
	public static function isActive($moduleName, string $view = ''): bool
176
	{
177
		return self::getQuery($moduleName, $view)->exists(Db::getInstance('admin'));
178
	}
179
180
	/**
181
	 * Function check if convert for record and view is available.
182
	 *
183
	 * @param \Vtiger_Record_Model $recordModel
184
	 * @param string               $view
185
	 * @param int|null             $userId
186
	 *
187
	 * @return bool
188
	 */
189
	public static function isAvailable(\Vtiger_Record_Model $recordModel, string $view = '', ?int $userId = null): bool
190
	{
191
		$result = false;
192
		if (null === $userId) {
193
			$userId = \App\User::getCurrentUserId();
194
		}
195
		$dataReader = self::getQuery($recordModel->getModuleName(), $view)->createCommand()->query();
196
		while (!$result && ($row = $dataReader->read())) {
197 1
			$modulePermitted = false;
198
			$destinyModules = array_filter(explode(',', $row['destiny_module']));
199 1
			foreach ($destinyModules as $destinyModuleId) {
200 1
				if (!($modulePermitted = \App\Privilege::isPermitted(\App\Module::getModuleName($destinyModuleId), 'CreateView', false, $userId))) {
201
					break;
202 1
				}
203
			}
204
			$conditions = $row['conditions'] ? \App\Json::decode($row['conditions']) : [];
205 1
			$result = $modulePermitted && \App\Condition::checkConditions($conditions, $recordModel);
206 1
		}
207 1
		$dataReader->close();
208
		return $result;
209 1
	}
210 1
211
	/**
212
	 * Function gets module converters.
213
	 *
214
	 * @param string   $moduleName
215
	 * @param string   $view
216
	 * @param array    $recordIds
217
	 * @param int|null $userId
218 1
	 *
219
	 * @return array
220 1
	 */
221 1
	public static function getModuleConverters(string $moduleName, string $view = '', array $recordIds = [], ?int $userId = null): array
222 1
	{
223 1
		$converters = [];
224 1
		if (null === $userId) {
225 1
			$userId = \App\User::getCurrentUserId();
226 1
		}
227
		$dataReader = self::getQuery($moduleName, $view)->createCommand()->query();
228
		while ($row = $dataReader->read()) {
229
			$modulePermitted = false;
230
			$destinyModules = array_filter(explode(',', $row['destiny_module']));
231
			foreach ($destinyModules as $destinyModuleId) {
232
				if (!($modulePermitted = \App\Privilege::isPermitted(\App\Module::getModuleName($destinyModuleId), 'CreateView', false, $userId))) {
233
					break;
234
				}
235
			}
236
			$conditions = $row['conditions'] ? \App\Json::decode($row['conditions']) : [];
237
			if ($modulePermitted && $conditions && $recordIds) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $recordIds 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...
238
				foreach ($recordIds as $recordId) {
239
					if (\App\Condition::checkConditions($conditions, \Vtiger_Record_Model::getInstanceById($recordId))) {
240
						$converters[$row['id']] = $row;
241
						break;
242
					}
243
				}
244
			} elseif ($modulePermitted) {
245
				$converters[$row['id']] = $row;
246
			}
247
		}
248
		$dataReader->close();
249
		return $converters;
250
	}
251
252
	/**
253
	 * Function return query about module converters in view.
254
	 *
255
	 * @param int|string $moduleName
256
	 * @param string     $view
257 1
	 *
258
	 * @return Db\Query
259 1
	 */
260 1
	public static function getQuery($moduleName, string $view = ''): Db\Query
261 1
	{
262 1
		if (\is_string($moduleName)) {
263 1
			$moduleName = Module::getModuleId($moduleName);
264 1
		}
265
		if (Cache::has('getQueryRecordConverter', $moduleName . $view)) {
266
			return Cache::get('getQueryRecordConverter', $moduleName . $view);
267
		}
268 1
		$query = (new Db\Query())->from('a_#__record_converter')->where(['source_module' => $moduleName, 'status' => 1]);
269 1
		if ($view) {
270 1
			$query->andWhere(['show_in_' . \strtolower($view) => 1]);
271 1
		}
272 1
		Cache::save('getQueryRecordConverter', $moduleName . $view, $query);
273
		return $query;
274
	}
275
276 1
	/**
277
	 * Gets ID.
278
	 *
279
	 * @return int
280 1
	 */
281
	public function getId()
282
	{
283
		return $this->get('id');
284
	}
285
286
	/**
287 1
	 * Function variable initializing.
288
	 *
289 1
	 * @throws Exceptions\AppException
290 1
	 */
291
	public function init()
292
	{
293
		$this->sourceModule = Module::getModuleName($this->get('source_module'));
0 ignored issues
show
Documentation Bug introduced by
It seems like App\Module::getModuleNam...->get('source_module')) can also be of type boolean. However, the property $sourceModule is declared as type string. 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...
294
		$this->sourceModuleModel = \Vtiger_Module_Model::getInstance($this->sourceModule);
295 1
		$this->fieldMapping = $this->get('field_mapping') ? Json::decode($this->get('field_mapping')) : [];
296
		$this->getMappingFields();
297 1
		$this->inventoryMapping = $this->get('inv_field_mapping') ? Json::decode($this->get('inv_field_mapping')) : [];
298 1
		if ($this->sourceModuleModel->isInventory()) {
299
			$this->sourceInvFields = \Vtiger_Inventory_Model::getInstance($this->sourceModule)->getFields();
300
		}
301
		$this->defaultValuesCreatedRecord = $this->get('default_values') ? Json::decode($this->get('default_values')) : [];
0 ignored issues
show
Bug Best Practice introduced by
The property defaultValuesCreatedRecord does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
302
	}
303
304
	/**
305 1
	 * Check permissions.
306
	 *
307 1
	 * @param int $recordId
308 1
	 *
309 1
	 * @return bool
310 1
	 */
311
	public function isPermitted(int $recordId): bool
312
	{
313
		$moduleName = Module::getModuleName($this->get('source_module'));
314
		return \App\Privilege::isPermitted($moduleName, 'RecordConventer') && \App\Privilege::isPermitted($moduleName, 'DetailView', $recordId)
315
			&& (\App\Json::isEmpty($this->get('conditions')) || \App\Condition::checkConditions(\App\Json::decode($this->get('conditions')), \Vtiger_Record_Model::getInstanceById($recordId)));
316
	}
317
318
	/**
319
	 * Gets fields form mapping.
320
	 *
321
	 * @return array
322
	 */
323
	public function getMappingFields(): array
324
	{
325
		if (!isset($this->mapping)) {
326
			$this->mapping = [];
0 ignored issues
show
Bug Best Practice introduced by
The property mapping does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
327
			$dataReader = (new Db\Query())->from('a_#__record_converter_mapping')->where(['id' => $this->getId()])->createCommand()->query();
328
			while ($row = $dataReader->read()) {
329
				$this->mapping[$row['dest_module']][$row['dest_field']] = $row;
330
			}
331
		}
332
333
		return $this->mapping;
334
	}
335
336
	/**
337
	 * Main function of class.
338
	 *
339
	 * @param array $records
340
	 *
341
	 * @throws Exceptions\AppException
342
	 */
343
	public function process(array $records)
344
	{
345
		$this->init();
346
		$recordsAmount = \count($records);
347
		foreach ($this->getDestinyModules() as $destinyModuleName) {
348
			$this->initDestinyModuleValues($destinyModuleName);
349
			$this->checkFieldMergeExist();
350
			$this->setFieldsMapCanExecute($recordsAmount);
351
			$this->setInvMapCanExecute();
352
			if ($this->isFieldMergeExists) {
353
				$this->groupRecordConvert = true;
354
				$this->getRecordsGroupBy($records);
355
			} else {
356
				$this->getRecordModelsWithoutMerge($records);
357
			}
358
		}
359
	}
360
361
	/**
362
	 * Gets destiny modules.
363
	 *
364
	 * @return string[]
365
	 */
366
	public function getDestinyModules(): array
367
	{
368
		$modules = [];
369
		foreach (explode(',', $this->get('destiny_module')) as $destinyModuleId) {
370
			$destinyModuleName = Module::getModuleName($destinyModuleId);
0 ignored issues
show
Bug introduced by
$destinyModuleId of type string 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

370
			$destinyModuleName = Module::getModuleName(/** @scrutinizer ignore-type */ $destinyModuleId);
Loading history...
371
			if (Privilege::isPermitted($destinyModuleName, 'CreateView')) {
372
				$modules[$destinyModuleId] = $destinyModuleName;
373
			}
374
		}
375 1
		return $modules;
376
	}
377 1
378 1
	/**
379 1
	 * Function check if field mapping process can be proced.
380 1
	 *
381
	 * @param int $recordsAmount
382 1
	 */
383 1
	public function setFieldsMapCanExecute(int $recordsAmount)
384 1
	{
385 1
		$this->fieldMappingExecute = $this->fieldMapping && (isset($this->fieldMapping['auto']) || isset($this->fieldMapping['mapping'][$this->destinyModuleModel->getId()])) && (!$this->isFieldMergeExists || 1 === $recordsAmount);
386 1
	}
387 1
388
	/**
389
	 * Function check if inventory mapping process can be proced.
390 1
	 */
391
	public function setInvMapCanExecute()
392
	{
393
		$this->inventoryMappingExecute = $this->inventoryMapping && $this->sourceModuleModel->isInventory() && $this->destinyModuleModel->isInventory();
394
	}
395 1
396
	/**
397 1
	 * Function initializing destiny module values.
398 1
	 *
399
	 * @param string $moduleName
400
	 */
401
	public function initDestinyModuleValues(string $moduleName)
402 1
	{
403
		$this->destinyModule = $moduleName;
404
		$this->destinyModuleModel = \Vtiger_Module_Model::getInstance($this->destinyModule);
405
		if ($this->destinyModuleModel->isInventory()) {
406
			$this->destinyInvFields = \Vtiger_Inventory_Model::getInstance($this->destinyModule)->getFields();
407 1
		}
408 1
	}
409 1
410 1
	/**
411 1
	 * Function to edit process.
412 1
	 *
413
	 * @param int    $record
414
	 * @param string $destinyModule
415 1
	 *
416
	 * @throws Exceptions\AppException
417
	 *
418
	 * @return Vtiger_Module_Model
0 ignored issues
show
Bug introduced by
The type App\Vtiger_Module_Model was not found. Did you mean Vtiger_Module_Model? If so, make sure to prefix the type with \.
Loading history...
419
	 */
420 1
	public function processToEdit(int $record, string $destinyModule): \Vtiger_Record_Model
421
	{
422
		$this->initDestinyModuleValues($destinyModule);
423
		$this->init();
424
		$this->checkFieldMergeExist();
425
		if ($this->fieldMapping && (isset($this->fieldMapping['auto']) || isset($this->fieldMapping['mapping'][$this->destinyModuleModel->getId()])) && $this->isFieldMergeExists) {
426
			$this->fieldMappingExecute = true;
427
		}
428
		$this->setInvMapCanExecute();
429
		$this->getRecordModelsWithoutMerge([$record]);
430
		return \current($this->cleanRecordModels);
431
	}
432
433
	/**
434
	 * Function get query to group records.
435
	 *
436
	 * @param int[] $records
437
	 *
438
	 * @return array
439
	 */
440
	public function getGroupRecords(array $records): array
441
	{
442 1
		$fieldModel = $this->sourceModuleModel->getField($this->get('field_merge'));
443
		$focus = \CRMEntity::getInstance($this->sourceModule);
444 1
		return (new Db\Query())->select([$fieldModel->getTableName() . ".{$fieldModel->getColumnName()}", $focus->tab_name_index[$fieldModel->getTableName()]])->from($fieldModel->getTableName())->where([$focus->tab_name_index[$fieldModel->getTableName()] => $records])->createCommand()->queryAllByGroup(2);
445
	}
446 1
447 1
	/**
448 1
	 * Function prepare records model group by field merge.
449
	 *
450
	 * @param array $records
451
	 */
452
	public function getRecordsGroupBy(array $records)
453 1
	{
454
		foreach ($this->getGroupRecords($records) as $groupBy => $recordsId) {
455
			$this->cleanRecordModels[$groupBy] = \Vtiger_Record_Model::getCleanInstance($this->destinyModule);
456
			$this->cleanRecordModels[$groupBy]->set($this->fieldMapping['field_merge'][$this->destinyModuleModel->getId()], $groupBy);
457
			foreach ($recordsId as $recordId) {
458 1
				if (!isset($this->recordModels[$groupBy][$recordId])) {
459
					$this->recordModels[$groupBy][$recordId] = \Vtiger_Record_Model::getInstanceById($recordId, $this->sourceModule);
460 1
				}
461 1
			}
462 1
			$this->processInventoryMapping();
463
			$this->checkIfDuplicateRecordExists();
464
			$this->saveChanges();
465
		}
466
	}
467 1
468
	/**
469
	 * Function prepare records model.
470
	 *
471
	 * @param array $records
472 1
	 */
473
	public function getRecordModelsWithoutMerge(array $records)
474 1
	{
475 1
		foreach ($records as $recordId) {
476 1
			if (!$this->isPermitted($recordId)) {
477 1
				continue;
478 1
			}
479
			$this->cleanRecordModels[$recordId] = \Vtiger_Record_Model::getCleanInstance($this->destinyModule);
480
			if (!isset($this->recordModels[$recordId])) {
481
				$this->recordModels[$recordId] = \Vtiger_Record_Model::getInstanceById($recordId, $this->sourceModule);
482 1
			}
483 1
			$this->processFieldMapping();
484 1
			$this->checkFieldMappingFields();
485
			$this->processInventoryMapping();
486 1
			$this->checkIfDuplicateRecordExists();
487 1
			if (!$this->get('redirect_to_edit')) {
488 1
				$this->saveChanges();
489 1
			}
490 1
		}
491
	}
492 1
493
	/**
494 1
	 * Function prepare mapping fields.
495 1
	 */
496 1
	public function processFieldMapping()
497 1
	{
498 1
		if (isset($this->inventoryMapping[0]) && 'auto' === $this->inventoryMapping[0]) {
499
			$this->initFieldValuesAuto();
500
		} else {
501
			$this->initFieldValuesByUser();
502 1
		}
503
	}
504
505
	/**
506
	 * Function set values to new record automatically.
507 1
	 */
508 1
	public function initFieldValuesAuto()
509
	{
510
		foreach ($this->cleanRecordModels as $groupBy => $newRecordModel) {
511
			foreach ($this->sourceModuleModel->getFields() as $fieldModel) {
512
				if ('picklist' === $fieldModel->getFieldDataType()) {
513
					if (Fields\Picklist::isExists($fieldModel->getFieldName(), $this->recordModels[$groupBy]->get($fieldModel->getFieldName()))) {
0 ignored issues
show
Deprecated Code introduced by
The function Vtiger_Field_Model::getFieldName() has been deprecated: Use $this->getName() ( Ignorable by Annotation )

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

513
					if (Fields\Picklist::isExists(/** @scrutinizer ignore-deprecated */ $fieldModel->getFieldName(), $this->recordModels[$groupBy]->get($fieldModel->getFieldName()))) {

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...
514
						$newRecordModel->set($fieldModel->getFieldName(), $this->recordModels[$groupBy]->get($fieldModel->getFieldName()));
0 ignored issues
show
Deprecated Code introduced by
The function Vtiger_Field_Model::getFieldName() has been deprecated: Use $this->getName() ( Ignorable by Annotation )

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

514
						$newRecordModel->set(/** @scrutinizer ignore-deprecated */ $fieldModel->getFieldName(), $this->recordModels[$groupBy]->get($fieldModel->getFieldName()));

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...
515
					}
516
				} else {
517
					$newRecordModel->set($fieldModel->getFieldName(), $this->recordModels[$groupBy]->get($fieldModel->getFieldName()));
0 ignored issues
show
Deprecated Code introduced by
The function Vtiger_Field_Model::getFieldName() has been deprecated: Use $this->getName() ( Ignorable by Annotation )

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

517
					$newRecordModel->set(/** @scrutinizer ignore-deprecated */ $fieldModel->getFieldName(), $this->recordModels[$groupBy]->get($fieldModel->getFieldName()));

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...
518
				}
519
			}
520
		}
521
	}
522
523
	/**
524
	 * Function set values to new record defined by user.
525
	 */
526
	public function initFieldValuesByUser()
527
	{
528
		$fieldsData = $this->getMappingFields()[$this->destinyModuleModel->getId()] ?? [];
529
		$destFieldList = $this->destinyModuleModel->getFieldsById();
530
		foreach ($this->cleanRecordModels as $key => $cleanRecordModel) {
531
			$sourceFieldList = $this->recordModels[$key]->getModule()->getFieldsById();
532
			foreach ($fieldsData as $destFieldId => $fieldRow) {
533
				if (self::FIELD_TO_MAPPING === $fieldRow['state'] && ($fieldModel = $destFieldList[$destFieldId])->isEditable() && ($sourceFieldModel = $sourceFieldList[$fieldRow['source_field']])->isActiveField()) {
534
					$cleanRecordModel->set($fieldModel->getName(), $this->recordModels[$key]->get($sourceFieldModel->getName()));
535
				}
536
			}
537
		}
538
	}
539
540
	/**
541
	 * Function save changes in new record models.
542
	 */
543
	public function saveChanges()
544
	{
545
		foreach ($this->cleanRecordModels as $key => $recordModel) {
546
			try {
547
				$recordModel->save();
548
				$this->createdRecords[] = $recordModel->getId();
549
				$this->set('sourceRecord', $this->recordModels[$key]);
550
				$eventHandler = $recordModel->getEventHandler();
551
				$eventHandler->setParams(['converter' => $this]);
552
				$eventHandler->trigger(EventHandler::RECORD_CONVERTER_AFTER_SAVE);
553
				unset($this->cleanRecordModels[$key]);
554
			} catch (\Throwable $ex) {
555
				$this->error = $ex->getMessage();
556
			}
557
		}
558
	}
559
560
	/**
561
	 * Function prepare inventory mapping.
562
	 */
563 1
	public function processInventoryMapping()
564
	{
565 1
		if ($this->inventoryMappingExecute && $this->inventoryMapping) {
566
			if (isset($this->inventoryMapping[0]) && 'auto' === $this->inventoryMapping[0]) {
567
				$this->initInventoryValuesAuto();
568
			} else {
569
				$this->initInventoryValuesByUser();
570
			}
571
		}
572 1
	}
573
574
	/**
575
	 * Function prepare auto inventory mapping.
576
	 */
577 1
	private function initInventoryValuesAuto()
578
	{
579 1
		$invData = [];
580
		$counter = 1;
581
		foreach ($this->cleanRecordModels as $groupBy => $newRecordModel) {
582
			if (!\is_array($this->recordModels[$groupBy])) {
583
				$sourceRecordModels = [$this->recordModels[$groupBy]];
584
			} else {
585
				$sourceRecordModels = $this->recordModels[$groupBy];
586
			}
587
			foreach ($sourceRecordModels as $recordModel) {
588
				if (!\is_array($recordModel)) {
589 1
					$recordModel = [$recordModel];
590 1
				}
591
				foreach ($recordModel as $recordModelGroupBy) {
592
					foreach ($recordModelGroupBy->getInventoryData() as $inventoryRow) {
593
						foreach ($this->destinyInvFields as $columnName => $fieldModel) {
594
							if (isset($this->sourceInvFields[$columnName])) {
595
								$inventoryFieldValue = $inventoryRow[$columnName];
596
							} else {
597
								$inventoryFieldValue = $fieldModel->getDefaultValue();
598
							}
599
							$invData[$groupBy][$counter][$columnName] = $inventoryFieldValue;
600
							$fieldCustomColumn = $fieldModel->getCustomColumn();
601
							if ($fieldCustomColumn) {
602
								foreach (array_keys($fieldCustomColumn) as $customColumn) {
603
									$invData[$groupBy][$counter][$customColumn] = $inventoryRow[$customColumn] ?? [];
604
								}
605
							}
606
						}
607 1
						++$counter;
608
					}
609 1
				}
610
			}
611
		}
612
		$newRecordModel->initInventoryDataFromRequest(new Request(['inventory' => $invData[$groupBy]], false));
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $groupBy seems to be defined by a foreach iteration on line 581. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
Comprehensibility Best Practice introduced by
The variable $newRecordModel seems to be defined by a foreach iteration on line 581. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
613
	}
614
615
	/**
616
	 * Function prepare user inventory mapping.
617
	 */
618
	private function initInventoryValuesByUser()
619
	{
620
		$invData = [];
621
		$counter = 1;
622
		foreach ($this->cleanRecordModels as $groupBy => $newRecordModel) {
623
			if (!\is_array($this->recordModels[$groupBy])) {
624
				$sourceRecordModels = [$this->recordModels[$groupBy]];
625
			} else {
626
				$sourceRecordModels = $this->recordModels[$groupBy];
627
			}
628
			foreach ($sourceRecordModels as $recordModel) {
629
				if (!\is_array($recordModel)) {
630
					$recordModel = [$recordModel];
631
				}
632
				foreach ($recordModel as $recordModelGroupBy) {
633 1
					foreach ($recordModelGroupBy->getInventoryData() as $inventoryRow) {
634
						if (isset($this->inventoryMapping[$this->destinyModuleModel->getId()])) {
635
							foreach ($this->inventoryMapping[$this->destinyModuleModel->getId()] as $destinyField => $sourceField) {
636
								if ($fieldCustomColumn = $this->destinyInvFields[$destinyField]->getCustomColumn()) {
637
									foreach (array_keys($fieldCustomColumn) as $customColumn) {
638
										$invData[$groupBy][$counter][$customColumn] = $inventoryRow[$customColumn] ?? [];
639
									}
640
								}
641
								$invData[$groupBy][$counter][$destinyField] = $inventoryRow[$sourceField];
642
							}
643
						}
644
						foreach ($this->destinyInvFields as $columnName => $fieldModel) {
645
							if (!isset($invData[$groupBy][$counter][$columnName]) && $fieldModel->has('defaultValue')) {
646
								$invData[$groupBy][$counter][$columnName] = $fieldModel->getDefaultValue();
647
							} elseif (!isset($invData[$groupBy][$counter][$columnName])) {
648
								$invData[$groupBy][$counter][$columnName] = $inventoryRow[$columnName];
649
							}
650
							if ($fieldCustomColumn = $fieldModel->getCustomColumn()) {
651
								foreach (array_keys($fieldCustomColumn) as $customColumn) {
652
									$invData[$groupBy][$counter][$customColumn] = '';
653
								}
654
							}
655
						}
656
						$invData[$groupBy][$counter]['id'] = $inventoryRow['id'];
657
						++$counter;
658
					}
659
				}
660
			}
661
		}
662
		$newRecordModel->initInventoryDataFromRequest(new Request(['inventory' => $invData[$groupBy]], false));
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $groupBy seems to be defined by a foreach iteration on line 622. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
Comprehensibility Best Practice introduced by
The variable $newRecordModel seems to be defined by a foreach iteration on line 622. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
663
	}
664
665
	/**
666
	 * Function check mapped fields.
667
	 */
668
	public function checkFieldMappingFields()
669
	{
670
		if (isset($this->fieldMapping['mapping'][$this->destinyModuleModel->getId()])) {
671
			foreach ($this->fieldMapping['mapping'][$this->destinyModuleModel->getId()] as $destinyField => $sourceField) {
672
				if (!$this->destinyModuleModel->getField($destinyField)) {
673
					unset($this->fieldMapping['mapping'][$this->destinyModuleModel->getId()][$destinyField]);
674
				}
675
			}
676
		}
677
	}
678
679
	/**
680
	 * Function check if merge can be execute.
681
	 */
682
	public function checkFieldMergeExist()
683
	{
684
		$this->isFieldMergeExists = false;
685
		if (isset($this->fieldMapping['field_merge'])) {
686
			$destinyReferenceFields = $this->destinyModuleModel->getFieldsByReference();
687
			$referenceDestinyField = $this->fieldMapping['field_merge'][$this->destinyModuleModel->getId()];
688
			if ($referenceDestinyField) {
689
				if (!$this->destinyModuleModel->getField($referenceDestinyField) || !$this->sourceModuleModel->getField($this->get('field_merge')) || !isset($destinyReferenceFields[$referenceDestinyField])) {
690
					$this->isFieldMergeExists = false;
691
				}
692
				$this->isFieldMergeExists = true;
693
			}
694
		}
695
	}
696
697
	/**
698
	 * Function get query for searching duplicates.
699
	 *
700
	 * @return Db\Query
701
	 */
702
	public function getQueryForDuplicate()
703
	{
704
		$focus = \CRMEntity::getInstance($this->destinyModule);
705
		return (new Db\Query())->from($focus->table_name)->innerJoin($focus->customFieldTable[0], $focus->table_name . '.' . $focus->table_index . '=' . $focus->customFieldTable[0] . '.' . $focus->customFieldTable[1])
706
			->innerJoin('vtiger_crmentity', $focus->table_name . '.' . $focus->table_index . '= vtiger_crmentity.crmid');
707
	}
708
709
	/**
710
	 * Function check if exist duplicate of records.
711
	 */
712
	public function checkIfDuplicateRecordExists()
713
	{
714
		if ($this->get('check_duplicate') && isset($this->fieldMapping['field_merge'][$this->destinyModuleModel->getId()])) {
715
			$referenceDestinyField = $this->fieldMapping['field_merge'][$this->destinyModuleModel->getId()];
716
			if ($referenceDestinyField) {
717
				foreach ($this->cleanRecordModels as $groupBy => $recordModel) {
718
					$columnsToCheck = [];
719
					if ($this->isFieldMergeExists) {
720
						if ($this->groupRecordConvert) {
721
							$columnsToCheck[$referenceDestinyField] = $groupBy;
722
						} else {
723
							$sourceRecordModel = \Vtiger_Record_Model::getInstanceById($groupBy, $this->sourceModule);
724
							$columnsToCheck[$referenceDestinyField] = $sourceRecordModel->get($this->get('field_merge'));
725
						}
726
					} else {
727
						foreach ($this->fieldMapping['mapping'][$this->destinyModuleModel->getId()] as $destinyField => $sourceField) {
728
							$columnsToCheck[$destinyField] = $this->textParserValues[$groupBy][$sourceField];
729
						}
730
					}
731
					$query = $this->getQueryForDuplicate();
732
					if ($query->where($columnsToCheck)->exists()) {
733
						unset($this->cleanRecordModels[$groupBy]);
734
					}
735
				}
736
			}
737
		}
738
	}
739
}
740