Sidebar

Using iTop

Creating your iTop

iTop Customization

"How to" examples
DataModel

User Interface

Automation & Ticket management

Portal Customization

:: Version 3.2.0 ::

Store Count of 1:n relation

Prerequisite: You must be familiar with the Syntax used in Tutorials and have already created an extension.

learning:
Update an object based on related objects
level:
Advanced
domains:
PHP, Automation
min version:
2.3.0

This example is another specific example of that tutorial Calculated field on 1:n

Here we want to see in the details of an object A, the count of objects B which are linked to the object A through an one-to-many relationship (an external key field on class B pointing to A).

We will see two flavors of that particular case:

  1. On Ticket count the associated WorkOrders
  2. On User Request count of sub-UserRequests (special case where classes A and B are the same class)

That information is easily visible on the details of a single Ticket/User Request, but you have no mean to retrieve quickly all the Ticket/User Request with more that 2 WorkOrders/sub-requests or having no WorkOrders/sub-requests at all. This tutorial, will explain how to resolve that issue

WorkOrders on Ticket

In order to be able to do this:

  • We need to create a field count_workorders_list on the Ticket class, to store the number permanently so it can be queried.
  • We have a workorders_list field on Ticket, providing the list of sub-request under the current one
  • We have a ticket_id field on WorkOrder, providing the Ticket which work-order count must be updated

Lets define when we need to recompute?

  • When a Work Order is created, modified or deleted alone
  • When the list of work orders is modified with the Ticket it-self
itop_design / classes / class@Ticket
      <fields>
        <field id="workorders_list" xsi:type="AttributeLinkedSet">
          <with_php_computation _delta="force">true</with_php_computation>
        </field>
        <field id="count_workorders" xsi:type="AttributeInteger" _delta="define">
          <sql>count_workorders</sql>
          <default_value>0</default_value>
          <is_null_allowed>false</is_null_allowed>
          <tracking_level>all</tracking_level>
        </field>
      <fields>
      <event_listeners>
        <event_listener id="EvtOnLinksChanged" _delta="define">
          <event>EVENT_DB_LINKS_CHANGED</event>
          <callback>OnLinksChanged</callback>
          <rank>0</rank>
        </event_listener>
        <event_listener id="EvtBeforeWrite" _delta="define">
          <event>EVENT_DB_BEFORE_WRITE</event>
          <callback>BeforeWrite</callback>
          <rank>0</rank>
        </event_listener>
      </event_listeners>
      <methods>
Ticket callbacks
public function OnLinksChanged(?Combodo\iTop\Service\Events\EventData $oEventData)
{   // Note the ? in the method declaration, allowing to be called with null as parameter
    $oSet = $this->Get('workorders_list');
    $this->Set('count_workorders', $oSet->count());
    // $this->DBUpdate(); useless when $this is modified as it's automatically called at the end of callbacks
}
public function BeforeWrite(?Combodo\iTop\Service\Events\EventData $oEventData)
{
    $aChanges = $this->ListChanges();
    if (array_key_exists('workorders_list', $aChanges)) {
        $this->OnLinksChanged(null); // We have no EventData to provide, which is anyhow not used in this method
    }
}

When a WorkOrder object is created, deleted or modified alone and not within a modification of its Ticket, the callback Ticket::OnLinksChanged() will be called automatically

When the Ticket is modified and some of its workorders are created, modified or deleted at the same time as the Ticket, then EVENT_DB_LINKS_CHANGED is not called, but EVENT_DB_BEFORE_WRITE is and you should plug the recomputation in its callback

Child UserRequest

This use case is very similar to the above one. With previous methods because classes A and B are the same it was a bit different, now it is no more.

In order to be able to do this:

  • We need to create a field count_related_request_list on the UserRequest class, to store the number of sub requests permanently so it can be queried.
  • We have a related_request_list field on UserRequest, providing the list of sub-request under the current one
  • We have a parent_request_id field on UserRequest, providing the parent

Lets define when we need to compute what?

itop_design / classes / class@UserRequest
      <fields>
        <field id="related_request_list" xsi:type="AttributeLinkedSet">
          <with_php_computation _delta="force">true</with_php_computation>
        </field>
        <field id="count_related_request" xsi:type="AttributeInteger" _delta="define">
          <sql>count_related_request</sql>
          <default_value>0</default_value>
          <is_null_allowed>false</is_null_allowed>
          <tracking_level>all</tracking_level>
        </field>
      <fields>
      <event_listeners>
        <event_listener id="EvtOnLinksChanged" _delta="define">
          <event>EVENT_DB_LINKS_CHANGED</event>
          <callback>OnLinksChanged</callback>
          <rank>0</rank>
        </event_listener>
        <event_listener id="EvtBeforeWrite" _delta="define">
          <event>EVENT_DB_BEFORE_WRITE</event>
          <callback>BeforeWrite</callback>
          <rank>0</rank>
        </event_listener>
      </event_listeners>
      <methods>
UserRequest callbacks
public function BeforeWrite(?Combodo\iTop\Service\Events\EventData $oEventData)
{
    $aChanges = $this->ListChanges();
    if (array_key_exists('related_request_list', $aChanges)) {
        $this->OnLinksChanged(null);
        // Never call $this->DBUpdate(); within a callback, it's useless and ignored
    }
}
public function OnLinksChanged(?Combodo\iTop\Service\Events\EventData $oEventData)
{
    $oSet = $this->Get('related_request_list');
    $this->Set('count_related_request', $oSet->count());
    // Calling ->DBUpdate() is useful ONLY if the updated object is not $oEventData->Get('object') 
}

You can look at how it was done before, to realize how it has been simplified

3_2_0/customization/count-linkset.txt · Last modified: 2025/05/19 18:31 by 127.0.0.1
Back to top
Contact us