Passed
Push — developer ( 9bdcd9...f81d2e )
by Radosław
31:14 queued 13:35
created

entityAfterLink()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
eloc 10
dl 0
loc 13
rs 9.9332
c 0
b 0
f 0
ccs 0
cts 5
cp 0
cc 3
nc 3
nop 1
crap 12
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
require_once __DIR__ . '/../ModTracker.php';
12
13
class ModTracker_ModTrackerHandler_Handler
14
{
15
	/**
16
	 * EntityAfterSave function.
17
	 *
18
	 * @param App\EventHandler $eventHandler
19
	 */
20 25
	public function entityAfterSave(App\EventHandler $eventHandler)
21
	{
22 25
		if (!ModTracker::isTrackingEnabledForModule($eventHandler->getModuleName())) {
23 2
			return false;
24
		}
25 24
		$recordModel = $eventHandler->getRecordModel();
26 24
		if ($recordModel->isNew()) {
27 12
			$delta = array_intersect_key($recordModel->getData(), $recordModel->getModule()->getFields());
28 12
			$delta = array_fill_keys(array_keys($delta), null);
29 2
			if ($recordModel->getModule()->isInventory() && ($invData = $recordModel->getInventoryData())) {
30
				$delta['inventory'] = array_fill_keys(array_keys($invData), []);
31 12
			}
32 12
			unset($delta['createdtime'], $delta['modifiedtime'], $delta['modifiedby']);
33 12
			$status = ModTracker::$CREATED;
34 12
			$watchdogTitle = 'LBL_CREATED';
35 19
			$watchdogMessage = '$(record : ChangesListValues)$';
36
		} elseif (isset($recordModel->ext['modificationType'], ModTracker::getAllActionsTypes()[$recordModel->ext['modificationType']])) {
37
			$delta = $recordModel->getChanges();
38
			$status = $recordModel->ext['modificationType'];
39
			$watchdogTitle = $status === ModTracker::$TRANSFER_EDIT ? ModTracker_Record_Model::$statusLabel[$status] : '';
40
			$watchdogMessage = '';
41 19
		} else {
42 19
			$delta = $recordModel->getChanges();
43 19
			$status = ModTracker::$UPDATED;
44 19
			$watchdogTitle = 'LBL_UPDATED';
45
			$watchdogMessage = '$(record : ChangesListValues)$';
46 24
		}
47 1
		if ($skipFields = $recordModel->ext['ModTrackerSkipFields'] ?? []) {
48
			foreach ($delta as $fieldName => $preValue) {
49 24
				if (\in_array($fieldName, $skipFields)) {
50 24
					unset($delta[$fieldName]);
51 24
				}
52 24
			}
53 24
		}
54 24
		if (empty($delta)) {
55 24
			return false;
56 24
		}
57 24
		$recordId = $recordModel->getId();
58 24
		$db = \App\Db::getInstance();
59 24
		$db->createCommand()->insert('vtiger_modtracker_basic', [
60 24
			'crmid' => $recordId,
61 19
			'module' => $eventHandler->getModuleName(),
62
			'whodid' => App\User::getCurrentUserRealId(),
63 24
			'changedon' => $recordModel->get('modifiedtime'),
64 2
			'status' => $status,
65 2
			'last_reviewed_users' => '#' . App\User::getCurrentUserRealId() . '#',
66 2
		])->execute();
67 2
		$id = $db->getLastInsertID('vtiger_modtracker_basic_id_seq');
68 2
		if (!$recordModel->isNew()) {
69 2
			ModTracker_Record_Model::unsetReviewed($recordId, App\User::getCurrentUserRealId(), $id);
70 2
		}
71
		if (isset($delta['inventory'])) {
72 2
			$inventoryData = [];
73 2
			foreach ($delta['inventory'] as $key => $invData) {
74
				$item = $recordModel->getInventoryItem($key) ?? [];
75 24
				$itemId = $invData['id'] ?? $item['id'];
76 24
				$inventoryData[$itemId]['item'] = $invData['name'] ?? $item['name'];
77 24
				$inventoryData[$itemId]['prevalue'] = $invData;
78 24
				$inventoryData[$itemId]['postvalue'] = $invData ? array_intersect_key($item, $invData) : $item;
79 24
			}
80 12
			$db->createCommand()->insert('u_#__modtracker_inv', ['id' => $id, 'changes' => \App\Json::encode($inventoryData)])->execute();
81
			unset($delta['inventory']);
82 24
		}
83
		$insertedData = [];
84
		foreach ($delta as $fieldName => $preValue) {
85 24
			$newValue = $recordModel->get($fieldName);
86
			$fieldModel = $recordModel->getField($fieldName);
87
			if (empty($preValue) && empty($newValue)) {
88 24
				continue;
89 4
			}
90 24
			if (\is_object($newValue)) {
91 6
				throw new App\Exceptions\AppException("Incorrect data type in $fieldName: Value can not be the object of " . \get_class($newValue));
92 6
			}
93
			if (\is_array($newValue)) {
94 24
				$newValue = implode(',', $newValue);
95
			}
96 24
			if (!$fieldModel) {
97 24
				\App\Log::warning($fieldName . ' field does not exist in the module ' . $eventHandler->getModuleName(), __METHOD__);
98 24
			} elseif ('text' === $fieldModel->getFieldDataType()) {
99 24
				$preValue = empty($preValue) ? $preValue : \App\TextUtils::textTruncate($preValue, 65532);
100
				$newValue = empty($newValue) ? $newValue : \App\TextUtils::textTruncate($newValue, 65532);
101 24
			}
102 24
			if ($fieldModel && \in_array(\App\Anonymization::MODTRACKER_DB, $fieldModel->getAnonymizationTarget())) {
103
				$preValue = $newValue = '****';
104
			}
105
			$insertedData[] = [$id, $fieldName, $preValue, $newValue];
106
		}
107
		if ($insertedData) {
108
			$db->createCommand()
109 1
				->batchInsert('vtiger_modtracker_detail', ['id', 'fieldname', 'prevalue', 'postvalue'], $insertedData)
110
				->execute();
111 1
		}
112 1
		$this->addNotification($eventHandler->getModuleName(), $recordId, $watchdogTitle, $watchdogMessage);
113 1
	}
114
115
	/**
116
	 * EntityAfterLink handler function.
117
	 *
118
	 * @param App\EventHandler $eventHandler
119
	 */
120
	public function entityAfterLink(App\EventHandler $eventHandler)
121
	{
122
		$params = $eventHandler->getParams();
123
		if (!ModTracker::isTrackingEnabledForModule($params['sourceModule'])) {
124
			return false;
125
		}
126
		ModTracker::linkRelation($params['sourceModule'], $params['sourceRecordId'], $params['destinationModule'], $params['destinationRecordId']);
127
		if (App\Config::module('ModTracker', 'WATCHDOG')) {
128
			$watchdogTitle = 'LBL_ADDED';
129
			$watchdogMessage = '<a href="index.php?module=' . $params['sourceModule'] . '&view=Detail&record=' . $params['sourceRecordId'] . '">' . vtlib\Functions::getCRMRecordLabel($params['sourceRecordId']) . '</a>';
0 ignored issues
show
Bug introduced by
Are you sure vtlib\Functions::getCRMR...rams['sourceRecordId']) of type array|mixed|string can be used in concatenation? ( Ignorable by Annotation )

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

129
			$watchdogMessage = '<a href="index.php?module=' . $params['sourceModule'] . '&view=Detail&record=' . $params['sourceRecordId'] . '">' . /** @scrutinizer ignore-type */ vtlib\Functions::getCRMRecordLabel($params['sourceRecordId']) . '</a>';
Loading history...
130
			$watchdogMessage .= ' $(translate : LBL_WITH)$ ';
131
			$watchdogMessage .= '<a href="index.php?module=' . $params['destinationModule'] . '&view=Detail&record=' . $params['destinationRecordId'] . '">$(record : RecordLabel)$</a>';
132
			$this->addNotification($params['destinationModule'], $params['destinationRecordId'], $watchdogTitle, $watchdogMessage);
133
		}
134
	}
