| 本帖最后由 adminlily 于 2020-12-16 09:41 编辑 
 字段约束条件
 先决条件:您必须熟悉教程中使用的语法 并且已经创建了一个扩展. 
 学习:施加数据完整性规则 
 水平:[ ttps://www.itophub.io/wiki/page?id=level&dataflt%5B0%5D=level_%3DIntermediate]中[/url]间 
 域:[ ttps://www.itophub.io/wiki/page?id=domains&dataflt%5B0%5D=domains_%3DPHP]PHP[/url], [ ttps://www.itophub.io/wiki/page?id=domains&dataflt%5B0%5D=domains_%3DConstrain]Constrain[/url] 
 最低版本:2.1.0 
 在下面的示例中,我们将使用一种方法来检测不一致性并防止将此类对象保存在数据库中。 
 控制台或门户中的此方法在提交后报告错误。并防止创建和更新由DataSynchro,REST/JSON和CSV导入完成的含混的对象。
 
 
 理论
 
 我们将覆盖对象类的方法DoCheckToWrite(): 
 即将在写入数据库之前调用此方法-请参见调用堆栈.如果该方法遇到数据不一致性,则应提供错误消息。错误消息记录在数组$ this-> m_aCheckIssues []中,警告消息记录在数组$ this-> m_aCheckWarnings []中,从该方法返回时,如果至少有一个错误,则不会将对象写入数据库(创建或更新)错误和警告消息是
 仅以交互模式显示到用户:控制台,门户,CSV导入在跟踪DataSynchro,REST/JSON,CLI的级别上登录itop/plog/error.log依赖
 
 
 
 - - 被检查 !- 
 迁移:对设置没有可见的影响,但是在符合标准之前,不能再修改不符合标准的对象。因此,这可能会阻止datasynchro或REST/JSON脚本更新其他字段,例如。 要识别故障对象,请创建审计规则以检索不符合此新约束的对象,并在UI或CSV导入中一一修复它们。
 
 DoCheckToWrite方法可以在所有情况下防止创建或修改:在控制台,门户,CSV导入,DataSynchro和REST/JSON API中 除了覆盖DoCheckToWrite()方法,您还可以使用扩展API 并将相同的代码放入iApplicationObjectExtension :: OnCheckToWrite() 
 该API的优势在于,多个扩展可以并行进行检查,方法的覆盖只能由一个扩展名完成。
 
 
 例子开始日期<结束日期
 
 在此用例中,我们将防止记录变更的结束日期早于开始日期。 
 [ ttps://www.itophub.io/wiki/page?do=export_code&id=2_7_0%3Acustomization%3Acheck-to-write&codeblock=0]class:Change[/url] 
 public function DoCheckToWrite()    {       // Always ask the parent class to perform its own check       parent::DoCheckToWrite();         // Defensive programming, ensuring that 'end_date' and 'start_date' has not  
 been removed        // from the Change class by some extensions which I am not yet aware of.       // Get the value in seconds before comparing them is safer       if (MetaModel::IsValidAttCode(($this), 'start_date')         && MetaModel::IsValidAttCode(($this), 'end_date')        && (AttributeDateTime::GetAsUnixSeconds($this->Get('start_date'))           > AttributeDateTime::GetAsUnixSeconds($this->Get('end_date'))))       {          $this->m_aCheckIssues[] = Dict::Format 
 ('Class:Error:EndDateMustBeGreaterThanStartDate');       }    }生产服务器所需的位置
 
 在此用例中,我们要防止将服务器放入“生产”状况中,而无需提供位置。 
 [ ttps://www.itophub.io/wiki/page?do=export_code&id=2_7_0%3Acustomization%3Acheck-to-write&codeblock=1]class:Server[/url] 
 public function DoCheckToWrite() {    // Always ask the parent class to perform their own check    parent::DoCheckToWrite();    // 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(($this), 'status')    && ($this->Get('status') == 'production'))    {       // AttributeExternalKey are never NULL, O is the value used when empty       if (MetaModel::IsValidAttCode(($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_aCheckI 
这是在XML中定义字典条目的方法: 
 [ ttps://www.itophub.io/wiki/page?do=export_code&id=2_7_0%3Acustomization%3Acheck-to-write&codeblock=3]itop_design / dictionaries / dictionary@EN US / entries[/url] <entry id="Server:Error:LocationMandatoryInProduction" _delta="define">
 <![CDATA['Location is mandatory for all Servers in production']]>
 </entry>
 
 FunctionalCI名称唯一
 
 在此用例中,我们要防止两个FunctionalCI具有相同的名称。除非FunctionalCI实际上是SoftwareInstance, MiddlewareInstance,DatabaseSchema或ApplicationSolution,在这种情况下,我们不在乎。 
 唯一性规则 可以执行类似的唯一性检查,但全部以XML进行,而无需编写PHP代码。 
 [ ttps://www.itophub.io/wiki/page?do=export_code&id=2_7_0%3Acustomization%3Acheck-to-write&codeblock=4]class:FunctionalCI[/url] 
 public function DoCheckToWrite() {     // Call the function on the parent class as it may need to check stuff as well     parent::DoCheckToWrite();     // Check that the name of the FunctionalCI must be unique     $aChanges = $this->ListChanges();     // Check if the name field was set or changed     if (('name', $aChanges))     {       $sNewName = $aChanges['name'];       // Retrieve all FunctionalCI having that new name, ignoring CIs from some  
 sub-classes       $oSearch = DBObjectSearch::FromOQL_AllData("          SELECT FunctionalCI WHERE name = :newFCI           AND finalclass NOT IN  
 ('DBServer','Middleware','OtherSoftware','WebServer',              
 'PCSoftware','MiddlewareInstance','DatabaseSchema','ApplicationSolution')       ");       $oSet = new DBObjectSet($oSearch, (), ('newFCI' => $sNewName));       // If there is at least one FunctionalCI matching the required name       if ($oSet->() > 0)       {          // Block the FunctionalCI writing the Database          $this->m_aCheckIssues[] = Dict::Format 
 ('Class:FunctionalCI:FCINameMustBeUnique', $sNewName);       }    } }用户必须具有简档
 
 这就是iTop如何确保用户始终至少连接一个简档的方式。 
 强制n:n关系至少具有一个条目是一个很好的例子。请注意,这还不足以防止删除简档,而这将是给定用户中的唯一一个
 在此特定示例中没什么大不了的,因为iTop UI并不意味着删除简档就是供应
 
 
 如果对当前对象的其他对象进行检查,则DoCheckToWrite或iApplicationObjectExtension :: OnCheckToWrite()无法保证将始终应用该规则。例如是这种情况。在本示例中,在LinkedSet或LinkedSetIndirect字段上测试条件时。 
  写一个关于如何确保LinkedSet字段总是至少一个条目的教程
 [ ttps://www.itophub.io/wiki/page?do=export_code&id=2_7_0%3Acustomization%3Acheck-to-write&codeblock=5]class:User[/url] 
 public function DoCheckToWrite() {     // Call the function on the parent class as it may need to check stuff as well     parent::DoCheckToWrite();     // Check that the name of the FunctionalCI must be unique     $aChanges = $this->ListChanges();    // Check if the profile list was changed to avoid loading it for nothing    if (('profile_list', $aChanges))    {         $oSet = $this->Get('profile_list');         if ($oSet->() == 0)         {              $this->m_aCheckIssues[] = Dict::S 
 ('Class:User/Error:AtLeastOneProfileIsNeeded');         }     } }
 
 |