Example #1
0
         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);
 }