135
136
	/**
137
	 * EntityAfterLinkForSource handler function.
138
	 *
139
	 * @param App\EventHandler $eventHandler
140
	 */
141
	public function entityAfterLinkForSource(App\EventHandler $eventHandler)
142
	{
143
		['sourceModule' => $sourceModule, 'sourceRecordId' => $sourceRecordId,'destinationModule' => $destinationModule,'destinationRecordId' => $destinationRecordId, 'relationId' => $relationId] = $eventHandler->getParams();
144
		if (!ModTracker::isTrackingEnabledForModule($destinationModule) || Vtiger_Relation_Model::getInstanceById($relationId)->isDirectRelation()) {
145
			return false;
146
		}
147
		ModTracker::linkRelation($destinationModule, $destinationRecordId, $sourceModule, $sourceRecordId);
148
		if (\App\Config::module('ModTracker', 'WATCHDOG')) {
149
			$watchdogTitle = 'LBL_ADDED';
150
			$watchdogMessage = '<a href="index.php?module=' . $destinationModule . '&view=Detail&record=' . $destinationRecordId . '">' . vtlib\Functions::getCRMRecordLabel($destinationRecordId) . '</a>';
0 ignored issues
show
Bug introduced by
Are you sure vtlib\Functions::getCRMR...l($destinationRecordId) of type array|mixed|string can be used in concatenation? ( Ignorable by Annotation )

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

150
			$watchdogMessage = '<a href="index.php?module=' . $destinationModule . '&view=Detail&record=' . $destinationRecordId . '">' . /** @scrutinizer ignore-type */ vtlib\Functions::getCRMRecordLabel($destinationRecordId) . '</a>';
Loading history...
151
			$watchdogMessage .= ' $(translate : LBL_WITH)$ ';
152
			$watchdogMessage .= '<a href="index.php?module=' . $sourceModule . '&view=Detail&record=' . $sourceRecordId . '">$(record : RecordLabel)$</a>';
153
			$this->addNotification($sourceModule, $sourceRecordId, $watchdogTitle, $watchdogMessage);
154
		}
155
	}
