if ($oLnk->Get($sImpactAttCode) == 'manual') { $aSourceObjects[] = MetaModel::GetObject($sRemoteClass, $oLnk->Get($sExtKeyToRemote)); } if ($oLnk->Get($sImpactAttCode) == 'not_impacted') { $aExcludedObjects[] = MetaModel::GetObject($sRemoteClass, $oLnk->Get($sExtKeyToRemote)); } } // Compute the graph $iMaxRecursionDepth = MetaModel::GetConfig()->Get('relations_max_depth', 20); if ($sDirection == 'up') { $oRelGraph = MetaModel::GetRelatedObjectsUp($sRelation, $aSourceObjects, $iMaxRecursionDepth); } else { $oRelGraph = MetaModel::GetRelatedObjectsDown($sRelation, $aSourceObjects, $iMaxRecursionDepth, $aExcludedObjects); } $aResults = $oRelGraph->GetObjectsByClass(); $oGraph = DisplayableGraph::FromRelationGraph($oRelGraph, $iGroupingThreshold, $sDirection == 'down'); $sContextKey = 'itop-tickets/relation_context/' . $sClass . '/' . $sRelation . '/' . $sDirection; $oAppContext = new ApplicationContext(); $oGraph->Display($oPage, $aResults, $sRelation, $oAppContext, $aExcludedObjects, $sClass, $iId, $sContextKey, array('this' => $oTicket)); break; case 'export_build': try { $token = utils::ReadParam('token', null); $aResult = array('code' => 'error', 'percentage' => 100, 'message' => "Export not found for token: '{$token}'"); // Fallback error, just in case $data = ''; if ($token === null) { $sFormat = utils::ReadParam('format', ''); $sExpression = utils::ReadParam('expression', null, false, 'raw_data'); $iQueryId = utils::ReadParam('query', null); if ($sExpression === null) {
/** * Build a DisplayableGraph from a RelationGraph * @param RelationGraph $oGraph * @param number $iGroupingThreshold * @param string $bDirectionDown * @return DisplayableGraph */ public static function FromRelationGraph(RelationGraph $oGraph, $iGroupingThreshold = 20, $bDirectionDown = true) { $oNewGraph = new DisplayableGraph(); $oNewGraph->bDirectionDown = $bDirectionDown; $iPreviousTimeLimit = ini_get('max_execution_time'); $iLoopTimeLimit = MetaModel::GetConfig()->Get('max_execution_time_per_loop'); $oNodesIter = new RelationTypeIterator($oGraph, 'Node'); foreach ($oNodesIter as $oNode) { set_time_limit($iLoopTimeLimit); switch (get_class($oNode)) { case 'RelationObjectNode': $oNewNode = new DisplayableNode($oNewGraph, $oNode->GetId(), 0, 0); $oObj = $oNode->GetProperty('object'); $sClass = get_class($oObj); if ($oNode->GetProperty('source')) { if (!array_key_exists($sClass, $oNewGraph->aSourceObjects)) { $oNewGraph->aSourceObjects[$sClass] = array(); } $oNewGraph->aSourceObjects[$sClass][] = $oObj->GetKey(); $oNewNode->SetProperty('source', true); } if ($oNode->GetProperty('sink')) { if (!array_key_exists($sClass, $oNewGraph->aSinkObjects)) { $oNewGraph->aSinkObjects[$sClass] = array(); } $oNewGraph->aSinkObjects[$sClass][] = $oObj->GetKey(); $oNewNode->SetProperty('sink', true); } $oNewNode->SetProperty('object', $oObj); $oNewNode->SetProperty('icon_url', $oObj->GetIcon(false)); $oNewNode->SetProperty('label', $oObj->GetRawName()); $oNewNode->SetProperty('is_reached', $bDirectionDown ? $oNode->GetProperty('is_reached') : true); // When going "up" is_reached does not matter $oNewNode->SetProperty('is_reached_allowed', $oNode->GetProperty('is_reached_allowed')); $oNewNode->SetProperty('context_root_causes', $oNode->GetProperty('context_root_causes')); break; default: $oNewNode = new DisplayableRedundancyNode($oNewGraph, $oNode->GetId(), 0, 0); $iNbReached = is_null($oNode->GetProperty('is_reached_count')) ? 0 : $oNode->GetProperty('is_reached_count'); $oNewNode->SetProperty('label', $iNbReached . "/" . ($oNode->GetProperty('min_up') + $oNode->GetProperty('threshold'))); $oNewNode->SetProperty('min_up', $oNode->GetProperty('min_up')); $oNewNode->SetProperty('threshold', $oNode->GetProperty('threshold')); $oNewNode->SetProperty('is_reached_count', $iNbReached); $oNewNode->SetProperty('is_reached', true); } } $oEdgesIter = new RelationTypeIterator($oGraph, 'Edge'); foreach ($oEdgesIter as $oEdge) { set_time_limit($iLoopTimeLimit); $oSourceNode = $oNewGraph->GetNode($oEdge->GetSourceNode()->GetId()); $oSinkNode = $oNewGraph->GetNode($oEdge->GetSinkNode()->GetId()); $oNewEdge = new DisplayableEdge($oNewGraph, $oEdge->GetId(), $oSourceNode, $oSinkNode); } // Remove duplicate edges between two nodes $oEdgesIter = new RelationTypeIterator($oNewGraph, 'Edge'); $aEdgeKeys = array(); foreach ($oEdgesIter as $oEdge) { set_time_limit($iLoopTimeLimit); $sSourceId = $oEdge->GetSourceNode()->GetId(); $sSinkId = $oEdge->GetSinkNode()->GetId(); if ($sSourceId == $sSinkId) { // Remove self referring edges $oNewGraph->_RemoveEdge($oEdge); } else { $sKey = $sSourceId . '//' . $sSinkId; if (array_key_exists($sKey, $aEdgeKeys)) { // Remove duplicate edges $oNewGraph->_RemoveEdge($oEdge); } else { $aEdgeKeys[$sKey] = true; } } } $oNodesIter = new RelationTypeIterator($oNewGraph, 'Node'); foreach ($oNodesIter as $oNode) { set_time_limit($iLoopTimeLimit); if ($oNode->GetProperty('source')) { $oNode->GroupSimilarNeighbours($oNewGraph, $iGroupingThreshold, true, true); } } // Groups numbering $oIterator = new RelationTypeIterator($oNewGraph, 'Node'); $iGroupIdx = 0; foreach ($oIterator as $oNode) { set_time_limit($iLoopTimeLimit); if ($oNode instanceof DisplayableGroupNode) { if ($oNode->GetObjectCount() == 0) { // Remove emtpry groups $oNewGraph->_RemoveNode($oNode); } else { $aGroups[] = $oNode->GetObjects(); $oNode->SetProperty('group_index', $iGroupIdx); $iGroupIdx++; } } } // Remove duplicate edges between two nodes $oEdgesIter = new RelationTypeIterator($oNewGraph, 'Edge'); $aEdgeKeys = array(); foreach ($oEdgesIter as $oEdge) { set_time_limit($iLoopTimeLimit); $sSourceId = $oEdge->GetSourceNode()->GetId(); $sSinkId = $oEdge->GetSinkNode()->GetId(); if ($sSourceId == $sSinkId) { // Remove self referring edges $oNewGraph->_RemoveEdge($oEdge); } else { $sKey = $sSourceId . '//' . $sSinkId; if (array_key_exists($sKey, $aEdgeKeys)) { // Remove duplicate edges $oNewGraph->_RemoveEdge($oEdge); } else { $aEdgeKeys[$sKey] = true; } } } set_time_limit($iPreviousTimeLimit); return $oNewGraph; }
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); } } $oContactsSet = DBObjectSet::FromScratch('lnkContactToTicket'); $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, $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(); $sRootClass = MetaModel::GetRootClass(get_class($oObj)); $aGraphObjects[get_class($oObj) . '::' . $iKey] = $oNode->GetProperty('object'); } } if (count($aDefaultContexts) > 0) { $oAnnotatedGraph = MetaModel::GetRelatedObjectsDown('impacts', $aSources, 10, true, $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(); $sRootClass = MetaModel::GetRootClass(get_class($oObj)); $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 link 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) || $aCIsToImpactCode[$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); }