Using Events instead of methods
Methods & Events
DBObject methods | iApplicationObjectExtension | Events (iTop 3.1 min) |
---|---|---|
ComputeValues | n/a | EVENT_DB_COMPUTE_VALUES |
DoCheckToWrite | OnCheckToWrite | EVENT_DB_CHECK_TO_WRITE |
DoCheckToDelete | OnCheckToDelete | EVENT_DB_CHECK_TO_DELETE |
GetAttributeFlags | n/a | EVENT_DB_SET_ATTRIBUTES_FLAGS |
GetInitialStateAttributeFlags | n/a | EVENT_DB_SET_INITIAL_ATTRIBUTES_FLAGS |
n/a | n/a | EVENT_DB_LINKS_CHANGED |
n/a | n/a | EVENT_ADD_ATTACHMENT_TO_OBJECT |
n/a | n/a | EVENT_REMOVE_ATTACHMENT_FROM_OBJECT |
EnumTransitions | n/a | EVENT_ENUM_TRANSITION |
OnInsert | n/a | EVENT_DB_BEFORE_WRITE |
AfterInsert | OnDBInsert | EVENT_DB_AFTER_WRITE |
OnUpdate | n/a | EVENT_DB_BEFORE_WRITE |
AfterUpdate | OnDBUpdate | EVENT_DB_AFTER_WRITE |
OnDelete | OnDBDelete | EVENT_DB_ABOUT_TO_DELETE |
AfterDelete | n/a | EVENT_DB_AFTER_DELETE |
Non replaceable methods
DBObject methods | iApplicationObjectExtension | Events |
PrefillSearchForm | n/a | n/a |
PrefillCreationForm | n/a | n/a |
PrefillTransitionForm | n/a | n/a |
DisplayBareRelations | n/a | n/a |
Below explanation is a extract from this reference: Events API
Migrating from DBObject methods overload to listeners
-
Register to an event within a class in order to execute some code in a callback method.
-
Enter the PHP code you want to execute in an object method.
- itop_design version="3.1"
-
<classes> <class id="UserRequest"> <event_listeners> <event_listener id="HideTransitionsIfApprovalRule" _delta="define"> <event>EVENT_ENUM_TRANSITIONS</event> <rank>10</rank> <callback>HideTransitionsIfApprovalRule</callback> </event_listener> </event_listeners> <methods> <method id="HideTransitionsIfApprovalRule" _delta="define"> <comment>/** * If an approval rule could apply to the current object, hide all transitions * As the service and service subcategory are not yet set, we can't determine if the approval rule will really apply * So we hide all transitions if the object is new and in a state where an approval rule could apply */</comment> <static>false</static> <access>public </access> <code><![CDATA[public function HideTransitionsIfApprovalRule(Combodo\iTop\Service\Events\EventData $oEventData) { // PHP code here... }]]></ code> </method> </methods>
-
Callback method receive an event in parameter, you may allow it to be null in the signature, to reuse the method
Migrating from iApplicationObjectExtension to listeners
Pure PHP
In any case, consider first the pure PHP way of handling an event. Paste the sample hereafter and tune it until it matches your need.
/** * Template to ease migration of hooks from iApplicationObjectExtension to event-based listeners. * To be used as a starting point: * - the list of classes to listen to must be specified (or the parameter omitted to listen to all classes) * - the code of the former hooks must be copied/pasted in the appropriate methods * - unnecessary listeners must be removed * - the proposed events are the closest to the former hooks, but may not be the best suited. * - the whole stuff could be defined in XML instead of PHP, allowing finer control (priority, etc.) at integration time */ class MyCustomHooks implements iEventServiceSetup { public function RegisterEventsAndListeners() : void { // TODO: Remove unnecessary listeners EventService::RegisterListener(EVENT_DB_CHECK_TO_WRITE, [$this, 'OnDBCheckToWrite'], ['Class1', 'Class2']); // TODO: Specify the classes to listen to, or omit this parameter to listen to all classes EventService::RegisterListener(EVENT_DB_CHECK_TO_DELETE, [$this, 'OnDBCheckToDelete'], ['Class1', 'Class2']); // TODO: Specify the classes to listen to, or omit this parameter to listen to all classes EventService::RegisterListener(EVENT_DB_AFTER_WRITE, [$this, 'OnDBAfterWrite'], ['Class1', 'Class2']); // TODO: Specify the classes to listen to, or omit this parameter to listen to all classes EventService::RegisterListener(EVENT_DB_ABOUT_TO_DELETE, [$this, 'OnDBAboutToDelete'], ['Class1', 'Class2']); // TODO: Specify the classes to listen to, or omit this parameter to listen to all classes } public function OnDBCheckToWrite(EventData $oEventData) { $oObject = $oEventData->Get('object'); // TODO: Put here the code implemented previously in OnCheckToWrite and report issues using AddCheckIssue, instead of returning them as an array // // Example: // if ($oObject->Get('some_field') == 'some_value') { // $oObject->AddCheckIssue('Some message'); // } } public function OnDBCheckToDelete(EventData $oEventData) { $oObject = $oEventData->Get('object'); // TODO: Put here the code implemented previously in OnCheckToDelete and report issues using AddDeleteIssue, instead of returning them as an array // // Example: // if ($oObject->Get('some_field') == 'some_value') { // $oObject->AddDeleteIssue('Some message'); // } } public function OnDBAfterWrite(EventData $oEventData) { $oObject = $oEventData->Get('object'); if ($oEventData->Get('is_new')) { // TODO: Put here the code implemented previously in OnDBInsert } else { // TODO: Put here the code implemented previously in OnDBUpdate } } public function OnDBAboutToDelete(EventData $oEventData) { $oObject = $oEventData->Get('object'); // TODO: Put here the code implemented previously in OnDBDelete } }
In XML
-
Register to an event outside [or within] a class in order to execute some code,
-
provide that code outside [or within] a class
Example from combodo-autodispatch-ticket where the listener is called for any class:
- itop_design version="3.1"
-
<event_listeners> <event_listener id="HideTransitionsIfAutoDispatchRule" _delta="define"> <event>EVENT_DB_AFTER_WRITE</event> <filters/> <rank>0</rank> <code><![CDATA[function(Combodo\iTop\Service\Events\EventData $oEventData) { $oObject = $oEventData->Get('object'); if ($oEventData->Get('is_new')) { // TODO: Put here the code implemented previously in OnDBInsert } else { // TODO: Put here the code implemented previously in OnDBUpdate } } ]]></ code> </event_listener> </event_listeners>
Events
EVENT_DB_COMPUTE_VALUES
Register to this event in order to compute the value of field based on the values of other fields of the same object…
public function EvtComputeValues(Combodo\iTop\Service\Events\EventData $oEventData) { $this->Set('vat', 0.2*$this->Get('cost')); }
-
You can know if you are within a particular transition, using
$oEventData->Get('stimulus_applied') // null if not in a transition
In previous versions of iTop and in some classes, you may
encounter the method ComputeValues()
which is
deprecated and was performing the same job.
Example: Compute WorkOrder End Date
EVENT_DB_SET_INITIAL_ATTRIBUTES_FLAGS
There are two different EVENTs, one before displaying the creation form and the other on displaying the modification form of a given class
public function EvtSetInitialAttributeFlags(Combodo\iTop\Service\Events\EventData $oEventData) { $this->AddInitialAttributeFlags($sAttCode, $iFlags); // To add flags to a field $this->ForceInitialAttributeFlags($sAttCode, $iFlags); // To force the flags of a field } /* constant values for $iFlags to combine with bit operator | * OPT_ATT_NORMAL * OPT_ATT_HIDDEN * OPT_ATT_READONLY * OPT_ATT_MANDATORY * OPT_ATT_MUSTCHANGE * OPT_ATT_MUSTPROMPT */
EVENT_DB_SET_ATTRIBUTES_FLAGS
public function EvtSetAttributeFlags(Combodo\iTop\Service\Events\EventData $oEventData) { $this->AddAttributeFlags($sAttCode, $iFlags); // To add flags to a field $this->ForceAttributeFlags($sAttCode, $iFlags); // To force the flags of a field }
The methods GetAttributeFlags and GetInitialStateAttributeFlags which were performing the same job and can still be found on some classes in the Designer are deprecated and should no more be used.
EVENT_DB_CHECK_TO_WRITE
This event is triggered just before an object is written in
database.
-
It allow to prevent recording the current object if certain conditions aren’t met
-
It can also simply warn the user about non blocking issue.
-
Adding a
AddCheckIssue
message in the callback method, will stop the object creation/modification/transition with an error message// A blocking issue $this->AddCheckIssue('Some error message'); // A non-blocking warning $this->AddCheckWarning('Some warning message');
-
You can know if you are within a particular transition, using
$oEventData->Get('stimulus_applied') // Empty string if not in a transition
It is too late to modify the object itself
Check UserRequest::DoCheckToWrite() in Designer, method doing the same job but deprecated.
Example: Check data integrity
EVENT_DB_BEFORE_WRITE
If you want to modify the current object automatically, the right answer is usually EVENT_DB_COMPUTE_VALUES.
-
If this change must only occur at object creation, use EVENT_DB_BEFORE_WRITE and test if you are in creation using
$oEventData->Get('is_new') == $this->IsNew()
-
You can know if you are within a particular transition, using
$oEventData->Get('stimulus_applied') // Empty string if not in a transition
* If this update is resources intensive and should only be done if some field have been set/modified, then do it in an EVENT_DB_BEFORE_ WRITE after having checked the on-going changes:
$this->ListChanges()
Example: Compute WorkOrder End Date
EVENT_DB_AFTER_WRITE
If you want to modify other objects automatically when a given object is modified. The event to use is EVENT_DB_AFTER_WRITE.
-
It is triggered once after the current object is saved in DB
-
Test if the object was just created with
$oEventData->Get('is_new') === true
-
Test if you are within a particular transition, using
$oEventData->Get('stimulus_applied') // Empty string if not in a transition
-
To checked the performed changes, use one or the other:
$aChanges = $oEventData->Get('changes'); $aChanges = $this->ListPreviousValuesForUpdatedAttributes();
EVENT_DISPLAY_OBJECT_DETAILS
This event is triggered just before an object is displayed in a User Portal.
-
It’s not design to act on what is displayed, but it allow you to count how many times a FAQ was displayed in the User Portal for eg. and maybe store this count within the FAQ object it-self.
EVENT_DB_LINKS_CHANGED
This event is triggered on an object, after the modification of one of its LinkedSet flagged with « PHP computation ».
-
It is not triggered if the host object it-self is modified
-
It is not triggered if a PHP code update the LinkedSet of an object
$oObj->Set(‘xxxx_list’, $oSet); $oObj->DBUpdate();
-
It is not triggered if the remote object of a LinkedSetIndirect is modified (eg. on a Team.persons_list, a change a status on Person)
-
It is triggered if one sub-object inside the LinkedSetAttribute is added, remove or modified individually (either from the other side of the links or with the host object being in display mode)
During this execution of the callback, you don’t know:
-
What has changed, not even which LinkedSet
-
If the current object was just created or modified
Use-cases: It allows to be sure that as soon as a link is created, modified or deleted, your code is executed. It can be used for storing a count or sum of relations, reordering them, finding one relation having a particular value and storing it in the object as an ExternalKey.
Example: LinkedSet related values
EVENT_ENUM_TRANSITIONS
This event is triggered just before an object is displayed.
-
It allows to remove transitions from an object on some conditions.
-
For example prevent a user other than the current agent to reassign a Ticket to another team.
-
If you remove a transition which is not available it has no effect.
$this->DenyTransition($sStimulusCode)
It is a not a UI only limitation
EVENT_ADD_ATTACHMENT_TO_OBJECT
This event is triggered on the object, just after an attachment is added to it.
-
It allows to add an entry in the caselog or test constrains on the attachment and remove it automatically on some conditions (file types at risk for eg.)
$oEventData->Get('attachment')