156
157
	/**
158
	 * EntityAfterUnLink handler function.
159
	 *
160
	 * @param App\EventHandler $eventHandler
161
	 */
162
	public function entityAfterUnLink(App\EventHandler $eventHandler)
163
	{
164
		$params = $eventHandler->getParams();
165
		if (!ModTracker::isTrackingEnabledForModule($params['sourceModule'])) {
166
			return false;
167
		}
168
		ModTracker::unLinkRelation($params['sourceModule'], $params['sourceRecordId'], $params['destinationModule'], $params['destinationRecordId']);
169
		if (App\Config::module('ModTracker', 'WATCHDOG')) {
170
			$watchdogTitle = 'LBL_UNLINK';
171
			$watchdogMessage = '<a href="index.php?module=' . $params['sourceModule'] . '&view=Detail&record=' . $params['sourceRecordId'] . '">' . vtlib\Functions::getCRMRecordLabel($params['sourceRecordId']) . '</a>';
0 ignored issues
show
Bug introduced by
Are you sure vtlib\Functions::getCRMR...rams['sourceRecordId']) of type array|mixed|string can be used in concatenation? ( Ignorable by Annotation )

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

171
			$watchdogMessage = '<a href="index.php?module=' . $params['sourceModule'] . '&view=Detail&record=' . $params['sourceRecordId'] . '">' . /** @scrutinizer ignore-type */ vtlib\Functions::getCRMRecordLabel($params['sourceRecordId']) . '</a>';
Loading history...
172
			$watchdogMessage .= ' $(translate : LBL_WITH)$ ';
173
			$watchdogMessage .= '<a href="index.php?module=' . $params['destinationModule'] . '&view=Detail&record=' . $params['destinationRecordId'] . '">$(record : RecordLabel)$</a>';
174
			$this->addNotification($params['destinationModule'], $params['destinationRecordId'], $watchdogTitle, $watchdogMessage);
175
		}
176
	}
177
178
	/**
179
	 * EntityAfterUnLinkForSource handler function.
180
	 *
181
	 * @param App\EventHandler $eventHandler
182
	 */
183
	public function entityAfterUnLinkForSource(App\EventHandler $eventHandler)
184
	{
185
		['sourceModule' => $sourceModule, 'sourceRecordId' => $sourceRecordId,'destinationModule' => $destinationModule,'destinationRecordId' => $destinationRecordId, 'relationId' => $relationId] = $eventHandler->getParams();
186
		if (!ModTracker::isTrackingEnabledForModule($destinationModule) || Vtiger_Relation_Model::getInstanceById($relationId)->isDirectRelation()) {
187
			return false;
188
		}
189
190
		ModTracker::unLinkRelation($destinationModule, $destinationRecordId, $sourceModule, $sourceRecordId);
191
		if (App\Config::module('ModTracker', 'WATCHDOG')) {
192
			$watchdogTitle = 'LBL_UNLINK';
193
			$watchdogMessage = '<a href="index.php?module=' . $destinationModule . '&view=Detail&record=' . $destinationRecordId . '">' . vtlib\Functions::getCRMRecordLabel($destinationRecordId) . '</a>';
0 ignored issues
show
Bug introduced by
Are you sure vtlib\Functions::getCRMR...l($destinationRecordId) of type array|mixed|string can be used in concatenation? ( Ignorable by Annotation )

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

193
			$watchdogMessage = '<a href="index.php?module=' . $destinationModule . '&view=Detail&record=' . $destinationRecordId . '">' . /** @scrutinizer ignore-type */ vtlib\Functions::getCRMRecordLabel($destinationRecordId) . '</a>';
Loading history...
194
			$watchdogMessage .= ' $(translate : LBL_WITH)$ ';
195
			$watchdogMessage .= '<a href="index.php?module=' . $sourceModule . '&view=Detail&record=' . $sourceRecordId . '">$(record : RecordLabel)$</a>';
196
			$this->addNotification($sourceModule, $sourceRecordId, $watchdogTitle, $watchdogMessage);
197
		}
198
	}
