Sidebar

Using iTop

Creating your iTop

iTop Customization

"How to" examples
DataModel

User Interface

Automation & Ticket management

Portal Customization

Events API

Events service is new in iTop 3.1

It is one of the extensibility APIs

Overview

This service provides extensibility through events.

The main behavior is that events providers register events they want to fire and events listeners register the callback functions to be called when an event is fired.

Publisher

Registration

The providers must register the events in XML prior to firing them in PHP. Registration requires:

  • an event: roughly a unique name
  • event data: parameters provided with the event
  • sources: filtering criteria usable by the listener, optional and event specific

events

The event id should follow the constants guidelines (i.e. uppercase with '_' underscore characters only), and it is also recommended that the event's name contains 'EVENT'.

  • of course it must be unique within iTop and all extensions
  • In the below example, we have named our event EVENT_DOWNLOAD_DOCUMENT
  • A string constant will automatically be created with the same name as the string
  const EVENT_DOWNLOAD_DOCUMENT = 'EVENT_DOWNLOAD_DOCUMENT'; 

event_data

Events data are given to all the listeners by the event provider when the event is fired. It's the information provided with the event, so the listener can act with sufficient information.

  • The Data are specific to the providers and consist in a flat list of values.
  • Nevertheless, the values can be any PHP value like objects or arrays, which must be specified in the declaration
  • The event data and their type are declared in the provider event registration
  • They are specifics to each event

In the below example, 5 event_datum have been declared

  • object which is a DBObject
  • document which is an ormDocument
  • att_code and content_disposition which are string
  • debug_info which is a string and is always present in Combodo's created events

sources

Events Sources is a way to filter events depending on the source of the event.

For example, for events on datamodel objects, the class of the object is a source that can be used by the listeners. In fact all the parent classes are added to the event sources, so listeners can filter events at any level of the class tree. A listener can specify to listen on “Ticket” events. All the events fired on objects inheriting from Ticket will be sent to this listener.

Result in XML

itop_design 3.1
  <events>
    <event id="EVENT_DOWNLOAD_DOCUMENT" _delta="define">
      <description>A document has been downloaded from the GUI</description>
      <sources>
        <source id="Document">Document</source>
      </sources>
      <event_data>
        <event_datum id="object">
          <description>The object containing the document</description>
          <type>DBObject</type>
        </event_datum>
        <event_datum id="document">
          <description>The document downloaded</description>
          <type>ormDocument</type>
        </event_datum>
        <event_datum id="att_code">
          <description>Attribute code of the object, containing the document</description>
          <type>string</type>
        <event_datum id="content_disposition">
          <description>To differentiate if the document was displayed in preview or truly downloaded</description>
          <type>string</type>
        <event_datum id="debug_info">
          <description>Debug string</description>
          <type>string</type>
        </event_datum>
      </event_data>
    </event>

All iTop events

  • All iTop core events declaration can be found in <itop>/code/datamodel.application.xml
  • Of course it does not include events which would be brought by an iTop extension

Event firing

This part is written in PHP. It is done by the event provider, when it makes sense to fire the event. It must provides

  • the Event data, compliant with the id and type declared in the registration
  • the applicable Event sources
