:: Version 3.0.0 ::

Force a field to be mandatory on condition

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

Force a field to be filled on condition
PHP, Constrain
min version:

This use case is just one way of forcing a field to be provided.

Check before Submission

This method can force a field to be provided, on the Console, CSV import and in the Portal
But it does not work for DataSynchro and REST/JSON API.
Warning, this methods works only with iTop 2.7.1 and after

Only Server in production

In this use case, we only want to ensure that all Server in production, do have a location documented.

In theory we could use the GetAttributeFlags methods, adding a dependency between location_id and status, to ensure a refresh of the form, when the status is changed.

itop_design / classes
    <class id="PhysicalDevice">
        <field id="location_id">
          <!-- force location_id flags to be recomputed if status is changed -->
          <dependencies _delta="redefine">
            <attribute id="org_id"/>
            <attribute id="status"/>
    <class id="Server" _delta="must_exist">
        <method id="GetInitialStateAttributeFlags" _delta="define">
          <access>public </access>
public function GetInitialStateAttributeFlags($sAttCode, &$aReasons = array())
   if (($sAttCode == 'location_id') 
       && (MetaModel::IsValidAttCode(get_class($this), 'status'))
       && ($this->Get('status') == 'production'))
      return(OPT_ATT_MANDATORY | parent::GetInitialStateAttributeFlags($sAttCode, $aReasons));
   return parent::GetInitialStateAttributeFlags($sAttCode, $aReasons);
          ]]></ code>
        <method id="GetAttributeFlags" _delta="define">
          <access>public </access>
public function GetAttributeFlags($sAttCode, &$aReasons = array(), $sTargetState = '')
   if (($sAttCode == 'location_id') 
        && (MetaModel::IsValidAttCode(get_class($this), 'status'))
        && ($this->Get('status') == 'production'))
      return(OPT_ATT_MANDATORY | parent::GetAttributeFlags($sAttCode, $aReasons, $sTargetState));
   return parent::GetAttributeFlags($sAttCode, $aReasons, $sTargetState);
          ]]></ code>

Only Server and Network Device in production

Declare the above method twice, one on each class Server and NetworkDevice

Only Datacenter Devices in production

Declare the above method on class DatacenterDevice instead of Server

Check on Submission

We can also check on submission that a location was provided, if not, we prevent the creation/modification and display an error message so the user can fill the Location and submit again.

This method can force a field to be provided, on the Console, CSV import, in the Portal, in DataSynchro and REST/JSON API.

We will overwrite the method DoCheckToWrite() of the object class:

  • This method is invoked just before writing to database - See details of call stack.
  • The method should provide error message(s) if it encounters data incoherence.
  • Errors messages are recorded in an array $this->m_aCheckIssues[],
  • Warnings messages are recorded in an array $this->m_aCheckWarnings[],
  • When returning from this method, if there is at least one error the object is not written to database (creation or update)
  • Error and warning messages are
    • displayed to the user in interactive mode only: Console, Portal, CSV import
    • logged in itop/log/error.log depending on level of tracking for DataSynchro, REST/JSON, CLI FIXME -to be checked !-

Migration: No visible effect on setup, but objects not compliant can no more be modified, until they are made compliant. So it could prevent a datasynchro or a REST/JSON script to update other fields for eg.
To identify faulty objects, create an audit rule to retrieve objects not compliant to this new constrain and fix them one by one in the UI or by CSV import.

DoCheckToWrite method can prevent creation/modification in all cases: on the Console, in the Portal, in CSV import, in DataSynchro and in REST/JSON API
Instead of overwriting the DoCheckToWrite() method, you can also use the Extensions API and put that same code into iApplicationObjectExtension::OnCheckToWrite()
  • The advantage of the API is that multiple extensions can do their check in parallel,
  • The overwrite of method can only be done by a single extension.
Do not try to Set values on current object in this method as it has effect

In this use case we want to prevent a Server to be put in 'production' status without a Location to be provided.

public function DoCheckToWrite()
   // Always ask the parent class to perform their own check
   // Defensive programming, ensuring that 'status' is an existing field on the current class
   // then checking the condition: an enum value returns code, not label, so we test the code,
   if (MetaModel::IsValidAttCode(get_class($this), 'status')
   && ($this->Get('status') == 'production'))
      // AttributeExternalKey are never NULL, O is the value used when empty
      if (MetaModel::IsValidAttCode(get_class($this), 'location_id')
      && ($this->Get('location_id') == 0))
         // 'Server:Error:LocationMandatoryInProduction' must be declared as a dictionary entry
         $this->m_aCheckIssues[] = Dict::Format('Server:Error:LocationMandatoryInProduction');
         // You may also provide a simple error message in plain text
         $this->m_aCheckIssues[] = 'Location is mandatory for all Servers in production';

Here the way to define a dictionary entry in XML:

itop_design / dictionaries / dictionary@EN US / entries
    <entry id="Server:Error:LocationMandatoryInProduction" _delta="define">
      <![CDATA['Location is mandatory for all Servers in production']]>
3_0_0/customization/mandatory-field-on-condition.txt ยท Last modified: 2021/07/06 15:44 (external edit)
Back to top
Contact us