mirror of
https://github.com/Combodo/iTop.git
synced 2026-04-25 19:48:49 +02:00
* refactor
* Add event AFTER_DISPLAY_PAGE
This commit is contained in:
298
sources/application/Service/EventService.php
Normal file
298
sources/application/Service/EventService.php
Normal file
@@ -0,0 +1,298 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2020 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Service;
|
||||
|
||||
use Closure;
|
||||
use ContextTag;
|
||||
use Exception;
|
||||
use ExecutionKPI;
|
||||
use IssueLog;
|
||||
|
||||
define('LOG_EVENT_SERVICE_CHANNEL', 'EventService');
|
||||
|
||||
class EventService
|
||||
{
|
||||
private static $aEvents = array();
|
||||
private static $iEventIdCounter = 0;
|
||||
|
||||
/**
|
||||
* Register a callback for a specific event
|
||||
*
|
||||
* @param string $sEvent corresponding event
|
||||
* @param callable $callback The callback to call
|
||||
* @param array|string|null $sEventSource event filtering depending on the source of the event
|
||||
* @param array $aCallbackData optional data given by the registrar to the callback
|
||||
* @param array|string|null $context context filter
|
||||
* @param float $fPriority optional priority for callback order
|
||||
*
|
||||
* @return string Id of the registration (used for unregistering)
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function Register($sEvent, callable $callback, $sEventSource = null, $aCallbackData = array(), $context = null, $fPriority = 0.0)
|
||||
{
|
||||
is_callable($callback, false, $sName);
|
||||
|
||||
$aEventCallbacks = isset(self::$aEvents[$sEvent]) ? self::$aEvents[$sEvent] : array();
|
||||
$sId = 'event_'.self::$iEventIdCounter++;
|
||||
$aEventCallbacks[] = array(
|
||||
'id' => $sId,
|
||||
'callback' => $callback,
|
||||
'source' => $sEventSource,
|
||||
'name' => $sName,
|
||||
'data' => $aCallbackData,
|
||||
'context' => $context,
|
||||
'priority' => $fPriority,
|
||||
);
|
||||
usort($aEventCallbacks, function ($a, $b) {
|
||||
$fPriorityA = $a['priority'];
|
||||
$fPriorityB = $b['priority'];
|
||||
if ($fPriorityA == $fPriorityB) {
|
||||
return 0;
|
||||
}
|
||||
return ($fPriorityA < $fPriorityB) ? -1 : 1;
|
||||
});
|
||||
self::$aEvents[$sEvent] = $aEventCallbacks;
|
||||
|
||||
if (IssueLog::CanLog(IssueLog::LEVEL_DEBUG, LOG_EVENT_SERVICE_CHANNEL))
|
||||
{
|
||||
$iTotalRegistrations = 0;
|
||||
foreach (self::$aEvents as $aEvent)
|
||||
{
|
||||
$iTotalRegistrations += count($aEvent);
|
||||
}
|
||||
$sEventName = "$sEvent:".self::GetSourcesAsString($sEventSource);
|
||||
IssueLog::Trace("Registering event '$sEventName' for '$sName' with id '$sId' (total $iTotalRegistrations)", LOG_EVENT_SERVICE_CHANNEL);
|
||||
}
|
||||
return $sId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fire an event. Call all the callbacks registered for this event.
|
||||
*
|
||||
* @param string $sEvent event to trigger
|
||||
* @param string|array $eventSource source of the event
|
||||
* @param array $aEventData event related data
|
||||
*
|
||||
* @throws \Exception from the callback
|
||||
*/
|
||||
public static function FireEvent($sEvent, $eventSource = null, $aEventData = array())
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
$sSource = isset($aEventData['debug_info']) ? " {$aEventData['debug_info']}" : '';
|
||||
$sEventName = "$sEvent:".self::GetSourcesAsString($eventSource);
|
||||
IssueLog::Trace("Fire event '$sEventName'$sSource", LOG_EVENT_SERVICE_CHANNEL);
|
||||
if (!isset(self::$aEvents[$sEvent]))
|
||||
{
|
||||
IssueLog::Trace("No registration found for event '$sEvent'", LOG_EVENT_SERVICE_CHANNEL);
|
||||
$oKPI->ComputeStats('FireEvent', $sEvent);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (self::$aEvents[$sEvent] as $aEventCallback)
|
||||
{
|
||||
if (!self::MatchEventSource($aEventCallback['source'], $eventSource))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!self::MatchContext($aEventCallback['context']))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
$sName = $aEventCallback['name'];
|
||||
IssueLog::Debug("Fire event '$sEventName'$sSource calling '{$sName}'", LOG_EVENT_SERVICE_CHANNEL);
|
||||
try
|
||||
{
|
||||
if (is_callable($aEventCallback['callback']))
|
||||
{
|
||||
call_user_func($aEventCallback['callback'], new EventData($sEvent, $eventSource, $aEventData, $aEventCallback['data']));
|
||||
}
|
||||
else
|
||||
{
|
||||
IssueLog::Debug("Callback '{$sName}' not a callable anymore, unregister", LOG_EVENT_SERVICE_CHANNEL);
|
||||
self::UnRegisterCallback($aEventCallback['id']);
|
||||
}
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
IssueLog::Error("Event '$sEventName' for '{$sName}' id {$aEventCallback['id']} failed with error: ".$e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
$oKPI->ComputeStats('FireEvent', $sEvent);
|
||||
}
|
||||
|
||||
private static function MatchEventSource($srcRegistered, $srcEvent)
|
||||
{
|
||||
if (empty($srcRegistered))
|
||||
{
|
||||
// no filtering
|
||||
return true;
|
||||
}
|
||||
if (empty($srcEvent))
|
||||
{
|
||||
// no match (the registered source is not empty)
|
||||
return false;
|
||||
}
|
||||
if (is_string($srcRegistered))
|
||||
{
|
||||
$aSrcRegistered = array($srcRegistered);
|
||||
}
|
||||
elseif (is_array($srcRegistered))
|
||||
{
|
||||
$aSrcRegistered = $srcRegistered;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aSrcRegistered = array();
|
||||
}
|
||||
|
||||
if (is_string($srcEvent))
|
||||
{
|
||||
$aSrcEvent = array($srcEvent);
|
||||
}
|
||||
elseif (is_array($srcEvent))
|
||||
{
|
||||
$aSrcEvent = $srcEvent;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aSrcEvent = array();
|
||||
}
|
||||
|
||||
foreach ($aSrcRegistered as $sSrcRegistered)
|
||||
{
|
||||
foreach ($aSrcEvent as $sSrcEvent)
|
||||
{
|
||||
if ($sSrcRegistered == $sSrcEvent)
|
||||
{
|
||||
// sources matches
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// no match
|
||||
return false;
|
||||
}
|
||||
|
||||
private static function MatchContext($registeredContext)
|
||||
{
|
||||
if (empty($registeredContext))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (is_string($registeredContext))
|
||||
{
|
||||
$aContexts = array($registeredContext);
|
||||
}
|
||||
elseif (is_array($registeredContext))
|
||||
{
|
||||
$aContexts = $registeredContext;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
foreach ($aContexts as $sContext)
|
||||
{
|
||||
if (ContextTag::Check($sContext))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static function GetSourcesAsString($srcRegistered)
|
||||
{
|
||||
if (empty($srcRegistered))
|
||||
{
|
||||
return '';
|
||||
}
|
||||
if (is_string($srcRegistered))
|
||||
{
|
||||
return $srcRegistered;
|
||||
}
|
||||
if (is_array($srcRegistered))
|
||||
{
|
||||
$sStr = implode(',', $srcRegistered);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister a previously registered callback
|
||||
*
|
||||
* @param string $sId the callback registration id
|
||||
*/
|
||||
public static function UnRegisterCallback($sId)
|
||||
{
|
||||
$bRemoved = self::Browse(function ($sEvent, $idx, $aEventCallback) use ($sId) {
|
||||
if ($aEventCallback['id'] == $sId)
|
||||
{
|
||||
$sName = self::$aEvents[$sEvent][$idx]['name'];
|
||||
unset (self::$aEvents[$sEvent][$idx]);
|
||||
IssueLog::Trace("Unregistered callback '{$sName}' id {$sId}' on event '{$sEvent}'", LOG_EVENT_SERVICE_CHANNEL);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (!$bRemoved)
|
||||
{
|
||||
IssueLog::Trace("No registration found for callback '{$sId}'", LOG_EVENT_SERVICE_CHANNEL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister an event
|
||||
*
|
||||
* @param string $sEvent event to unregister
|
||||
*/
|
||||
public static function UnRegisterEvent($sEvent)
|
||||
{
|
||||
if (!isset(self::$aEvents[$sEvent]))
|
||||
{
|
||||
IssueLog::Trace("No registration found for event '$sEvent'", LOG_EVENT_SERVICE_CHANNEL);
|
||||
return;
|
||||
}
|
||||
|
||||
unset(self::$aEvents[$sEvent]);
|
||||
IssueLog::Trace("Unregistered all the callbacks on event '{$sEvent}'", LOG_EVENT_SERVICE_CHANNEL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister all the events
|
||||
*/
|
||||
public static function UnRegisterAll()
|
||||
{
|
||||
self::$aEvents = array();
|
||||
IssueLog::Trace("Unregistered all events", LOG_EVENT_SERVICE_CHANNEL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Browse all the registrations
|
||||
*
|
||||
* @param \Closure $callback function($sEvent, $idx, $aEventCallback) to call (return false to interrupt the browsing)
|
||||
*
|
||||
* @return bool true if interrupted else false
|
||||
*/
|
||||
private static function Browse(closure $callback)
|
||||
{
|
||||
foreach (self::$aEvents as $sEvent => $aCallbackList)
|
||||
{
|
||||
foreach ($aCallbackList as $idx => $aEventCallback)
|
||||
{
|
||||
if (call_user_func($callback, $sEvent, $idx, $aEventCallback) === false)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user