salala 发表于 2020-12-16 10:50:18

二次开发-调整工单-多字段运算

本帖最后由 adminlily 于 2020-12-16 10:52 编辑

多字段运算和级联更新先决条件:您必须熟悉教程中使用的语法 并且已经创建了一个扩展.
学习:根据相关对象更新对象
水平:[ ttps://www.itophub.io/wiki/page?id=level&dataflt%5B0%5D=level_%3DAdvanced]高级
域:[ ttps://www.itophub.io/wiki/page?id=domains&dataflt%5B0%5D=domains_%3DPHP]PHP,[ ttps://www.itophub.io/wiki/page?id=domains&dataflt%5B0%5D=domains_%3DAutomation]Automation
最低版本:2.3.0
假设您要在A类上定义一个“计算”字段,这依赖于在B类对象上定义的数据,这比仅一个ExternalField要复杂得多。举些例子:

[*]在工单上,您需要花费在所有WorkOrder上的时间
[*]在工单上,您需要手动添加的配置项的计数。
[*]在FunctionalCI上,您需要一个Location字段,该字段仅是PhysicalDevice的位置,以及基于Logical正在运行的物理设备的位置在Logical Device上的计算位置。
[*]…

您希望能够在“已计算”字段上使用搜索。
您希望能够针对该“计算”字段运行审计。
请注意,在更新大量B类对象时,此类“计算”字段会在性能上引发风险
通用策略
这是实现这种“计算”字段的通用策略。

[*]为了能够在其上使用查询,我们必须将其存储在数据库中,因此使其成为持久字段。
[*]为了确保它总是准确的,您需要确定何时必须重新计算它并执行。为此,我们将定义覆盖这些功能:


在A班

[*]ComputeValues():根据其他与字段相关的对象,计算“已计算”字段价值。
[*]GetInitialStateAttributeFlags():指定在创建表单中隐藏“计算所得”字段
[*]GetAttributeFlag():指定修改时“计算所得”字段为只读


在依赖B类上

[*]OnUpdate(),OnDelete():检查字段是否已被修改(这将使影响度为A类的“计算”字段),设置一个内部变量以在AfterUpdate()AfterDelete()中记住它。
[*]AfterInsert,AfterUpdate(),AfterDelete:如果需要(基于上面设置的内部变量),则对具有受“变更”影响的“已计算”字段的所有对象A强制重新计算。


提示与解释

[*]我们使用AfterXXX()将变更设置为级联,而不使用OnXXX(),因为否则远程对象尚未保存在数据库中,因此基于ComputeValues的计算将使用数据库中发现的不准确的数据。
[*]我们使用OnUpdate()来检查是否需要级联和变更,因为在更新后删除数组$ this→ListChanges()为空。
[*]通常会调用ComputeValues(),但是在将对象加载到内存中时不会调用。


用例:总和
在此用例中,我们希望在工单上求和该工单的所有工作订单上花费的时间。

[*]首先,我们需要在WorkOrder和工单类上添加一个time_spent整数属性
[*]为了确保工单:: time_spent始终准确,我们需要确定何时必须重新计算它:

[*]工单更新时
[*]创建工作订单后→我们需要重新计算其工单
[*]更新工作订单后→我们需要重新计算其先前版本和新版本工单
[*]删除工作订单后→我们需要重新计算其以前的工单


[*]然后定义重写这些功能:


在工单类上

[*]ComputeTimeSpent():基于WorOrders的“ time_spent”来计算价值的“ time_spent”字段。
[*]OnUpdate():无法从默认数据模型中的工单修改工作单列表,但是如果在编辑模式下启用了该工作单,则需要此职能。
[*]GetInitialStateAttributeFlags():指定在工单创建表单上隐藏“计算的”字段
[*]GetAttributeFlag():指定在工单修改时,“计算的”字段为只读


[ ttps://www.itophub.io/wiki/page?do=export_code&id=2_7_0%3Acustomization%3Acascade-update&codeblock=0]class::Ticket

protected function ComputeTimeSpent(){   $iSum = 0;   $oWorkOrderSet = $this->Get('workorders_list');   while($oWorkOrder = $oWorkOrderSet->Fetch())   {      $iSum += $oWorkOrder->Get('time_spent');   }   $this->Set('time_spent', $iSum);} protected function OnUpdate(){$aChanges = $this->ListChanges();if (('workorders_list', $aChanges)){      $this->ComputeTimeSpent();}}public function GetInitialStateAttributeFlags($sAttCode, &$aReasons = ()){   // Hide the calculated field in object creation form   if (($sAttCode == 'time_spent'))         return(OPT_ATT_HIDDEN | parent::GetInitialStateAttributeFlags($sAttCode,
$aReasons));   return parent::GetInitialStateAttributeFlags($sAttCode, $aReasons);} public function GetAttributeFlags($sAttCode, &$aReasons = (), $sTargetState = ''){   // Force the computed field to be read-only, preventing it to be written   if (($sAttCode == 'time_spent'))         return(OPT_ATT_READONLY | parent::GetAttributeFlags($sAttCode, $aReasons,
$sTargetState));   return parent::GetAttributeFlags($sAttCode, $aReasons, $sTargetState);}
在class的工作指令