199
200
	/**
201
	 * EntityAfterTransferLink handler function.
202
	 *
203
	 * @param App\EventHandler $eventHandler
204 1
	 *
205
	 * @return bool
206 1
	 */
207
	public function entityAfterTransferLink(App\EventHandler $eventHandler)
208
	{
209 1
		$params = $eventHandler->getParams();
210 1
		if (!ModTracker::isTrackingEnabledForModule($eventHandler->getModuleName())) {
211 1
			return false;
212 1
		}
213
		ModTracker::transferRelation($eventHandler->getModuleName(), $params['sourceRecordId'], $params['destinationModule'], $params['destinationRecordId'], ModTracker::$TRANSFER_LINK);
214
	}
215 1
216 1
	/**
217 1
	 * @param App\EventHandler $eventHandler
218 1
	 *
219 1
	 * @return bool
220 1
	 */
221 1
	public function entityAfterTransferUnLink(App\EventHandler $eventHandler)
222 1
	{
223 1
		$params = $eventHandler->getParams();
224 1
		if (!ModTracker::isTrackingEnabledForModule($eventHandler->getModuleName())) {
225
			return false;
226
		}
227
		ModTracker::transferRelation($eventHandler->getModuleName(), $params['sourceRecordId'], $params['destinationModule'], $params['destinationRecordId'], ModTracker::$TRANSFER_UNLINK);
228
	}
229 1
230 1
	/**
231 1
	 * DetailViewBefore handler function.
232 1
	 *
233 1
	 * @param App\EventHandler $eventHandler
234 1
	 */
235 1
	public function detailViewBefore(App\EventHandler $eventHandler)
236 1
	{
237 1
		if (!ModTracker::isTrackingEnabledForModule($eventHandler->getModuleName())) {
238 1
			return false;
239 1
		}
240 1
		\App\Db::getInstance()->createCommand()->insert('vtiger_modtracker_basic', [
241 1
			'crmid' => $eventHandler->getRecordModel()->getId(),
242
			'module' => $eventHandler->getModuleName(),
243
			'whodid' => \App\User::getCurrentUserRealId(),
244 1
			'changedon' => date('Y-m-d H:i:s'),
245 1
			'status' => ModTracker::$DISPLAYED,
246
		])->execute();
247
	}
248
249
	/**
250
	 * EntityChangeState handler function.
251
	 *
252
	 * @param App\EventHandler $eventHandler
253
	 */
254
	public function entityChangeState(App\EventHandler $eventHandler)
255 25
	{
256
		if (!ModTracker::isTrackingEnabledForModule($eventHandler->getModuleName())) {
257 25
			return false;
258 25
		}
259 25
		$recordModel = $eventHandler->getRecordModel();
260 25
		$recordId = $recordModel->getId();
261
		$status = 0;
262
		if (isset($recordModel->ext['modificationType'], ModTracker::getAllActionsTypes()[$recordModel->ext['modificationType']])) {
263
			$status = $recordModel->ext['modificationType'];
264
		} elseif (is_numeric($state = $recordModel->get('deleted'))) {
265
			switch ($state) {
266
				case \App\Record::STATE_ACTIVE:
267
					$status = ModTracker::$ACTIVE;
268
					break;
269
				case \App\Record::STATE_TRASH:
270
					$status = ModTracker::$TRASH;
271
					break;
272
				case \App\Record::STATE_ARCHIVED:
273
					$status = ModTracker::$ARCHIVED;
274
					break;
275
				default:
276
					break;
277
			}
278 25
		}
279
		$db = \App\Db::getInstance();
280
		$db->createCommand()->insert('vtiger_modtracker_basic', [
281
			'crmid' => $recordId,
282
			'module' => $eventHandler->getModuleName(),
283
			'whodid' => \App\User::getCurrentUserRealId(),
284
			'changedon' => date('Y-m-d H:i:s'),
285
			'status' => $status,
286
			'last_reviewed_users' => '#' . \App\User::getCurrentUserRealId() . '#',
287
		])->execute();
288
		$id = $db->getLastInsertID('vtiger_modtracker_basic_id_seq');
289
		ModTracker_Record_Model::unsetReviewed($recordId, \App\User::getCurrentUserRealId(), $id);
290
		$isExists = (new \App\Db\Query())->from('vtiger_crmentity')->where(['crmid' => $recordId])->andWhere(['<>', 'smownerid', \App\User::getCurrentUserRealId()])->exists();
291
		if ($isExists) {
292
			$db->createCommand()->update('vtiger_crmentity', ['was_read' => 0], ['crmid' => $recordId])->execute();
293
		}
294
		$this->addNotification($eventHandler->getModuleName(), $recordId, ModTracker_Record_Model::$statusLabel[$status]);
295
	}
