mirror of
https://github.com/Combodo/iTop.git
synced 2026-04-21 01:28:47 +02:00
Retrofit from trunk
N°789 - Fix losing the additional links attributes values during impact analysis update [from revision 5162] SVN:2.4[5163]
This commit is contained in:
@@ -123,7 +123,8 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|
||||
{
|
||||
assert($oLink instanceof $this->sClass);
|
||||
// No impact on the iteration algorithm
|
||||
$this->aAdded[] = $oLink;
|
||||
$iObjectId = $oLink->GetKey();
|
||||
$this->aAdded[$iObjectId] = $oLink;
|
||||
$this->bHasDelta = true;
|
||||
}
|
||||
|
||||
@@ -148,6 +149,13 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|
||||
$this->aRemoved[$iObjectId] = $iObjectId;
|
||||
$this->bHasDelta = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (array_key_exists($iObjectId, $this->aAdded))
|
||||
{
|
||||
unset($this->aAdded[$iObjectId]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -587,7 +595,7 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|
||||
$oSearch->AddCondition($sExtKeyToMe, $oHostObject->GetKey(), '=');
|
||||
$oSearch->AddCondition($sExtKeyToRemote, $aCheckRemote, 'IN');
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
$aExistingRemote = $oSet->GetColumnAsArray($sExtKeyToRemote);
|
||||
$aExistingRemote = $oSet->GetColumnAsArray($sExtKeyToRemote, true);
|
||||
}
|
||||
|
||||
// Write the links according to the existing links
|
||||
@@ -601,11 +609,28 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|
||||
{
|
||||
if (count($aCheckRemote) > 0)
|
||||
{
|
||||
if (in_array($oLink->Get($sExtKeyToRemote), $aExistingRemote))
|
||||
{
|
||||
// Do not create a duplicate
|
||||
continue;
|
||||
}
|
||||
$bIsDuplicate = false;
|
||||
foreach($aExistingRemote as $sLinkKey => $sExtKey)
|
||||
{
|
||||
if ($sExtKey == $oLink->Get($sExtKeyToRemote))
|
||||
{
|
||||
// Do not create a duplicate
|
||||
// + In the case of a remove action followed by an add action
|
||||
// of an existing link,
|
||||
// the final state to consider is add action,
|
||||
// so suppress the entry in the removed list.
|
||||
if (array_key_exists($sLinkKey, $this->aRemoved))
|
||||
{
|
||||
unset($this->aRemoved[$sLinkKey]);
|
||||
}
|
||||
$bIsDuplicate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($bIsDuplicate)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,287 +1,286 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2017 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* Base class for computing TTO or TTR on a ticket
|
||||
*/
|
||||
class ResponseTicketSLT
|
||||
{
|
||||
/**
|
||||
* Determines the shortest SLT, for this ticket, for the given metric. Returns null is no SLT was found
|
||||
* @param string $sMetric Type of metric 'TTO', 'TTR', etc as defined in the SLT class
|
||||
* @return hash Array with 'SLT' => name of the SLT selected, 'value' => duration in seconds of the SLT metric, null if no SLT applies to this ticket
|
||||
*/
|
||||
protected static function ComputeSLT($oTicket, $sMetric = 'TTO')
|
||||
{
|
||||
$iDeadline = null;
|
||||
if (MetaModel::IsValidClass('SLT'))
|
||||
{
|
||||
$sType=get_class($oTicket);
|
||||
if ($sType == 'Incident')
|
||||
{
|
||||
$sRequestType = 'incident';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sRequestType = $oTicket->Get('request_type');
|
||||
}
|
||||
|
||||
$aArgs = $oTicket->ToArgs();
|
||||
$aArgs['metric'] = $sMetric;
|
||||
$aArgs['request_type'] = $sRequestType;
|
||||
|
||||
//echo "<p>Managing:".$sMetric."-".$this->Get('request_type')."-".$this->Get('importance')."</p>\n";
|
||||
$oSLTSet = new DBObjectSet(DBObjectSearch::FromOQL(RESPONSE_TICKET_SLT_QUERY),
|
||||
array(),
|
||||
$aArgs
|
||||
);
|
||||
|
||||
$iMinDuration = PHP_INT_MAX;
|
||||
$sSLTName = '';
|
||||
|
||||
while($oSLT = $oSLTSet->Fetch())
|
||||
{
|
||||
$iDuration = (int)$oSLT->Get('value');
|
||||
$sUnit = $oSLT->Get('unit');
|
||||
switch($sUnit)
|
||||
{
|
||||
case 'days':
|
||||
$iDuration = $iDuration * 24; // 24 hours in 1 days
|
||||
// Fall though
|
||||
|
||||
case 'hours':
|
||||
$iDuration = $iDuration * 60; // 60 minutes in 1 hour
|
||||
// Fall though
|
||||
|
||||
case 'minutes':
|
||||
$iDuration = $iDuration * 60;
|
||||
}
|
||||
if ($iDuration < $iMinDuration)
|
||||
{
|
||||
$iMinDuration = $iDuration;
|
||||
$sSLTName = $oSLT->GetName();
|
||||
}
|
||||
}
|
||||
if ($iMinDuration == PHP_INT_MAX)
|
||||
{
|
||||
$iDeadline = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Store $sSLTName to keep track of which SLT has been used
|
||||
$iDeadline = $iMinDuration;
|
||||
}
|
||||
}
|
||||
return $iDeadline;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the TTO of a ticket - null if the class 'SLT' does not exist
|
||||
*/
|
||||
class ResponseTicketTTO extends ResponseTicketSLT implements iMetricComputer
|
||||
{
|
||||
public static function GetDescription()
|
||||
{
|
||||
return "Time to own a ticket";
|
||||
}
|
||||
|
||||
public function ComputeMetric($oObject)
|
||||
{
|
||||
$iRes = $this->ComputeSLT($oObject, 'TTO');
|
||||
return $iRes;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the TTR of a ticket - null if the class 'SLT' does not exist
|
||||
*/
|
||||
class ResponseTicketTTR extends ResponseTicketSLT implements iMetricComputer
|
||||
{
|
||||
public static function GetDescription()
|
||||
{
|
||||
return "Time to resolve a ticket";
|
||||
}
|
||||
|
||||
public function ComputeMetric($oObject)
|
||||
{
|
||||
$iRes = $this->ComputeSLT($oObject, 'TTR');
|
||||
return $iRes;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class _Ticket extends cmdbAbstractObject
|
||||
{
|
||||
|
||||
public function UpdateImpactedItems()
|
||||
{
|
||||
require_once(APPROOT.'core/displayablegraph.class.inc.php');
|
||||
$oContactsSet = $this->Get('contacts_list');
|
||||
$oCIsSet = $this->Get('functionalcis_list');
|
||||
|
||||
$aCIsToImpactCode = array();
|
||||
$aSources = array();
|
||||
$aExcluded = array();
|
||||
|
||||
$oCIsSet->Rewind();
|
||||
while ($oLink = $oCIsSet->Fetch())
|
||||
{
|
||||
$iKey = $oLink->Get('functionalci_id');
|
||||
$aCIsToImpactCode[$iKey] = $oLink->Get('impact_code');
|
||||
if ($oLink->Get('impact_code') == 'manual')
|
||||
{
|
||||
$oObj = MetaModel::GetObject('FunctionalCI', $iKey);
|
||||
$aSources[$iKey] = $oObj;
|
||||
}
|
||||
else if ($oLink->Get('impact_code') == 'not_impacted')
|
||||
{
|
||||
$oObj = MetaModel::GetObject('FunctionalCI', $iKey);
|
||||
$aExcluded[$iKey] = $oObj;
|
||||
}
|
||||
}
|
||||
|
||||
$aContactsToRoleCode = array();
|
||||
$oContactsSet->Rewind();
|
||||
while ($oLink = $oContactsSet->Fetch())
|
||||
{
|
||||
$iKey = $oLink->Get('contact_id');
|
||||
$aContactsToRoleCode[$iKey] = $oLink->Get('role_code');
|
||||
if ($oLink->Get('role_code') == 'do_not_notify')
|
||||
{
|
||||
$oObj = MetaModel::GetObject('Contact', $iKey);
|
||||
$aExcluded[$iKey] = $oObj;
|
||||
}
|
||||
}
|
||||
|
||||
$oNewCIsSet = DBObjectSet::FromScratch('lnkFunctionalCIToTicket');
|
||||
foreach($aCIsToImpactCode as $iKey => $sImpactCode)
|
||||
{
|
||||
if ($sImpactCode != 'computed')
|
||||
{
|
||||
$oNewLink = new lnkFunctionalCIToTicket();
|
||||
$oNewLink->Set('functionalci_id', $iKey);
|
||||
$oNewLink->Set('impact_code', $sImpactCode);
|
||||
$oNewCIsSet->AddObject($oNewLink);
|
||||
}
|
||||
}
|
||||
|
||||
$oNewContactsSet = DBObjectSet::FromScratch('lnkContactToTicket');
|
||||
foreach($aContactsToRoleCode as $iKey => $sImpactCode)
|
||||
{
|
||||
if ($sImpactCode != 'computed')
|
||||
{
|
||||
$oNewLink = new lnkContactToTicket();
|
||||
$oNewLink->Set('contact_id', $iKey);
|
||||
$oNewLink->Set('role_code', $sImpactCode);
|
||||
$oNewContactsSet->AddObject($oNewLink);
|
||||
}
|
||||
}
|
||||
|
||||
$sContextKey = 'itop-tickets/relation_context/'.get_class($this).'/impacts/down';
|
||||
$aContextDefs = DisplayableGraph::GetContextDefinitions($sContextKey, true, array('this' => $this));
|
||||
$aDefaultContexts = array();
|
||||
foreach($aContextDefs as $sKey => $aDefinition)
|
||||
{
|
||||
// Add the default context queries to the computation
|
||||
if (array_key_exists('default', $aDefinition) && ($aDefinition['default'] == 'yes'))
|
||||
{
|
||||
$aDefaultContexts[] = $aDefinition['oql'];
|
||||
}
|
||||
}
|
||||
// Merge the directly impacted items with the "new" ones added by the "context" queries
|
||||
$aGraphObjects = array();
|
||||
$oRawGraph = MetaModel::GetRelatedObjectsDown('impacts', $aSources, 10, true /* bEnableRedundancy */, $aExcluded);
|
||||
$oIterator = new RelationTypeIterator($oRawGraph, 'Node');
|
||||
foreach ($oIterator as $oNode)
|
||||
{
|
||||
// Any object node reached AND different from a source will do
|
||||
if ( ($oNode instanceof RelationObjectNode) && ($oNode->GetProperty('is_reached')) && (!$oNode->GetProperty('source')) )
|
||||
{
|
||||
$oObj = $oNode->GetProperty('object');
|
||||
$iKey = $oObj->GetKey();
|
||||
$aGraphObjects[get_class($oObj).'::'.$iKey] = $oNode->GetProperty('object');
|
||||
}
|
||||
}
|
||||
|
||||
if (count($aDefaultContexts) > 0)
|
||||
{
|
||||
$oAnnotatedGraph = MetaModel::GetRelatedObjectsDown('impacts', $aSources, 10, true /* bEnableRedundancy */, $aExcluded, $aDefaultContexts);
|
||||
$oIterator = new RelationTypeIterator($oAnnotatedGraph, 'Node');
|
||||
foreach ($oIterator as $oNode)
|
||||
{
|
||||
// Only pick the nodes which are NOT impacted by a context root cause, and merge them in the list
|
||||
if ( ($oNode instanceof RelationObjectNode) && ($oNode->GetProperty('is_reached')) && (!$oNode->GetProperty('source')) && ($oNode->GetProperty('context_root_causes', null) == null) )
|
||||
{
|
||||
$oObj = $oNode->GetProperty('object');
|
||||
$iKey = $oObj->GetKey();
|
||||
$aGraphObjects[get_class($oObj).'::'.$iKey] = $oNode->GetProperty('object');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($aGraphObjects as $oObj)
|
||||
{
|
||||
$iKey = $oObj->GetKey();
|
||||
$sRootClass = MetaModel::GetRootClass(get_class($oObj));
|
||||
switch ($sRootClass)
|
||||
{
|
||||
case 'FunctionalCI':
|
||||
// Only FunctionalCIs which are not already linked to the ticket
|
||||
if (!array_key_exists($iKey, $aCIsToImpactCode) || ($aCIsToImpactCode[$iKey] != 'not_impacted'))
|
||||
{
|
||||
$oNewLink = new lnkFunctionalCIToTicket();
|
||||
$oNewLink->Set('functionalci_id', $iKey);
|
||||
$oNewLink->Set('impact_code', 'computed');
|
||||
$oNewCIsSet->AddObject($oNewLink);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Contact':
|
||||
// Only link Contacts which are not already linked to the ticket
|
||||
if (!array_key_exists($iKey, $aContactsToRoleCode) || ($aContactsToRoleCode[$iKey] != 'do_not_notify'))
|
||||
{
|
||||
$oNewLink = new lnkContactToTicket();
|
||||
$oNewLink->Set('contact_id', $iKey);
|
||||
$oNewLink->Set('role_code', 'computed');
|
||||
$oNewContactsSet->AddObject($oNewLink);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->Set('functionalcis_list', $oNewCIsSet);
|
||||
$this->Set('contacts_list', $oNewContactsSet);
|
||||
}
|
||||
|
||||
public function DisplayBareRelations(WebPage $oPage, $bEditMode = false)
|
||||
{
|
||||
parent::DisplayBareRelations($oPage, $bEditMode);
|
||||
// Display the impact analysis for tickets not in 'closed' or 'resolved' status... and not in edition
|
||||
if ((!$bEditMode) && (!in_array($this->Get('status'), array('resolved', 'closed'))))
|
||||
{
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/fraphael.js');
|
||||
$oPage->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/jquery.contextMenu.css');
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.contextMenu.js');
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/simple_graph.js');
|
||||
$oPage->AddAjaxTab(Dict::S('Ticket:ImpactAnalysis'), utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=ticket_impact&class='.get_class($this).'&id='.$this->GetKey(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
<?php
|
||||
// Copyright (C) 2010-2017 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* Base class for computing TTO or TTR on a ticket
|
||||
*/
|
||||
class ResponseTicketSLT
|
||||
{
|
||||
/**
|
||||
* Determines the shortest SLT, for this ticket, for the given metric. Returns null is no SLT was found
|
||||
* @param string $sMetric Type of metric 'TTO', 'TTR', etc as defined in the SLT class
|
||||
* @return hash Array with 'SLT' => name of the SLT selected, 'value' => duration in seconds of the SLT metric, null if no SLT applies to this ticket
|
||||
*/
|
||||
protected static function ComputeSLT($oTicket, $sMetric = 'TTO')
|
||||
{
|
||||
$iDeadline = null;
|
||||
if (MetaModel::IsValidClass('SLT'))
|
||||
{
|
||||
$sType=get_class($oTicket);
|
||||
if ($sType == 'Incident')
|
||||
{
|
||||
$sRequestType = 'incident';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sRequestType = $oTicket->Get('request_type');
|
||||
}
|
||||
|
||||
$aArgs = $oTicket->ToArgs();
|
||||
$aArgs['metric'] = $sMetric;
|
||||
$aArgs['request_type'] = $sRequestType;
|
||||
|
||||
//echo "<p>Managing:".$sMetric."-".$this->Get('request_type')."-".$this->Get('importance')."</p>\n";
|
||||
$oSLTSet = new DBObjectSet(DBObjectSearch::FromOQL(RESPONSE_TICKET_SLT_QUERY),
|
||||
array(),
|
||||
$aArgs
|
||||
);
|
||||
|
||||
$iMinDuration = PHP_INT_MAX;
|
||||
$sSLTName = '';
|
||||
|
||||
while($oSLT = $oSLTSet->Fetch())
|
||||
{
|
||||
$iDuration = (int)$oSLT->Get('value');
|
||||
$sUnit = $oSLT->Get('unit');
|
||||
switch($sUnit)
|
||||
{
|
||||
case 'days':
|
||||
$iDuration = $iDuration * 24; // 24 hours in 1 days
|
||||
// Fall though
|
||||
|
||||
case 'hours':
|
||||
$iDuration = $iDuration * 60; // 60 minutes in 1 hour
|
||||
// Fall though
|
||||
|
||||
case 'minutes':
|
||||
$iDuration = $iDuration * 60;
|
||||
}
|
||||
if ($iDuration < $iMinDuration)
|
||||
{
|
||||
$iMinDuration = $iDuration;
|
||||
$sSLTName = $oSLT->GetName();
|
||||
}
|
||||
}
|
||||
if ($iMinDuration == PHP_INT_MAX)
|
||||
{
|
||||
$iDeadline = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Store $sSLTName to keep track of which SLT has been used
|
||||
$iDeadline = $iMinDuration;
|
||||
}
|
||||
}
|
||||
return $iDeadline;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the TTO of a ticket - null if the class 'SLT' does not exist
|
||||
*/
|
||||
class ResponseTicketTTO extends ResponseTicketSLT implements iMetricComputer
|
||||
{
|
||||
public static function GetDescription()
|
||||
{
|
||||
return "Time to own a ticket";
|
||||
}
|
||||
|
||||
public function ComputeMetric($oObject)
|
||||
{
|
||||
$iRes = $this->ComputeSLT($oObject, 'TTO');
|
||||
return $iRes;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the TTR of a ticket - null if the class 'SLT' does not exist
|
||||
*/
|
||||
class ResponseTicketTTR extends ResponseTicketSLT implements iMetricComputer
|
||||
{
|
||||
public static function GetDescription()
|
||||
{
|
||||
return "Time to resolve a ticket";
|
||||
}
|
||||
|
||||
public function ComputeMetric($oObject)
|
||||
{
|
||||
$iRes = $this->ComputeSLT($oObject, 'TTR');
|
||||
return $iRes;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class _Ticket extends cmdbAbstractObject
|
||||
{
|
||||
|
||||
public function UpdateImpactedItems()
|
||||
{
|
||||
require_once(APPROOT.'core/displayablegraph.class.inc.php');
|
||||
|
||||
/** @var ormLinkSet $oContactsSet */
|
||||
$oContactsSet = $this->Get('contacts_list');
|
||||
/** @var ormLinkSet $oCIsSet */
|
||||
$oCIsSet = $this->Get('functionalcis_list');
|
||||
|
||||
$aCIsToImpactCode = array();
|
||||
$aSources = array();
|
||||
$aExcluded = array();
|
||||
foreach ($oCIsSet as $oLink)
|
||||
{
|
||||
$iKey = $oLink->Get('functionalci_id');
|
||||
$aCIsToImpactCode[$iKey] = array('link' => $oLink->GetKey(), 'code' => $oLink->Get('impact_code'));
|
||||
if ($oLink->Get('impact_code') == 'manual')
|
||||
{
|
||||
$oObj = MetaModel::GetObject('FunctionalCI', $iKey);
|
||||
$aSources[$iKey] = $oObj;
|
||||
}
|
||||
else if ($oLink->Get('impact_code') == 'not_impacted')
|
||||
{
|
||||
$oObj = MetaModel::GetObject('FunctionalCI', $iKey);
|
||||
$aExcluded[] = $oObj;
|
||||
}
|
||||
}
|
||||
|
||||
$aContactsToRoleCode = array();
|
||||
foreach ($oContactsSet as $oLink)
|
||||
{
|
||||
$iKey = $oLink->Get('contact_id');
|
||||
$aContactsToRoleCode[$iKey] = array('link' => $oLink->GetKey(), 'code' => $oLink->Get('role_code'));
|
||||
if ($oLink->Get('role_code') == 'do_not_notify')
|
||||
{
|
||||
$oObj = MetaModel::GetObject('Contact', $iKey);
|
||||
$aExcluded[] = $oObj;
|
||||
}
|
||||
}
|
||||
|
||||
$sContextKey = 'itop-tickets/relation_context/'.get_class($this).'/impacts/down';
|
||||
$aContextDefs = DisplayableGraph::GetContextDefinitions($sContextKey, true, array('this' => $this));
|
||||
$aDefaultContexts = array();
|
||||
foreach($aContextDefs as $sKey => $aDefinition)
|
||||
{
|
||||
// Add the default context queries to the computation
|
||||
if (array_key_exists('default', $aDefinition) && ($aDefinition['default'] == 'yes'))
|
||||
{
|
||||
$aDefaultContexts[] = $aDefinition['oql'];
|
||||
}
|
||||
}
|
||||
// Merge the directly impacted items with the "new" ones added by the "context" queries
|
||||
$aGraphObjects = array();
|
||||
$oRawGraph = MetaModel::GetRelatedObjectsDown('impacts', $aSources, 10, true /* bEnableRedundancy */, $aExcluded);
|
||||
$oIterator = new RelationTypeIterator($oRawGraph, 'Node');
|
||||
foreach ($oIterator as $oNode)
|
||||
{
|
||||
// Any object node reached AND different from a source will do
|
||||
if ( ($oNode instanceof RelationObjectNode) && ($oNode->GetProperty('is_reached')) && (!$oNode->GetProperty('source')) )
|
||||
{
|
||||
$this->StoreComputedObject($aGraphObjects, $oNode->GetProperty('object'));
|
||||
}
|
||||
}
|
||||
if (count($aDefaultContexts) > 0)
|
||||
{
|
||||
$oAnnotatedGraph = MetaModel::GetRelatedObjectsDown('impacts', $aSources, 10, true /* bEnableRedundancy */, $aExcluded, $aDefaultContexts);
|
||||
$oIterator = new RelationTypeIterator($oAnnotatedGraph, 'Node');
|
||||
foreach ($oIterator as $oNode)
|
||||
{
|
||||
// Only pick the nodes which are NOT impacted by a context root cause, and merge them in the list
|
||||
if (($oNode instanceof RelationObjectNode) && ($oNode->GetProperty('is_reached')) && (!$oNode->GetProperty('source')) && ($oNode->GetProperty('context_root_causes', null) == null))
|
||||
{
|
||||
$this->StoreComputedObject($aGraphObjects, $oNode->GetProperty('object'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove unnecessary "computed" CIs and Contacts
|
||||
foreach($aCIsToImpactCode as $iKey => $aCode)
|
||||
{
|
||||
if (($aCode['code'] == 'computed') && (!isset($aGraphObjects['FunctionalCI']) || (!array_key_exists($iKey, $aGraphObjects['FunctionalCI']))))
|
||||
{
|
||||
$oCIsSet->RemoveItem($aCode['link']);
|
||||
}
|
||||
}
|
||||
foreach($aContactsToRoleCode as $iKey => $aCode)
|
||||
{
|
||||
if (($aCode['code'] == 'computed') && (!isset($aGraphObjects['Contact']) || (!array_key_exists($iKey, $aGraphObjects['Contact']))))
|
||||
{
|
||||
$oContactsSet->RemoveItem($aCode['link']);
|
||||
}
|
||||
}
|
||||
|
||||
// Add new nodes
|
||||
foreach ($aGraphObjects as $sRootClass => $aObjects)
|
||||
{
|
||||
switch ($sRootClass)
|
||||
{
|
||||
case 'FunctionalCI':
|
||||
// Only FunctionalCIs which are not already linked to the ticket
|
||||
foreach($aObjects as $iKey => $oObj)
|
||||
{
|
||||
if (!array_key_exists($iKey, $aCIsToImpactCode))
|
||||
{
|
||||
$oNewLink = new lnkFunctionalCIToTicket();
|
||||
$oNewLink->Set('functionalci_id', $iKey);
|
||||
$oNewLink->Set('impact_code', 'computed');
|
||||
$oCIsSet->AddItem($oNewLink);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Contact':
|
||||
// Only link Contacts which are not already linked to the ticket
|
||||
foreach($aObjects as $iKey => $oObj)
|
||||
{
|
||||
if (!array_key_exists($iKey, $aContactsToRoleCode))
|
||||
{
|
||||
$oNewLink = new lnkContactToTicket();
|
||||
$oNewLink->Set('contact_id', $iKey);
|
||||
$oNewLink->Set('role_code', 'computed');
|
||||
$oContactsSet->AddItem($oNewLink);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->Set('functionalcis_list', $oCIsSet);
|
||||
$this->Set('contacts_list', $oContactsSet);
|
||||
}
|
||||
|
||||
private function StoreComputedObject(&$aGraphObjects, $oObj)
|
||||
{
|
||||
$iKey = $oObj->GetKey();
|
||||
$sRootClass = MetaModel::GetRootClass(get_class($oObj));
|
||||
$aGraphObjects[$sRootClass][$iKey] = $oObj;
|
||||
}
|
||||
|
||||
public function DisplayBareRelations(WebPage $oPage, $bEditMode = false)
|
||||
{
|
||||
parent::DisplayBareRelations($oPage, $bEditMode);
|
||||
// Display the impact analysis for tickets not in 'closed' or 'resolved' status... and not in edition
|
||||
if ((!$bEditMode) && (!in_array($this->Get('status'), array('resolved', 'closed'))))
|
||||
{
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/fraphael.js');
|
||||
$oPage->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/jquery.contextMenu.css');
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.contextMenu.js');
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/simple_graph.js');
|
||||
$oPage->AddAjaxTab(Dict::S('Ticket:ImpactAnalysis'), utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=ticket_impact&class='.get_class($this).'&id='.$this->GetKey(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
Reference in New Issue
Block a user