[*]OnUpdate,OnDelete:如果字段工单_id已被修改,则暂时存储先前的价值。
[*]AfterInsert,AfterUpdate,AfterDelete:强制重新计算当前和以前的工单。


[ ttps://www.itophub.io/wiki/page?do=export_code&id=2_7_0%3Acustomization%3Acascade-update&codeblock=1]class::WorkOrder


protected function UpdateTicket($id)
{
   if ($id != 0)
   {
      $oObject = MetaModel::GetObject('Ticket', $id, false);
      // FYI: MetaModel::GetObject('Ticket', 0); generates a FatalError
      if (($oObject))// in case the user is not allowed to see the object
      {
         $oObject->ComputeTimeSpent();
         $oObject->DBUpdate();
      }
   }            
}

protected function OnUpdate()
{
$aChanges = $this->ListChanges();
if (('ticket_id', $aChanges))
{
      // store in the WorkOrder memory object the previous value
      $this->iPreviousTicketId = $this->GetOriginal('ticket_id');
}
if (('time_spent', $aChanges))
{
      // record in the WorkOrder memory object that time spent was changed
      $this->bTimeChanged = true;
}
}

protected function AfterUpdate()
{
   // The WorkOrder is updated in DB and Time spent was changed,
   if (($this->bTimeChanged))
   {
       // we need to recompute TimeSpent on the Ticket
       $this->UpdateTicket($this->Get('ticket_id'));
   }
   // If there was a "former" Ticket then we also need to update it
   if (($this->iPreviousTicketId )) $this->UpdateTicket($this->iPreviousTicketId);
}

protected function AfterInsert()
{
   // A new Workorder was created with time_spent, so let's recompute the Ticket
   if ($this->Get('time_spent') > 0)   $this->UpdateTicket($this->Get


('ticket_id'));
}

protected function OnDelete()
{
   // If the deleted Workorder had some time spent set,
   // then let's flag that a recomputation is needed, and store the former Ticket


id for later use
   if ($this->GetOriginal('time_spent') > 0)   
   {
      $this->iPreviousTicketId = $this->GetOriginal('ticket_id');
   }
}

protected function AfterDelete()
{
   // If a recomputation of the former Ticket is needed, let's do it
   if (($this->iPreviousTicketId )) $this->UpdateTicket($this->iPreviousTicketI


通过检查是否在OnXXXX()职能中修改了WorkOrder :: time_spent,然后设置一个标志并在AfterXXX()中使用它以仅在真正需要时才调用UpdateTicket()来改进此示例。

页: [1]
查看完整版本: 二次开发-调整工单-多字段运算