ormdocument.class.inc.php
public static function DownloadDocument(WebPage $oPage, $sClass, $id, $sAttCode, $sContentDisposition = 'attachment', $sSecretField = null, $sSecretValue = null)
{  
// ...
   $aEventData = array( // Array keys are the ids of the XML event_datum
      'debug_info' => $oDocument->GetFileName(), // debug_info was declared of type string in registration
      'object' => $oObj, // object was declared as a DBObject
      'document' => $oDocument, // document was declared as an ormDocument
      'att_code' => $sAttCode,
      'content_disposition' => $sContentDisposition,
   );
   $aEventSources = [];  // We put all parents classes of the current object, so the listeners at any levels are informed
   foreach (MetaModel::EnumParentClasses(get_class($this), ENUM_PARENT_CLASSES_ALL, false) as $sClass) {
        $aEventSources[] = $sClass;
   }
 
   Combodo\iTop\Service\EventService::FireEvent( // The event name is also a constant, so can be written without quote
      new Combodo\iTop\Service\EventData(EVENT_DOWNLOAD_DOCUMENT, $aEventSources , $aEventData)
   );
// ...

Listener

The listener will specify that, if a particular event is trigger on a source which matches the filter he has specified, then a particular PHP code must be executed.

  1. event: is the string name of the event
  2. callback: the code to execute when an event matching the filter occurs.
  3. filter: a set of strings. If the event has one of the filter strings in its $aEventSources, then the callback code is executed. For many triggers, those strings correspond to classes names. It's optional.
  4. rank: If you are not the only one to react to this event, you can specify a rank, to ensure that you will be executed before or after another extension which rank you know

This registration can be done in many different ways

in XML on the class

You can define a listener inside a class User request, for this you specify:

  • event_listener id: give it any name you like, here it must be unique with the class
  • event: under XML tag event EVENT_DB_AFTER_WRITE
  • callback: under XML tag callback provide the name of a method in this class
  • rank: under XML tag rank
  • filter: under XML collection filters/filter, but implicit when declared within a class
itop_design / classes
    <class id="UserRequest" _created_in="itop-request-mgmt" _delta="must_exist">
      <event_listeners>
        <event_listener id="OnUserRequestUpdateDone" _delta="define">
          <event>EVENT_DB_AFTER_WRITE</event>
          <callback>OnUserRequestUpdateDone</callback>
          <rank>0</rank>
        </event_listener>
      </event_listeners>

Registering to event EVENT_DB_AFTER_WRITE

  • Is similar to overwriting UserRequest::OnUpdate, but without the risk to be overwritten by another customization, as all listeners to an event are called in sequence to do their job
  • Is similar to implementing iObjectApplicationExtension OnDBUpdate(), but for many events, the interface equivalent method does not exist, and with this, you have no control on execution order

in XML with direct code

Here the XML declaration is done outside of any class, at the root of itop_design XML tree.

Note in that case that:

  • the XML filter tag to declare the applicable class(es)
  • If the event is not applicable to the class in the filter, it will not fail, displays no warning, just the callback will never be called.
  • the method has no name
  • you have no access to $this, the current $oObject is provided by the Event ($oEventData→Get('object'))
itop_design
  <event_listeners>
    <event_listener id="OnAttachmentDownloadActivateTriggers" _delta="define">
      <event>EVENT_DOWNLOAD_DOCUMENT</event>
      <filters>
        <filter>Attachment</filter>
      </filters>
      <rank>0</rank>
      <code><![CDATA[
      function(\Combodo\iTop\Service\EventData $oEventData)
      {
          // callback code: same content as the OnAttachmentDownloadActivateTriggers function described in the "In PHP" section below
          if ($oEventData->Get('content_disposition') !== ormDocument::ENUM_CONTENT_DISPOSITION_ATTACHMENT) {
              return;
        }
          $oObject = $oEventData->Get('object');
        $sAttCode = $oEventData->Get('att_code');
        $oDocument = $oEventData->Get('document');
 
          ...
      }
]]></ code>  <!-- remove the blank between </ and code (wiki limitation) -->
    </event_listener>
  </event_listeners>
Here the callback code is not even put in any class method, the compilation will take care of this

Callback

If you have registered your listener in XML in a class, then create the callback as a PHP method on that class.

class:UserRequest
public function OnUserRequestUpdateDone(Combodo\iTop\Service\EventData $oEventData)
{
      $sEvent = $oEventData->GetEvent(); // Returns the Event string, in case you would need it
      $aChange = $oEventData->Get('changes'); // Same as ListChanges()
      // Do you own treatment
}

Within the callback code

  • You can get the event_data of the event publisher registration with
  $oEventData->Get('xx') // where 'xx' is the 'id' of the 'event_datum' xml tag in event registration
  • See examples just above
  • In some event, standard methods can be available on the object, such as DBObject::AddCheckIssue(), DBObject::ListChanges(),…
  • When the event and the callback method is declared on the class itself, you can use $this instead of
 $oObject = $oEventData->Get('object');

Example: on Person change

Listener in PHP

If you do this registration and callback in PHP, the easiest is to declare a new class implementing iEventServiceSetup
In one place you will do the registration in RegisterEventsAndListeners() and specify the callback code.

Listeners can specify the sources they want to listen.

  • In the first example, there is any third parameter to specify the sources, so no filter, so any Document.
  • In the second example we want to handle the specific case of a single type of source the Attachment
sources/Core/EventListener/AttributeBlobEventListener.php
class AttributeBlobEventListener implements iEventServiceSetup
{
        public function RegisterEventsAndListeners()
        {
                EventService::RegisterListener(
                        EVENT_DOWNLOAD_DOCUMENT,
                        [$this, 'OnAttributeBlobDownloadActivateTrigger']
                );
        }
 
        public function OnAttributeBlobDownloadActivateTrigger(EventData $oEventData): void
        {
              // callback code
              ...
datamodels/2.x/itop-attachments/src/Hook/EventListener.php
class EventListener implements iEventServiceSetup
{
        public function RegisterEventsAndListeners()
        {
                EventService::RegisterListener(
                        EVENT_DOWNLOAD_DOCUMENT,
                        [$this, 'OnAttachmentDownloadActivateTriggers'],
                        'Attachment'
                );
        }
 
        public function OnAttachmentDownloadActivateTriggers(EventData $oEventData): void
        {
              // callback code
              if ($oEventData->Get('content_disposition') !== ormDocument::ENUM_CONTENT_DISPOSITION_ATTACHMENT) {
                 return;
              }
              $oObject = $oEventData->Get('object');
              $sAttCode = $oEventData->Get('att_code');
              $oDocument = $oEventData->Get('document');
              ...

Existing events

To get more details on the CRUD events

  • Their name, usage
  • Their data
  • DBObject callable methods from callback code

Finding which events are associated with datamodel classes

In the Data Model page, it is possible to have all the events and listeners registered for a specific class.

latest/customization/events_api.txt · Last modified: 2023/08/23 16:13 (external edit)
Back to top
Contact us