EventHandler::getRecordModel()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
ccs 0
cts 0
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 2
1
<?php
2
3
namespace App;
4
5
/**
6
 * Event Handler main class.
7
 *
8
 * @package App
9
 *
10
 * @copyright YetiForce S.A.
11
 * @license   YetiForce Public License 6.5 (licenses/LicenseEN.txt or yetiforce.com)
12
 * @author    Mariusz Krzaczkowski <[email protected]>
13
 * @author    Radosław Skrzypczak <[email protected]>
14
 */
15
class EventHandler
16
{
17
	/**
18
	 * Table name.
19
	 *
20
	 * @var string
21
	 */
22
	protected static $baseTable = 'vtiger_eventhandlers';
23
	private static $mandatoryEventClass = ['ModTracker_ModTrackerHandler_Handler'];
24
	private $recordModel;
25
	private $moduleName;
26
	private $params;
27
	private $exceptions = [];
28
	private $handlers = [];
29
30
	/** @var int Handler is in system mode, no editing possible */
31
	public const SYSTEM = 0;
32
	/** @var int Handler is in edit mode */
33
	public const EDITABLE = 1;
34
35 2
	/** @var string Edit view, validation before saving */
36
	public const EDIT_VIEW_PRE_SAVE = 'EditViewPreSave';
37 2
	/** @var string Edit view, change value */
38
	public const EDIT_VIEW_CHANGE_VALUE = 'EditViewChangeValue';
39
	/** @var string Record converter after create record */
40 2
	public const RECORD_CONVERTER_AFTER_SAVE = 'RecordConverterAfterSave';
41 2
42
	/**
43 2
	 * Handler types.
44 2
	 *
45 2
	 * @var array
46 2
	 */
47
	public const HANDLER_TYPES = [
48
		'EditViewPreSave' => [
49
			'label' => 'LBL_EDIT_VIEW_PRESAVE',
50 2
			'icon' => 'fas fa-step-backward',
51
			'columns' => [
52
				'eventName' => ['label' => 'LBL_EVENT_NAME'],
53
				'eventDescription' => ['label' => 'LBL_EVENT_DESC'],
54
				'modules' => ['label' => 'LBL_INCLUDE_MODULES'],
55
				'modulesExcluded' => ['label' => 'LBL_EXCLUDE_MODULES'],
56
				'active' => ['label' => 'LBL_EVENT_IS_ACTIVE'],
57
			],
58
		],
59
		'EntityChangeState' => [
60
			'label' => 'LBL_ENTITY_CHANGE_STATE',
61 5799
			'icon' => 'fas fa-compass',
62
			'columns' => [
63 5799
				'eventName' => ['label' => 'LBL_EVENT_NAME'],
64 2
				'eventDescription' => ['label' => 'LBL_EVENT_DESC'],
65 2
				'modules' => ['label' => 'LBL_INCLUDE_MODULES'],
66 2
				'modulesExcluded' => ['label' => 'LBL_EXCLUDE_MODULES'],
67
				'active' => ['label' => 'LBL_EVENT_IS_ACTIVE'],
68 2
			],
69
		],
70 5799
		'EntityBeforeSave' => [
71 5799
			'label' => 'LBL_ENTITY_BEFORE_SAVE',
72 5796
			'icon' => 'fas fa-save',
73 5796
			'columns' => [
74 28
				'eventName' => ['label' => 'LBL_EVENT_NAME'],
75
				'eventDescription' => ['label' => 'LBL_EVENT_DESC'],
76
				'modules' => ['label' => 'LBL_INCLUDE_MODULES'],
77
				'modulesExcluded' => ['label' => 'LBL_EXCLUDE_MODULES'],
78 5799
				'active' => ['label' => 'LBL_EVENT_IS_ACTIVE'],
79
			],
80
		],
81
		'EntityAfterSave' => [
82
			'label' => 'LBL_ENTITY_AFTER_SAVE',
83
			'icon' => 'far fa-save',
84
			'columns' => [
85
				'eventName' => ['label' => 'LBL_EVENT_NAME'],
86
				'eventDescription' => ['label' => 'LBL_EVENT_DESC'],
87
				'modules' => ['label' => 'LBL_INCLUDE_MODULES'],
88
				'modulesExcluded' => ['label' => 'LBL_EXCLUDE_MODULES'],
89
				'active' => ['label' => 'LBL_EVENT_IS_ACTIVE'],
90
			],
91
		],
92
		'DetailViewBefore' => [
93
			'label' => 'LBL_DETAIL_VIEW_BEFORE',
94
			'icon' => 'mdi mdi-account-details c-mdi',
95
			'columns' => [
96
				'eventName' => ['label' => 'LBL_EVENT_NAME'],
97
				'eventDescription' => ['label' => 'LBL_EVENT_DESC'],
98
				'modules' => ['label' => 'LBL_INCLUDE_MODULES'],
99
				'modulesExcluded' => ['label' => 'LBL_EXCLUDE_MODULES'],
100
				'active' => ['label' => 'LBL_EVENT_IS_ACTIVE'],
101
			],
102
		],
103
		'EditViewBefore' => [
104
			'label' => 'LBL_EDIT_VIEW_BEFORE',
105
			'icon' => 'yfi yfi-full-editing-view ',
106
			'columns' => [
107
				'eventName' => ['label' => 'LBL_EVENT_NAME'],
108
				'eventDescription' => ['label' => 'LBL_EVENT_DESC'],
109
				'modules' => ['label' => 'LBL_INCLUDE_MODULES'],
110
				'modulesExcluded' => ['label' => 'LBL_EXCLUDE_MODULES'],
111
				'active' => ['label' => 'LBL_EVENT_IS_ACTIVE'],
112
			],
113 2
		],
114
		'EditViewDuplicate' => [
115 2
			'label' => 'LBL_EDIT_VIEW_DUPLICATE',
116 2
			'icon' => 'fas fa-clone',
117 2
			'columns' => [
118
				'eventName' => ['label' => 'LBL_EVENT_NAME'],
119
				'eventDescription' => ['label' => 'LBL_EVENT_DESC'],
120
				'modules' => ['label' => 'LBL_INCLUDE_MODULES'],
121
				'modulesExcluded' => ['label' => 'LBL_EXCLUDE_MODULES'],
122
				'active' => ['label' => 'LBL_EVENT_IS_ACTIVE'],
123
			],
124
		],
125
		'InventoryRecordDetails' => [
126
			'label' => 'LBL_INVENTORY_RECORD_DETAILS',
127
			'icon' => 'fas fa-pallet',
128
			'columns' => [
129
				'eventName' => ['label' => 'LBL_EVENT_NAME'],
130
				'eventDescription' => ['label' => 'LBL_EVENT_DESC'],
131
				'modules' => ['label' => 'LBL_INCLUDE_MODULES'],
132
				'modulesExcluded' => ['label' => 'LBL_EXCLUDE_MODULES'],
133
				'active' => ['label' => 'LBL_EVENT_IS_ACTIVE'],
134
			],
135
		],
136
	];
137
138
	/**
139
	 * Get all event handlers.
140
	 *
141
	 * @param bool $active
142
	 *
143
	 * @return array
144
	 */
145
	public static function getAll(bool $active = true): array
146
	{
147
		$query = (new \App\Db\Query())->from(self::$baseTable)->orderBy(['priority' => SORT_DESC]);
148
		if ($active) {
149
			$query->where(['is_active' => 1]);
150
		}
151
		return $query->indexBy('eventhandler_id')->all();
152
	}
153
154
	/**
155 1
	 * Get active event handlers by type (event_name).
156
	 *
157 1
	 * @param string $name
158 1
	 * @param string $moduleName
159
	 * @param bool   $active
160
	 *
161 1
	 * @return array
162 1
	 */
163 1
	public static function getByType(string $name, ?string $moduleName = '', bool $active = true): array
164 1
	{
165
		$handlersByType = [];
166
		$cacheName = 'All' . ($active ? ':active' : '');
167
		if (Cache::has('EventHandlerByType', $cacheName)) {
168
			$handlersByType = Cache::get('EventHandlerByType', $cacheName);
169
		} else {
170
			foreach (self::getAll($active) as $handler) {
171
				$handlersByType[$handler['event_name']][$handler['handler_class']] = $handler;
172 1
			}
173
			Cache::save('EventHandlerByType', $cacheName, $handlersByType, Cache::LONG);
174 1
		}
175 1
		$handlers = $handlersByType[$name] ?? [];
176
		if ($moduleName) {
177
			foreach ($handlers as $key => $handler) {
178 1
				if ((!empty($handler['include_modules']) && !\in_array($moduleName, explode(',', $handler['include_modules']))) || (!empty($handler['exclude_modules']) && \in_array($moduleName, explode(',', $handler['exclude_modules'])))) {
179 1
					unset($handlers[$key]);
180 1
				}
181 1
			}
182
		}
183
		return $handlers;
184
	}
185
186
	/**
187
	 * Get vars event handlers by type (event_name).
188 5796
	 *
189
	 * @param string $name
190 5796
	 * @param string $moduleName
191 5796
	 * @param array  $params
192
	 * @param bool   $byKey
193
	 *
194
	 * @return string
195
	 */
196
	public static function getVarsByType(string $name, string $moduleName, array $params, bool $byKey = false): string
197
	{
198 5796
		$return = [];
199
		foreach (self::getByType($name, $moduleName) as $key => $handler) {
200 5796
			$className = $handler['handler_class'];
201 5796
			if (method_exists($className, 'vars') && ($vars = (new $className())->vars($name, $params, $moduleName))) {
202
				if ($byKey) {
203
					$return[$key] = $vars;
204
				} else {
205
					$return = array_values(array_unique(array_merge($return, $vars)));
206
				}
207
			}
208 4
		}
209
		return Purifier::encodeHtml(Json::encode($return));
210 4
	}
211 4
212
	/**
213
	 * Register an event handler.
214
	 *
215
	 * @param string $eventName      The name of the event to handle
216
	 * @param string $className
217
	 * @param string $includeModules
218
	 * @param string $excludeModules
219
	 * @param int    $priority
220
	 * @param bool   $isActive
221
	 * @param int    $ownerId
222
	 * @param int    $mode
223
	 *
224
	 * @return bool
225
	 */
226
	public static function registerHandler(string $eventName, string $className, $includeModules = '', $excludeModules = '', $priority = 5, $isActive = true, $ownerId = 0, $mode = 1): bool
227
	{
228
		$return = false;
229
		$isExists = (new \App\Db\Query())->from(self::$baseTable)->where(['event_name' => $eventName, 'handler_class' => $className])->exists();
230 5796
		if (!$isExists) {
231
			$return = \App\Db::getInstance()->createCommand()
232 5796
				->insert(self::$baseTable, [
233
					'event_name' => $eventName,
234
					'handler_class' => $className,
235
					'is_active' => $isActive,
236
					'include_modules' => $includeModules,
237
					'exclude_modules' => $excludeModules,
238
					'priority' => $priority,
239
					'owner_id' => $ownerId,
240 5796
					'privileges' => $mode,
241
				])->execute();
242 5796
			static::clearCache();
243
		}
244
		return $return;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $return could return the type integer which is incompatible with the type-hinted return boolean. Consider adding an additional type-check to rule them out.
Loading history...
245
	}
246
247
	/**
248
	 * Clear cache.
249
	 *
250 1
	 * @return void
251
	 */
252 1
	public static function clearCache(): void
253
	{
254
		Cache::delete('EventHandlerByType', 'All');
255
		Cache::delete('EventHandlerByType', 'All:active');
256
	}
257
258
	/**
259
	 * Unregister a registered handler.
260 1
	 *
261
	 * @param string      $className
262 1
	 * @param bool|string $eventName
263 1
	 */
264
	public static function deleteHandler($className, $eventName = false)
265
	{
266
		$params = ['handler_class' => $className];
267
		if ($eventName) {
268
			$params['event_name'] = $eventName;
269
		}
270 5799
		\App\Db::getInstance()->createCommand()->delete(self::$baseTable, $params)->execute();
271
		static::clearCache();
272 5799
	}
273 5799
274 1
	/**
275 1
	 * Update an event handler.
276 1
	 *
277 1
	 * @param array $params
278 1
	 * @param int   $id
279
	 *
280
	 * @return void
281 1
	 */
282 1
	public static function update(array $params, int $id)
283
	{
284 1
		Db::getInstance()->createCommand()->update(self::$baseTable, $params, ['eventhandler_id' => $id])->execute();
285
		static::clearCache();
286
	}
287 1
288
	/**
289
	 * Check if it is active function.
290
	 *
291
	 * @param string      $className
292
	 * @param string|null $eventName
293 5799
	 *
294
	 * @return bool
295
	 */
296
	public static function checkActive(string $className, ?string $eventName = null): bool
297
	{
298
		$rows = (new \App\Db\Query())->from(self::$baseTable)->where(['handler_class' => $className])->all();
299
		$status = false;
300
		foreach ($rows as $row) {
301
			if (isset($eventName) && $eventName !== $row['event_name']) {
302
				continue;
303 5799
			}
304
			if (empty($row['is_active'])) {
305 5799
				return false;
306 5796
			}
307 5795
			$status = true;
308
		}
309 3
		return $status;
310 3
	}
311
312 5796
	/**
313 5796
	 * Set an event handler as inactive.
314 5796
	 *
315
	 * @param string      $className
316
	 * @param bool|string $eventName
317
	 */
318
	public static function setInActive($className, $eventName = false)
319
	{
320 5799
		$params = ['handler_class' => $className];
321
		if ($eventName) {
322
			$params['event_name'] = $eventName;
323
		}
324
		\App\Db::getInstance()->createCommand()
325
			->update(self::$baseTable, ['is_active' => false], $params)->execute();
326
		static::clearCache();
327
	}
328
329
	/**
330
	 * Set an event handler as active.
331
	 *
332
	 * @param string      $className
333
	 * @param bool|string $eventName
334
	 */
335
	public static function setActive($className, $eventName = false)
336
	{
337
		$params = ['handler_class' => $className];
338
		if ($eventName) {
339
			$params['event_name'] = $eventName;
340
		}
341
		\App\Db::getInstance()->createCommand()->update(self::$baseTable, ['is_active' => true], $params)->execute();
342
		static::clearCache();
343
	}
344
345
	/**
346
	 * Set record model.
347
	 *
348
	 * @param \Vtiger_Record_Model $recordModel
349
	 *
350
	 * @return $this
351
	 */
352
	public function setRecordModel(\Vtiger_Record_Model $recordModel)
353
	{
354
		$this->recordModel = $recordModel;
355
		$this->moduleName = $recordModel->getModuleName();
356
		return $this;
357
	}
358
359
	/**
360
	 * Set module name.
361
	 *
362
	 * @param string $moduleName
363
	 *
364
	 * @return $this
365
	 */
366
	public function setModuleName($moduleName)
367
	{
368
		$this->moduleName = $moduleName;
369
		return $this;
370
	}
371
372
	/**
373
	 * Set params.
374
	 *
375
	 * @param array $params
376
	 */
377
	public function setParams($params)
378
	{
379
		$this->params = $params;
380
	}
381
382
	/**
383
	 * Add param.
384
	 *
385
	 * @param array $params
386
	 * @param mixed $key
387
	 * @param mixed $value
388
	 */
389
	public function addParams($key, $value)
390
	{
391
		$this->params[$key] = $value;
392
	}
393
394
	/**
395
	 * Get record model.
396
	 *
397
	 * @return \Vtiger_Record_Model
398
	 */
399
	public function getRecordModel()
400
	{
401
		return $this->recordModel;
402
	}
403
404
	/**
405
	 * Get module name.
406
	 *
407
	 * @return string
408
	 */
409
	public function getModuleName()
410
	{
411
		return $this->moduleName;
412
	}
413
414
	/**
415
	 * Get params.
416
	 *
417
	 * @return array Additional parameters
418
	 */
419
	public function getParams()
420
	{
421
		return $this->params;
422
	}
423
424
	/**
425
	 * Get param.
426
	 *
427
	 * @param string $key
428
	 *
429
	 * @return mixed
430
	 */
431
	public function getParam(string $key)
432
	{
433
		return $this->params[$key] ?? null;
434
	}
435
436
	/**
437
	 * Set exceptions.
438
	 *
439
	 * @param array $exceptions
440
	 */
441
	public function setExceptions(array $exceptions)
442
	{
443
		$this->exceptions = $exceptions;
444
		return $this;
445
	}
446
447
	/**
448
	 * @param string $name Event name
449
	 *
450
	 * @return array Handlers list
451
	 */
452
	public function getHandlers(string $name): array
453
	{
454
		$handlers = static::getByType($name, $this->moduleName);
455
		if ($this->exceptions['disableHandlers'] ?? null) {
456
			$handlers = array_intersect_key($handlers, array_flip(self::$mandatoryEventClass));
457
		} elseif ($disableHandlers = $this->exceptions['disableHandlerClasses'] ?? null) {
458
			foreach ($disableHandlers as $className) {
459
				if (isset($handlers[$className])) {
460
					unset($handlers[$className]);
461
				}
462
			}
463
		}
464
		return $handlers;
465
	}
466
467
	/**
468
	 * Trigger an event.
469
	 *
470
	 * @param string $name Event name
471
	 *
472
	 * @throws \App\Exceptions\AppException
473
	 */
474
	public function trigger(string $name)
475
	{
476
		foreach ($this->getHandlers($name) as $handler) {
477
			$this->triggerHandler($handler);
478
		}
479
	}
480
481
	/**
482
	 * Trigger handler.
483
	 *
484
	 * @param array $handler
485
	 *
486
	 * @throws \App\Exceptions\AppException
487
	 */
488
	public function triggerHandler(array $handler)
489
	{
490
		$className = $handler['handler_class'];
491
		$function = lcfirst($handler['event_name']);
492
		if (!method_exists($className, $function)) {
493
			Log::error("Handler not found, class: {$className} | {$function}");
494
			throw new \App\Exceptions\AppException('LBL_HANDLER_NOT_FOUND');
495
		}
496
		if (isset($this->handlers[$className])) {
497
			$handler = $this->handlers[$className];
498
		} else {
499
			$handler = $this->handlers[$className] = new $className();
500
		}
501
		return $handler->{$function}($this);
502
	}
503
}
504