EventHandler::registerHandler()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 19
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 16
dl 0
loc 19
ccs 4
cts 4
cp 1
rs 9.7333
c 0
b 0
f 0
cc 2
nc 2
nop 8
crap 2

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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