ModTracker_Record_Model   F
last analyzed

Complexity

Total Complexity 99

Size/Duplication

Total Lines 623
Duplicated Lines 0 %

Test Coverage

Coverage 5.28%

Importance

Changes 0
Metric Value
wmc 99
eloc 279
dl 0
loc 623
ccs 14
cts 265
cp 0.0528
rs 2
c 0
b 0
f 0

38 Methods

Rating   Name   Duplication   Size   Complexity  
A getModuleName() 0 3 1
A getUpdates() 0 24 3
B getUnreviewed() 0 37 10
A isNewChange() 0 12 3
A setLastReviewed() 0 19 2
A getModule() 0 6 2
A getDetailViewUrl() 0 14 3
A unsetReviewed() 0 22 5
A isReviewed() 0 11 3
A isRelationLink() 0 3 1
A isDisplayed() 0 3 1
A isRelationUnLink() 0 3 1
A isTransferLink() 0 3 1
A isCreate() 0 3 1
A getParent() 0 3 1
A getStatusLabel() 0 3 1
A isConvertToAccount() 0 3 1
A setParent() 0 4 1
A isTransferDelete() 0 3 1
A isChangeState() 0 3 1
A isTransferEdit() 0 3 1
A isTransferUnLink() 0 3 1
A isUpdate() 0 3 1
A isShowHiddenData() 0 3 1
A checkStatus() 0 7 2
A getActivityTime() 0 3 1
A getDisplayActivityTime() 0 6 1
A getModifierName() 0 3 1
A getModifiedBy() 0 3 1
B getFieldInstances() 0 21 8
B getLastRelation() 0 27 8
C getInventoryChanges() 0 32 14
A getFieldHistory() 0 14 2
A getConditionByType() 0 14 3
A getTotalRecordCount() 0 4 1
A setLastRelation() 0 22 4
A getRelationInstance() 0 8 5
A addConvertToAccountRelation() 0 13 1

How to fix   Complexity   

Complex Class

Complex classes like ModTracker_Record_Model 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 ModTracker_Record_Model, and based on these observations, apply Extract Interface, too.

1
<?php
2
/* +***********************************************************************************
3
 * The contents of this file are subject to the vtiger CRM Public License Version 1.0
4
 * ("License"); You may not use this file except in compliance with the License
5
 * The Original Code is:  vtiger CRM Open Source
6
 * The Initial Developer of the Original Code is vtiger.
7
 * Portions created by vtiger are Copyright (C) vtiger.
8
 * All Rights Reserved.
9
 * Contributor(s): YetiForce S.A.
10
 * *********************************************************************************** */
