Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
eventmanager.php
1<?php
2
10namespace Bitrix\Main;
11
13
15{
16 protected const CACHE_ID = 'b_module_to_module';
17
21 protected static $instance;
22 protected $handlers = [];
23 protected $isHandlersLoaded = false;
24
25 protected function __construct()
26 {
27 }
28
33 public static function getInstance()
34 {
35 if (!isset(self::$instance))
36 {
37 $c = __CLASS__;
38 self::$instance = new $c;
39 }
40
41 return self::$instance;
42 }
43
48 public static function setInstance($instance)
49 {
50 $c = __CLASS__;
51 if ($instance instanceof $c)
52 {
53 self::$instance = $instance;
54 }
55 }
56
57 protected function addEventHandlerInternal($fromModuleId, $eventType, $callback, $includeFile, $sort, $version)
58 {
59 $arEvent = [
60 'FROM_MODULE_ID' => $fromModuleId,
61 'MESSAGE_ID' => $eventType,
62 'CALLBACK' => $callback,
63 'SORT' => (int)$sort,
64 'FULL_PATH' => $includeFile,
65 'VERSION' => $version,
66 'TO_NAME' => $this->formatEventName(['CALLBACK' => $callback]),
67 ];
68
69 $fromModuleId = strtoupper($fromModuleId);
70 $eventType = strtoupper($eventType);
71
72 if (!isset($this->handlers[$fromModuleId]) || !is_array($this->handlers[$fromModuleId]))
73 {
74 $this->handlers[$fromModuleId] = [];
75 }
76
77 $arEvents = &$this->handlers[$fromModuleId];
78
79 if (empty($arEvents[$eventType]) || !is_array($arEvents[$eventType]))
80 {
81 $arEvents[$eventType] = [$arEvent];
82 $iEventHandlerKey = 0;
83 }
84 else
85 {
86 $newEvents = [];
87 $iEventHandlerKey = max(array_keys($arEvents[$eventType])) + 1;
88
89 foreach ($arEvents[$eventType] as $key => $value)
90 {
91 if ($value['SORT'] > $arEvent['SORT'])
92 {
93 $newEvents[$iEventHandlerKey] = $arEvent;
94 }
95
96 $newEvents[$key] = $value;
97 }
98 $newEvents[$iEventHandlerKey] = $arEvent;
99 $arEvents[$eventType] = $newEvents;
100 }
101
102 return $iEventHandlerKey;
103 }
104
105 public function addEventHandler($fromModuleId, $eventType, $callback, $includeFile = false, $sort = 100)
106 {
107 return $this->addEventHandlerInternal($fromModuleId, $eventType, $callback, $includeFile, $sort, 2);
108 }
109
118 public function addEventHandlerCompatible($fromModuleId, $eventType, $callback, $includeFile = false, $sort = 100)
119 {
120 return $this->addEventHandlerInternal($fromModuleId, $eventType, $callback, $includeFile, $sort, 1);
121 }
122
123 public function removeEventHandler($fromModuleId, $eventType, $iEventHandlerKey)
124 {
125 $fromModuleId = strtoupper($fromModuleId);
126 $eventType = strtoupper($eventType);
127
128 if (isset($this->handlers[$fromModuleId][$eventType][$iEventHandlerKey]))
129 {
130 unset($this->handlers[$fromModuleId][$eventType][$iEventHandlerKey]);
131 return true;
132 }
133
134 return false;
135 }
136
137 public function unRegisterEventHandler($fromModuleId, $eventType, $toModuleId, $toClass = '', $toMethod = '', $toPath = '', $toMethodArg = [])
138 {
139 $toMethodArg = (!is_array($toMethodArg) || empty($toMethodArg) ? '' : serialize($toMethodArg));
140
142 $sqlHelper = $con->getSqlHelper();
143
144 $strSql =
145 "DELETE FROM b_module_to_module " .
146 "WHERE FROM_MODULE_ID='" . $sqlHelper->forSql($fromModuleId) . "'" .
147 " AND MESSAGE_ID='" . $sqlHelper->forSql($eventType) . "' " .
148 " AND TO_MODULE_ID='" . $sqlHelper->forSql($toModuleId) . "' " .
149 (($toClass != '') ? " AND TO_CLASS='" . $sqlHelper->forSql($toClass) . "' " : " AND (TO_CLASS='' OR TO_CLASS IS NULL) ") .
150 (($toMethod != '') ? " AND TO_METHOD='" . $sqlHelper->forSql($toMethod) . "'" : " AND (TO_METHOD='' OR TO_METHOD IS NULL) ") .
151 (($toPath != '' && $toPath !== 1/*controller disconnect correction*/) ? " AND TO_PATH='" . $sqlHelper->forSql($toPath) . "'" : " AND (TO_PATH='' OR TO_PATH IS NULL) ") .
152 (($toMethodArg != '') ? " AND TO_METHOD_ARG='" . $sqlHelper->forSql($toMethodArg) . "'" : " AND (TO_METHOD_ARG='' OR TO_METHOD_ARG IS NULL) ");
153
154 $con->queryExecute($strSql);
155
156 $this->clearLoadedHandlers();
157 }
158
159 public function registerEventHandler($fromModuleId, $eventType, $toModuleId, $toClass = '', $toMethod = '', $sort = 100, $toPath = '', $toMethodArg = [])
160 {
161 $this->registerEventHandlerInternal($fromModuleId, $eventType, $toModuleId, $toClass, $toMethod, $sort, $toPath, $toMethodArg, 2);
162 }
163
164 public function registerEventHandlerCompatible($fromModuleId, $eventType, $toModuleId, $toClass = '', $toMethod = '', $sort = 100, $toPath = '', $toMethodArg = [])
165 {
166 $this->registerEventHandlerInternal($fromModuleId, $eventType, $toModuleId, $toClass, $toMethod, $sort, $toPath, $toMethodArg, 1);
167 }
168
169 protected function registerEventHandlerInternal($fromModuleId, $eventType, $toModuleId, $toClass, $toMethod, $sort, $toPath, $toMethodArg, $version)
170 {
171 $toMethodArg = (!is_array($toMethodArg) || empty($toMethodArg) ? '' : serialize($toMethodArg));
172 $sort = intval($sort);
173 $version = intval($version);
174
175 $uniqueID = md5(mb_strtolower($fromModuleId . '.' . $eventType . '.' . $toModuleId . '.' . $toPath . '.' . $toClass . '.' . $toMethod . '.' . $toMethodArg . '.' . $version));
176
177 $connection = Application::getConnection();
178 $sqlHelper = $connection->getSqlHelper();
179
180 $fromModuleId = $sqlHelper->forSql($fromModuleId);
181 $eventType = $sqlHelper->forSql($eventType);
182 $toModuleId = $sqlHelper->forSql($toModuleId);
183 $toClass = $sqlHelper->forSql($toClass);
184 $toMethod = $sqlHelper->forSql($toMethod);
185 $toPath = $sqlHelper->forSql($toPath);
186 $toMethodArg = $sqlHelper->forSql($toMethodArg);
187
188 $fields = '(SORT, FROM_MODULE_ID, MESSAGE_ID, TO_MODULE_ID, TO_CLASS, TO_METHOD, TO_PATH, TO_METHOD_ARG, VERSION, UNIQUE_ID)';
189 $values = "(" . $sort . ", '" . $fromModuleId . "', '" . $eventType . "', '" . $toModuleId . "', " . " '" . $toClass . "', '" . $toMethod . "', '" . $toPath . "', '" . $toMethodArg . "', " . $version . ", '" . $uniqueID . "')";
190 $sql = $sqlHelper->getInsertIgnore('b_module_to_module', $fields, 'VALUES ' . $values);
191 $connection->queryExecute($sql);
192
193 $this->clearLoadedHandlers();
194 }
195
196 protected function formatEventName($arEvent)
197 {
198 $strName = '';
199 if (isset($arEvent['CALLBACK']))
200 {
201 if (is_array($arEvent['CALLBACK']))
202 {
203 $strName .= (is_object($arEvent['CALLBACK'][0]) ? get_class($arEvent['CALLBACK'][0]) : $arEvent['CALLBACK'][0]) . '::' . $arEvent['CALLBACK'][1];
204 }
205 elseif (is_callable($arEvent['CALLBACK']))
206 {
207 $strName .= 'callable';
208 }
209 else
210 {
211 $strName .= $arEvent['CALLBACK'];
212 }
213 }
214 else
215 {
216 $strName .= $arEvent['TO_CLASS'] . '::' . $arEvent['TO_METHOD'];
217 }
218 if (!empty($arEvent['TO_MODULE_ID']))
219 {
220 $strName .= ' (' . $arEvent['TO_MODULE_ID'] . ')';
221 }
222 return $strName;
223 }
224
225 protected function loadEventHandlers()
226 {
227 $cache = Application::getInstance()->getManagedCache();
228
229 if ($cache->read(3600, self::CACHE_ID, self::CACHE_ID))
230 {
231 $rawEvents = $cache->get(self::CACHE_ID);
232
233 if (!is_array($rawEvents))
234 {
235 $rawEvents = [];
236 }
237 }
238 else
239 {
241
242 $rs = $con->query("
243 SELECT FROM_MODULE_ID, MESSAGE_ID, SORT, TO_MODULE_ID, TO_PATH,
244 TO_CLASS, TO_METHOD, TO_METHOD_ARG, VERSION
245 FROM b_module_to_module m2m
246 INNER JOIN b_module m ON (m2m.TO_MODULE_ID = m.ID)
247 ORDER BY SORT
248 ");
249
250 $rawEvents = $rs->fetchAll();
251
252 $cache->set(self::CACHE_ID, $rawEvents);
253 }
254
256 $hasHandlers = !empty($this->handlers);
257
258 foreach ($rawEvents as $ar)
259 {
260 $ar['TO_NAME'] = $this->formatEventName([
261 'TO_MODULE_ID' => $ar['TO_MODULE_ID'],
262 'TO_CLASS' => $ar['TO_CLASS'],
263 'TO_METHOD' => $ar['TO_METHOD'],
264 ]);
265 $ar['FROM_MODULE_ID'] = strtoupper($ar['FROM_MODULE_ID']);
266 $ar['MESSAGE_ID'] = strtoupper($ar['MESSAGE_ID']);
267 if ($ar['TO_METHOD_ARG'] != '')
268 {
269 $ar['TO_METHOD_ARG'] = unserialize($ar['TO_METHOD_ARG'], ['allowed_classes' => false]);
270 }
271 else
272 {
273 $ar['TO_METHOD_ARG'] = [];
274 }
275
276 $this->handlers[$ar['FROM_MODULE_ID']][$ar['MESSAGE_ID']][] = [
277 'SORT' => (int)$ar['SORT'],
278 'TO_MODULE_ID' => $ar['TO_MODULE_ID'],
279 'TO_PATH' => $ar['TO_PATH'],
280 'TO_CLASS' => $ar['TO_CLASS'],
281 'TO_METHOD' => $ar['TO_METHOD'],
282 'TO_METHOD_ARG' => $ar['TO_METHOD_ARG'],
283 'VERSION' => $ar['VERSION'],
284 'TO_NAME' => $ar['TO_NAME'],
285 'FROM_DB' => true,
286 ];
287 }
288
289 if ($hasHandlers)
290 {
291 // need to re-sort because of AddEventHandler() calls (before loadEventHandlers)
292 foreach (array_keys($handlers) as $moduleId)
293 {
294 foreach (array_keys($handlers[$moduleId]) as $event)
295 {
296 Collection::sortByColumn(
297 $this->handlers[$moduleId][$event],
298 ['SORT' => SORT_ASC],
299 '',
300 null,
301 true
302 );
303 }
304 }
305 }
306
307 $this->isHandlersLoaded = true;
308 }
309
310 public function clearLoadedHandlers()
311 {
312 $managedCache = Application::getInstance()->getManagedCache();
313 $managedCache->clean(self::CACHE_ID, self::CACHE_ID);
314
315 foreach ($this->handlers as $module => $types)
316 {
317 foreach ($types as $type => $events)
318 {
319 foreach ($events as $i => $event)
320 {
321 if (isset($event['FROM_DB']) && $event['FROM_DB'])
322 {
323 unset($this->handlers[$module][$type][$i]);
324 }
325 }
326 }
327 }
328 $this->isHandlersLoaded = false;
329 }
330
331 public function findEventHandlers($eventModuleId, $eventType, array $filter = null)
332 {
333 if (!$this->isHandlersLoaded)
334 {
335 $this->loadEventHandlers();
336 }
337
338 $eventModuleId = strtoupper($eventModuleId);
339 $eventType = strtoupper($eventType);
340
341 if (!isset($this->handlers[$eventModuleId]) || !isset($this->handlers[$eventModuleId][$eventType]))
342 {
343 return [];
344 }
345
346 $handlers = $this->handlers[$eventModuleId][$eventType];
347 if (!is_array($handlers))
348 {
349 return [];
350 }
351
352 if (is_array($filter) && !empty($filter))
353 {
354 $handlersTmp = $handlers;
355 $handlers = [];
356 foreach ($handlersTmp as $handler)
357 {
358 if (isset($handler['TO_MODULE_ID']) && in_array($handler['TO_MODULE_ID'], $filter))
359 {
360 $handlers[] = $handler;
361 }
362 }
363 }
364
365 return $handlers;
366 }
367
368 public function send(Event $event)
369 {
370 $handlers = $this->findEventHandlers($event->getModuleId(), $event->getEventType(), $event->getFilter());
371 foreach ($handlers as $handler)
372 {
373 $this->sendToEventHandler($handler, $event);
374 }
375 }
376
377 protected function sendToEventHandler(array $handler, Event $event)
378 {
379 try
380 {
381 $result = true;
382 $includeResult = true;
383
384 $event->addDebugInfo($handler);
385
386 if (!empty($handler['TO_MODULE_ID']) && ($handler['TO_MODULE_ID'] != 'main'))
387 {
388 $result = Loader::includeModule($handler['TO_MODULE_ID']);
389 }
390 elseif (!empty($handler['TO_PATH']))
391 {
392 $path = ltrim($handler['TO_PATH'], '/');
393 if (($path = Loader::getLocal($path)) !== false)
394 {
395 $includeResult = include_once($path);
396 }
397 }
398 elseif (!empty($handler['FULL_PATH']) && IO\File::isFileExists($handler['FULL_PATH']))
399 {
400 $includeResult = include_once($handler['FULL_PATH']);
401 }
402
403 $event->addDebugInfo($result);
404
405 if ($result)
406 {
407 if (!empty($handler['TO_METHOD_ARG']) && is_array($handler['TO_METHOD_ARG']))
408 {
409 $args = $handler['TO_METHOD_ARG'];
410 }
411 else
412 {
413 $args = [];
414 }
415
416 if ($handler['VERSION'] > 1)
417 {
418 $args[] = $event;
419 }
420 else
421 {
422 $args = array_merge($args, array_values($event->getParameters()));
423 }
424
425 $callback = null;
426 if (isset($handler['CALLBACK']))
427 {
428 $callback = $handler['CALLBACK'];
429 }
430 elseif (!empty($handler['TO_CLASS']) && !empty($handler['TO_METHOD']) && class_exists($handler['TO_CLASS']))
431 {
432 $callback = [$handler['TO_CLASS'], $handler['TO_METHOD']];
433 }
434
435 if ($callback != null)
436 {
437 $result = call_user_func_array($callback, $args);
438 }
439 else
440 {
441 $result = $includeResult;
442 }
443
444 if (($result != null) && !($result instanceof EventResult))
445 {
446 $result = new EventResult(EventResult::UNDEFINED, $result, $handler['TO_MODULE_ID'] ?? null);
447 }
448
449 $event->addDebugInfo($result);
450
451 if ($result != null)
452 {
453 $event->addResult($result);
454 }
455 }
456 }
457 catch (\Exception $ex)
458 {
459 if ($event->isDebugOn())
460 {
461 $event->addException($ex);
462 }
463 else
464 {
465 throw $ex;
466 }
467 }
468 }
469}
static getConnection($name="")
addException(\Exception $exception)
Definition event.php:145
addResult(EventResult $result)
Definition event.php:129
registerEventHandler($fromModuleId, $eventType, $toModuleId, $toClass='', $toMethod='', $sort=100, $toPath='', $toMethodArg=[])
addEventHandlerInternal($fromModuleId, $eventType, $callback, $includeFile, $sort, $version)
registerEventHandlerCompatible($fromModuleId, $eventType, $toModuleId, $toClass='', $toMethod='', $sort=100, $toPath='', $toMethodArg=[])
addEventHandlerCompatible($fromModuleId, $eventType, $callback, $includeFile=false, $sort=100)
removeEventHandler($fromModuleId, $eventType, $iEventHandlerKey)
sendToEventHandler(array $handler, Event $event)
addEventHandler($fromModuleId, $eventType, $callback, $includeFile=false, $sort=100)
unRegisterEventHandler($fromModuleId, $eventType, $toModuleId, $toClass='', $toMethod='', $toPath='', $toMethodArg=[])
registerEventHandlerInternal($fromModuleId, $eventType, $toModuleId, $toClass, $toMethod, $sort, $toPath, $toMethodArg, $version)
static setInstance($instance)
findEventHandlers($eventModuleId, $eventType, array $filter=null)
static includeModule($moduleName)
Definition loader.php:69
static getLocal($path, $root=null)
Definition loader.php:529