296
297
	/**
298
	 * EntityAfterDelete handler function.
299
	 *
300
	 * @param \App\EventHandler $eventHandler
301
	 */
302
	public function entityAfterDelete(App\EventHandler $eventHandler)
303
	{
304
		if (!ModTracker::isTrackingEnabledForModule($eventHandler->getModuleName())) {
305
			return false;
306
		}
307
		\App\Db::getInstance()->createCommand()->insert('vtiger_modtracker_basic', [
308
			'crmid' => $eventHandler->getRecordModel()->getId(),
309
			'module' => $eventHandler->getModuleName(),
310
			'whodid' => \App\User::getCurrentUserRealId(),
311
			'changedon' => date('Y-m-d H:i:s'),
312
			'status' => ModTracker::$DELETED,
313
		])->execute();
314
	}
315
316
	/**
317
	 * Show hidden data handler function.
318
	 *
319
	 * @param App\EventHandler $eventHandler
320
	 */
321
	public function entityAfterShowHiddenData(App\EventHandler $eventHandler)
322
	{
323
		if (!ModTracker::isTrackingEnabledForModule($eventHandler->getModuleName())) {
324
			return false;
325
		}
326
		$recordModel = $eventHandler->getRecordModel();
327
		\App\Db::getInstance()->createCommand()->insert('vtiger_modtracker_basic', [
328
			'crmid' => $recordModel->getId(),
329
			'module' => $eventHandler->getModuleName(),
330
			'whodid' => \App\User::getCurrentUserRealId(),
331
			'changedon' => date('Y-m-d H:i:s'),
332
			'status' => ModTracker::$SHOW_HIDDEN_DATA,
333
		])->execute();
334
	}
335
336
	/**
337
	 * Add notification in handler.
338
	 *
339
	 * @param string $moduleName
340
	 * @param int    $recordId
341
	 * @param string $watchdogTitle
342
	 * @param string $watchdogMessage
343
	 */
344
	public function addNotification($moduleName, $recordId, $watchdogTitle, $watchdogMessage = '')
345
	{
346
		if ($watchdogTitle) {
347
			$watchdog = Vtiger_Watchdog_Model::getInstanceById($recordId, $moduleName);
348
			$users = $watchdog->getWatchingUsers([\App\User::getCurrentUserRealId()]);
349
			if (!empty($users)) {
350
				$watchdogTitle = '$(translate : ModTracker|' . $watchdogTitle . ')$ $(record : RecordLabel)$';
351
				$watchdogTitle = \App\Fields\Owner::getUserLabel(\App\User::getCurrentUserId()) . ' ' . $watchdogTitle;
352
				$relatedField = \App\ModuleHierarchy::getMappingRelatedField($moduleName);
353
				if ($relatedField) {
354
					$notification = Vtiger_Record_Model::getCleanInstance('Notification');
355
					$notification->set('shownerid', $users);
356
					$notification->set($relatedField, $recordId);
357
					$notification->set('title', $watchdogTitle);
358
					$notification->set('description', $watchdogMessage);
359
					$notification->set('notification_type', $watchdog->noticeDefaultType);
360
					$notification->set('notification_status', 'PLL_UNREAD');
361
					$notification->setHandlerExceptions(['disableHandlerClasses' => ['ModTracker_ModTrackerHandler_Handler']]);
362
					$notification->save();
363
				}
364
			}
365
		}
366
	}
367
}
368