×

扫描二维码登录本站

QQ登录

只需一步,快速开始

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

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

多字段运算和级联更新
先决条件:您必须熟悉教程中使用的语法 并且已经创建了一个扩展.

学习:根据相关对象更新对象

水平:高级

域:PHP,  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():指定在工单修改时,“计算的”字段为只读


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:强制重新计算当前和以前的工单。


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()来改进此示例。






上一篇:二次开发-调整工单-统计工单重开次数
下一篇:二次开发-调整工单-排除非工作时间
salala

写了 312 篇文章,拥有财富 1686,被 3 人关注

您需要登录后才可以回帖 登录 | 立即注册
B Color Link Quote Code Smilies

成为第一个吐槽的人

手机版|小黑屋|最新100贴|论坛版块|ITIL先锋论坛 |粤ICP备11099876号|网站地图
Powered by Discuz! X3.4 Licensed  © 2001-2017 Comsenz Inc.
返回顶部