11
12
class ModTracker_Record_Model extends Vtiger_Record_Model
13
{
14
	const UPDATE = 0;
15
	const DELETE = 1;
16
	const CREATE = 2;
17
	const ACTIVE = 3;
18
	const LINK = 4;
19
	const UNLINK = 5;
20
	const CONVERTTOACCOUNT = 6;
21
	const DISPLAYED = 7;
22
	const ARCHIVED = 8;
23
	const REMOVED = 9;
24
	const TRANSFER_EDIT = 10;
25
	const TRANSFER_DELETE = 11;
26
	const TRANSFER_UNLINK = 12;
27
	const TRANSFER_LINK = 13;
28
	const SHOW_HIDDEN_DATA = 14;
29
30
	/**
31
	 * Status labels.
32
	 *
33
	 * @var string[]
34
	 */
35
	public static $statusLabel = [
36
		0 => 'LBL_UPDATED',
37
		1 => 'LBL_DELETED',
38
		2 => 'LBL_CREATED',
39
		3 => 'LBL_ACTIVE',
40
		4 => 'LBL_ADDED',
41
		5 => 'LBL_UNLINK',
42
		6 => 'LBL_CONVERTED_FROM_LEAD',
43
		7 => 'LBL_DISPLAYED',
44
		8 => 'LBL_ARCHIVED',
45
		9 => 'LBL_REMOVED',
46
		10 => 'LBL_TRANSFER_EDIT',
47
		11 => 'LBL_TRANSFER_DELETE',
48
		12 => 'LBL_TRANSFER_UNLINK',
49
		13 => 'LBL_TRANSFER_LINK',
50
		14 => 'LBL_SHOW_HIDDEN_DATA',
51
	];
52
53
	/**
54
	 * Function to get the history of updates on a record.
55
	 *
56
	 * @param int                 $parentRecordId
57
	 * @param Vtiger_Paging_Model $pagingModel
58
	 * @param string              $type
59
	 * @param int|null            $startWith
60
	 *
61
	 * @return self[] - list of  ModTracker_Record_Model
62
	 */
63
	public static function getUpdates(int $parentRecordId, Vtiger_Paging_Model $pagingModel, string $type, ?int $startWith = null)
64
	{
65
		$recordInstances = [];
66
		$startIndex = $pagingModel->getStartIndex();
67
		$pageLimit = $pagingModel->getPageLimit();
68
		$where = self::getConditionByType($type);
69
		$query = (new \App\Db\Query())
70
			->from('vtiger_modtracker_basic')
71
			->where(['crmid' => $parentRecordId])
72
			->andWhere($where)
73
			->limit($pageLimit)
74
			->offset($startIndex)
75
			->orderBy(['changedon' => SORT_DESC]);
76
		if (!empty($startWith)) {
77
			$query->andWhere(['>=', 'id', $startWith]);
78
		}
79
		$dataReader = $query->createCommand()->query();
80
		while ($row = $dataReader->read()) {
81
			$recordInstance = new self();
82
			$recordInstance->setData($row)->setParent($row['crmid'], $row['module']);
83
			$recordInstances[] = $recordInstance;
84
		}
85
		$dataReader->close();
86
		return $recordInstances;
87
	}
88
89
	public static function setLastReviewed($recordId)
90
	{
91
		$row = (new App\Db\Query())->select(['last_reviewed_users', 'id'])
92
			->from('vtiger_modtracker_basic')
93
			->where(['crmid' => $recordId])
94
			->andWhere(['<>', 'status', self::DISPLAYED])
95
			->orderBy(['changedon' => SORT_DESC, 'id' => SORT_DESC])
96
			->limit(1)
97
			->one();
98
		if ($row) {
99
			$lastReviewedUsers = explode('#', $row['last_reviewed_users']);
100
			$lastReviewedUsers[] = Users_Record_Model::getCurrentUserModel()->getRealId();
101
			\App\Db::getInstance()->createCommand()
102 20
				->update('vtiger_modtracker_basic', ['last_reviewed_users' => '#' . implode('#', array_filter($lastReviewedUsers)) . '#'], ['id' => $row['id']])
103
				->execute();
104 20
105
			return $row['id'];
106
		}
107
		return false;
108 20
	}
109 20
110 20
	public static function unsetReviewed($recordId, $userId = false, $exception = false)
111 20
	{
112 20
		if (!$userId) {
113
			$currentUser = Users_Record_Model::getCurrentUserModel();
114 20
			$userId = $currentUser->getRealId();
115 20
		}
116 20
		$query = new \App\Db\Query();
117 20
		$query->select(['last_reviewed_users', 'id'])->from('vtiger_modtracker_basic')->where(['crmid' => $recordId])
118 20
			->andWhere(['<>', 'status', self::DISPLAYED])->andWhere(['like', 'last_reviewed_users', "#$userId#"])->orderBy(['changedon' => SORT_DESC, 'id' => SORT_DESC])->limit(1);
119 20
		if ($exception) {
120
			$query->andWhere(['<>', 'id', $exception]);
121 20
		}
122
		$row = $query->one();
123
		if ($row) {
124
			$lastReviewedUsers = array_filter(explode('#', $row['last_reviewed_users']));
125
			$key = array_search($userId, $lastReviewedUsers);
126
			unset($lastReviewedUsers[$key]);
127
			$value = empty($lastReviewedUsers) ? '' : '#' . implode('#', array_filter($lastReviewedUsers)) . '#';
128
129
			return App\Db::getInstance()->createCommand()->update('vtiger_modtracker_basic', ['last_reviewed_users' => $value], ['id' => $row['id']])->execute();
130
		}
131
		return false;
132
	}
133
134
	/**
135
	 * Checks if is new changes.
136
	 *
137
	 * @param int $recordId
138
	 * @param int $userId
139
	 *
140
	 * @return bool
141
	 */
142
	public static function isNewChange(int $recordId, int $userId = 0): bool
143
	{
144
		if (0 === $userId) {
145
			$userId = App\User::getCurrentUserId();
146
		}
147
		$lastReviewedUsers = (new \App\Db\Query())->select(['last_reviewed_users'])->from('vtiger_modtracker_basic')
148
			->where(['crmid' => $recordId])
149
			->andWhere(['<>', 'status', self::DISPLAYED])->orderBy(['changedon' => SORT_DESC, 'id' => SORT_DESC])->scalar();
150
		if (false !== $lastReviewedUsers) {
151
			return false === strpos($lastReviewedUsers, "#$userId#");
152
		}
153
		return true;
154
	}
155
156
	/**
157
	 * Gets unreviewed entries.
158
	 *
159
	 * @param int|int[] $recordsId
160
	 * @param bool|int  $userId
161
	 * @param bool      $sort
162
	 *
163
	 * @return array
164
	 */
165
	public static function getUnreviewed($recordsId, $userId = false, $sort = false)
166
	{
167
		if (false === $userId) {
168
			$userId = \App\User::getCurrentUserId();
169
		}
170
		$query = (new \App\Db\Query())->select(['crmid', 'u' => 'last_reviewed_users'])->from('vtiger_modtracker_basic')
171
			->where(['crmid' => $recordsId])
172
			->andWhere(['not in', 'status', [self::DISPLAYED, self::SHOW_HIDDEN_DATA]]);
173
		if ($sort) {
174
			$query->addSelect(['vtiger_ossmailview.type'])
175
				->leftJoin('vtiger_modtracker_relations', 'vtiger_modtracker_basic.id = vtiger_modtracker_relations.id')
176
				->leftJoin('vtiger_ossmailview', 'vtiger_modtracker_relations.targetid = vtiger_ossmailview.ossmailviewid')
177
				->orderBy('vtiger_modtracker_basic.crmid ,vtiger_modtracker_basic.id DESC');
178
		}
179
		$dataReader = $query->createCommand()->query();
180
		$changes = [];
181
		while ($row = $dataReader->read()) {
182
			$changes[$row['crmid']][] = $row;
183
		}
184
		$dataReader->close();
185
		$unreviewed = [];
186
		foreach ($changes as $crmId => $rows) {
187
			$all = $mails = 0;
188
			foreach ($rows as $row) {
189
				if (false !== strpos($row['u'], "#$userId#")) {
190
					break;
191
				}
192
				if (isset($row['type']) && 1 === (int) $row['type']) {
193
					++$mails;
194
				} elseif (!isset($row['type'])) {
195
					++$all;
196
				}
197
			}
198
			$unreviewed[$crmId]['a'] = $all;
199
			$unreviewed[$crmId]['m'] = $mails;
200
		}
201
		return $unreviewed;
202
	}
203
204
	/**
205
	 * Function to get the name of the module to which the record belongs.
206
	 *
207
	 * @return Vtiger_Module_Model
208
	 */
209
	public function getModule(): Vtiger_Module_Model
210
	{
211
		if (empty($this->parent)) {
212
			return Vtiger_Module_Model::getInstance($this->getModuleName());
213
		}
214
		return $this->getParent()->getModule();
215
	}
216
217
	/**
218
	 * Function to get the name of the module to which the record belongs.
219
	 *
220
	 * @return string - Record Module Name
221
	 */
222
	public function getModuleName(): string
223
	{
224
		return $this->get('module');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->get('module') 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...
225
	}
226
227
	/**
228
	 * Function to get the Detail View url for the record.
229
	 *
230
	 * @return string - Record Detail View Url
231
	 */
232
	public function getDetailViewUrl()
233
	{
234
		$moduleName = $this->getModuleName();
235
		switch ($moduleName) {
236
			case 'Documents':
237
				return 'file.php?module=Documents&action=DownloadFile&record=' . $this->get('crmid');
238
			case 'OSSMailView':
239
				$action = 'view=preview';
240
				break;
241
			default:
242
				$action = 'view=Detail';
243
				break;
244
		}
245
		return "index.php?module=$moduleName&$action&record=" . $this->get('crmid');
246
	}
247
248
	/**
249
	 * Undocumented function.
250
	 *
251
	 * @param int    $id
252
	 * @param string $moduleName
253
	 *
254
	 * @return $this
255
	 */
256
	public function setParent($id, $moduleName)
257
	{
258
		$this->parent = Vtiger_Record_Model::getInstanceById($id, $moduleName);
0 ignored issues
show
Bug Best Practice introduced by
The property parent does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
259
		return $this;
260
	}
261
262
	public function getParent()
263
	{
264
		return $this->parent;
265
	}
266
267
	public function checkStatus($callerStatus)
268
	{
269
		$status = $this->get('status');
270
		if ($status == $callerStatus) {
271
			return true;
272
		}
273
		return false;
274
	}
275
276
	public function isConvertToAccount()
277
	{
278
		return $this->checkStatus(self::CONVERTTOACCOUNT);
279
	}
280
281
	public function isCreate()
282
	{
283
		return $this->checkStatus(self::CREATE);
284
	}
285
286
	public function isUpdate()
287
	{
288
		return $this->checkStatus(self::UPDATE);
289
	}
290
291
	public function isRelationLink()
292
	{
293
		return $this->checkStatus(self::LINK);
294
	}
295
296
	public function isRelationUnLink()
297
	{
298
		return $this->checkStatus(self::UNLINK);
299
	}
300
301
	public function isDisplayed()
302
	{
303
		return $this->checkStatus(self::DISPLAYED);
304
	}
305
306
	/**
307
	 * Function check if status is Transfer.
308
	 *
309
	 * @return bool
310
	 */
311
	public function isTransferEdit()
312
	{
313
		return $this->checkStatus(static::TRANSFER_EDIT);
314
	}
315
316
	/**
317
	 * Function check if status is Transfer.
318
	 *
319
	 * @return bool
320
	 */
321
	public function isTransferLink()
322
	{
323
		return $this->checkStatus(static::TRANSFER_LINK);
324
	}
325
326
	/**
327
	 * Function check if status is Transfer.
328
	 *
329
	 * @return bool
330
	 */
331
	public function isTransferUnLink()
332
	{
333
		return $this->checkStatus(static::TRANSFER_UNLINK);
334
	}
335
336
	/**
337
	 * Function check if status is Transfer.
338
	 *
339
	 * @return bool
340
	 */
341
	public function isTransferDelete()
342
	{
343
		return $this->checkStatus(static::TRANSFER_DELETE);
344
	}
345
346
	/**
347
	 * Function check if status is Transfer.
348
	 *
349
	 * @return bool
350
	 */
351
	public function isShowHiddenData()
352
	{
353
		return $this->checkStatus(static::SHOW_HIDDEN_DATA);
354
	}
355
356
	/**
357
	 * Has changed state.
358
	 *
359
	 * @return bool
360
	 */
361
	public function isChangeState()
362
	{
363
		return \in_array($this->get('status'), [1, 3, 8]);
364
	}
365
366
	public function isReviewed($userId = false)
367
	{
368
		if (false === $userId) {
369
			$currentUser = Users_Record_Model::getCurrentUserModel();
370
			$userId = $currentUser->getId();
371
		}
372
		$reviewed = $this->get('last_reviewed_users');
373
		if (empty($reviewed)) {
374
			return false;
375
		}
376
		return false !== strpos($reviewed, "#$userId#");
377
	}
378
379
	/**
380
	 * Get status label.
381
	 *
382
	 * @return string
383
	 */
384
	public function getStatusLabel()
385
	{
386
		return static::$statusLabel[$this->get('status')];
387
	}
388
389
	/**
390
	 * Get the modifier object.
391
	 *
392
	 * @return \App\User
393
	 */
394
	public function getModifiedBy()
395
	{
396
		return \App\User::getUserModel($this->get('whodid'));
397
	}
398
399
	/**
400
	 * Get name for modifier by.
401
	 *
402
	 * @return string|bool
403
	 */
404
	public function getModifierName()
405
	{
406
		return \App\Fields\Owner::getUserLabel($this->get('whodid'));
407
	}
408
409
	public function getDisplayActivityTime()
410
	{
411
		$time = $this->getActivityTime();
412
		$time = new DateTimeField($time);
413
414
		return $time->getFullcalenderDateTimevalue();
415
	}
416
417
	public function getActivityTime()
418
	{
419
		return $this->get('changedon');
420
	}
421
422
	/**
423
	 * Function return Modtracker Field Model.
424
	 *
425
	 * @return \ModTracker_Field_Model[]
426
	 */
427
	public function getFieldInstances()
428
	{
429
		$fieldInstances = [];
430
		if ($this->isCreate() || $this->isUpdate() || $this->isTransferEdit()) {
431
			$dataReader = (new \App\Db\Query())->from('vtiger_modtracker_detail')->where(['id' => $this->get('id')])->createCommand()->query();
432
			while ($row = $dataReader->read()) {
433
				$row['prevalue'] = html_entity_decode((string) $row['prevalue']);
434
				$row['postvalue'] = html_entity_decode((string) $row['postvalue']);
435
				if ('record_id' === $row['fieldname'] || 'record_module' === $row['fieldname']) {
436
					continue;
437
				}
438
				if (!($fieldModel = $this->getModule()->getFieldByName($row['fieldname']))) {
439
					continue;
440
				}
441
				$fieldInstance = new ModTracker_Field_Model();
442
				$fieldInstance->setData($row)->setParent($this->getParent())->setFieldInstance($fieldModel);
443
				$fieldInstances[] = $fieldInstance;
444
			}
445
			$dataReader->close();
446
		}
447
		return $fieldInstances;
448
	}
449
450
	/**
451
	 * Gets inventory changes.
452
	 *
453
	 * @throws \App\Exceptions\AppException
454
	 *
455
	 * @return array
456
	 */
457
	public function getInventoryChanges()
458
	{
459
		if (!isset($this->inventoryChanges)) {
460
			$changes = [];
461
			if ($this->isCreate() || $this->isUpdate() || $this->isTransferEdit()) {
462
				$inventoryModel = Vtiger_Inventory_Model::getInstance($this->getParent()->getModuleName());
463
				$data = (new \App\Db\Query())->select(['changes'])->from('u_#__modtracker_inv')->where(['id' => $this->get('id')])->scalar();
464
				$data = $data ? \App\Json::decode($data) : [];
465
				foreach ($data as $key => $changed) {
466
					if (!\vtlib\Functions::getCRMRecordMetadata($changed['item'])) {
467
						continue;
468
					}
469
					$changes[$key]['item'] = $changed['item'];
470
					$changes[$key]['historyState'] = empty($changed['prevalue']) ? 'LBL_INV_ADDED' : (empty($changed['postvalue']) ? 'LBL_INV_DELETED' : 'LBL_INV_UPDATED');
471
					$changes[$key]['data'] = [];
472
					foreach ($changed['prevalue'] as $fieldName => $value) {
473
						if ($inventoryModel->isField($fieldName)) {
474
							$changes[$key]['data'][$fieldName]['field'] = $inventoryModel->getField($fieldName);
475
							$changes[$key]['data'][$fieldName]['prevalue'] = $value;
476
						}
477
					}
478
					foreach ($changed['postvalue'] as $fieldName => $value) {
479
						if ($inventoryModel->isField($fieldName)) {
480
							$changes[$key]['data'][$fieldName]['field'] = $inventoryModel->getField($fieldName);
481
							$changes[$key]['data'][$fieldName]['postvalue'] = $value;
482
						}
483
					}
484
				}
485
			}
486
			$this->inventoryChanges = $changes;
0 ignored issues
show
Bug Best Practice introduced by
The property inventoryChanges does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
487
		}
488
		return $this->inventoryChanges;
489
	}
490
491
	/**
492
	 * Function return modtracker relation model.
493
	 *
494
	 * @return \ModTracker_Relation_Model
495
	 */
496
	public function getRelationInstance()
497
	{
498
		if ($this->isRelationLink() || $this->isRelationUnLink() || $this->isTransferLink() || $this->isTransferUnLink()) {
499
			$row = (new \App\Db\Query())->from('vtiger_modtracker_relations')->where(['id' => $this->get('id')])->one();
500
			$relationInstance = new ModTracker_Relation_Model();
501
			$relationInstance->setData($row)->setParent($this);
502
		}
503
		return $relationInstance;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $relationInstance does not seem to be defined for all execution paths leading up to this point.
Loading history...
504
	}
505
506
	public static function getTotalRecordCount($recordId, $type = false)
507
	{
508
		$where = self::getConditionByType($type);
509
		return (new \App\Db\Query())->from('vtiger_modtracker_basic')->where(['crmid' => $recordId])->andWhere($where)->count();
510
	}
511
512
	public static function getConditionByType($type)
513
	{
514
		$where = [];
515
		switch ($type) {
516
			case 'changes':
517
				$where = ['not in', 'status', [self::DISPLAYED, self::SHOW_HIDDEN_DATA]];
518
				break;
519
			case 'review':
520
				$where = ['status' => [self::DISPLAYED, self::SHOW_HIDDEN_DATA]];
521
				break;
522
			default:
523
				break;
524
		}
525
		return $where;
526
	}
527
528
	public static function addConvertToAccountRelation($sourceModule, $sourceId, $current_user)
529
	{
530
		$db = \App\Db::getInstance();
531
		$db->createCommand()->insert('vtiger_modtracker_basic', [
532
			'crmid' => $sourceId,
533
			'module' => $sourceModule,
534
			'whodid' => $current_user,
535
			'changedon' => date('Y-m-d H:i:s'),
536
			'status' => 6,
537
			'last_reviewed_users' => '#' . App\User::getCurrentUserRealId() . '#',
538
		])->execute();
539
		$id = $db->getLastInsertID('vtiger_modtracker_basic_id_seq');
540
		self::unsetReviewed($sourceId, \App\User::getCurrentUserRealId(), $id);
541
	}
542
543
	/**
544
	 * Function sets the closest time-wise related record from selected modules.
545
	 *
546
	 * @param int    $sourceId
547
	 * @param string $sourceModule
548
	 * @param bool   $byUser
549
	 *
550
	 * @return array
551
	 */
552
	public static function setLastRelation($sourceId, $sourceModule, $byUser = false)
553
	{
554
		$db = \App\Db::getInstance();
555
		$userId = \App\User::getCurrentUserId();
556
		$query = Vtiger_HistoryRelation_Widget::getQuery($sourceId, $sourceModule, Vtiger_HistoryRelation_Widget::getActions());
557
		if (!$query) {
0 ignored issues
show
introduced by
$query is of type App\Db\Query, thus it always evaluated to true.
Loading history...
558
			return false;
559
		}
560
		$data = $query->limit(1)->one();
561
		$type = $data ? $data['type'] : '';
562
		$where = ['crmid' => $sourceId];
563
		if ($byUser) {
564
			$where['userid'] = $userId;
565
		}
566
		$db->createCommand()->delete('u_#__timeline', $where)->execute();
567
		$db->createCommand()->insert('u_#__timeline', [
568
			'crmid' => $sourceId,
569
			'type' => $type,
570
			'userid' => $userId,
571
		])->execute();
572
573
		return [$sourceId => $type];
574
	}
575
576
	/**
577
	 * Function gets the closest time-wise related record from database.
578
	 *
579
	 * @param int    $sourceIds
580
	 * @param string $sourceModule
581
	 *
582
	 * @return array
583
	 */
584
	public static function getLastRelation($sourceIds, $sourceModule)
585
	{
586
		$colors = Vtiger_HistoryRelation_Widget::$colors;
587
		if (!\is_array($sourceIds)) {
0 ignored issues
show
introduced by
The condition is_array($sourceIds) is always false.
Loading history...
588
			$sourceIds = [$sourceIds];
589
		}
590
		$data = (new \App\Db\Query())->from('u_#__timeline')->where(['crmid' => $sourceIds, 'userid' => \App\User::getCurrentUserId()])->createCommand()->queryAllByGroup(1);
591
		if (\count($data) !== \count($sourceIds)) {
592
			$reSearch = array_diff_key(array_flip($sourceIds), $data);
593
			foreach (array_keys($reSearch) as $id) {
594
				$result = self::setLastRelation($id, $sourceModule, true);
595
				if ($result) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $result of type array<mixed,mixed|string> 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...
596
					$data[key($result)]['type'] = current($result);
597
				}
598
			}
599
		}
600
		foreach ($data as $id => &$type) {
601
			if (isset($colors[$type['type']])) {
602
				$type['color'] = $colors[$type['type']];
603
			} else {
604
				$type['color'] = false;
605
			}
606
			if (false !== strpos($type['type'], 'OSSMailView')) {
607
				$type['type'] = 'OSSMailView';
608
			}
609
		}
610
		return $data;
611
	}
612
613
	/**
614
	 * Get field history.
615
	 *
616
	 * @param int    $record
617
	 * @param string $fieldName
618
	 *
619
	 * @return array
620
	 */
621
	public static function getFieldHistory(int $record, string $fieldName): array
622
	{
623
		$rows = [];
624
		$query = (new \App\Db\Query())
625
			->select(['vtiger_modtracker_basic.changedon', 'vtiger_modtracker_detail.prevalue', 'vtiger_modtracker_detail.postvalue'])
626
			->from('vtiger_modtracker_detail')
627
			->leftJoin('vtiger_modtracker_basic', 'vtiger_modtracker_detail.id = vtiger_modtracker_basic.id')
628
			->where(['vtiger_modtracker_basic.crmid' => $record, 'vtiger_modtracker_detail.fieldname' => $fieldName])->orderBy(['vtiger_modtracker_basic.id' => SORT_ASC]);
629
		$dataReader = $query->createCommand()->query();
630
		while ($row = $dataReader->read()) {
631
			$rows[] = $row;
632
		}
633
		$dataReader->close();
634
		return $rows;
635
	}
636
}
637