Ejemplo n.º 1
0
 public function Process($iTimeLimit)
 {
     $sDateLimit = date('Y-m-d H:i:s', time() - 24 * 3600);
     // Every BulkExportResult older than one day will be deleted
     $sOQL = "SELECT BulkExportResult WHERE created < '{$sDateLimit}'";
     $iProcessed = 0;
     while (time() < $iTimeLimit) {
         // Next one ?
         $oSet = new CMDBObjectSet(DBObjectSearch::FromOQL($sOQL), array('created' => true), array(), null, 1);
         $oSet->OptimizeColumnLoad(array('temp_file_path'));
         $oResult = $oSet->Fetch();
         if (is_null($oResult)) {
             // Nothing to be done
             break;
         }
         $iProcessed++;
         @unlink($oResult->Get('temp_file_path'));
         $oResult->DBDelete();
     }
     return "Cleaned {$iProcessed} old export results(s).";
 }
Ejemplo n.º 2
0
 public function Process($iTimeLimit)
 {
     $sNow = date('Y-m-d H:i:s');
     // Criteria: planned, and expected to occur... ASAP or in the past
     $sOQL = "SELECT AsyncTask WHERE (status = 'planned') AND (ISNULL(planned) OR (planned < '{$sNow}'))";
     $iProcessed = 0;
     while (time() < $iTimeLimit) {
         // Next one ?
         $oSet = new CMDBObjectSet(DBObjectSearch::FromOQL($sOQL), array('created' => true), array(), null, 1);
         $oTask = $oSet->Fetch();
         if (is_null($oTask)) {
             // Nothing to be done
             break;
         }
         $iProcessed++;
         if ($oTask->Process()) {
             $oTask->DBDelete();
         }
     }
     return "processed {$iProcessed} tasks";
 }
Ejemplo n.º 3
0
 $oP->add("<table>\n");
 $oP->add("<tr>\n");
 $oP->add("<th><img src=\"../images/minus.gif\"></th><th class=\"alignLeft\">" . Dict::S('UI:Audit:HeaderAuditRule') . "</th><th>" . Dict::S('UI:Audit:HeaderNbObjects') . "</th><th>" . Dict::S('UI:Audit:HeaderNbErrors') . "</th><th>" . Dict::S('UI:Audit:PercentageOk') . "</th>\n");
 $oP->add("</tr>\n");
 while ($oAuditCategory = $oCategoriesSet->fetch()) {
     try {
         $oDefinitionFilter = DBObjectSearch::FromOQL($oAuditCategory->Get('definition_set'));
         FilterByContext($oDefinitionFilter, $oAppContext);
         $aObjectsWithErrors = array();
         if (!empty($currentOrganization)) {
             if (MetaModel::IsValidFilterCode($oDefinitionFilter->GetClass(), 'org_id')) {
                 $oDefinitionFilter->AddCondition('org_id', $currentOrganization, '=');
             }
         }
         $aResults = array();
         $oDefinitionSet = new CMDBObjectSet($oDefinitionFilter);
         $iCount = $oDefinitionSet->Count();
         $oRulesFilter = new DBObjectSearch('AuditRule');
         $oRulesFilter->AddCondition('category_id', $oAuditCategory->GetKey(), '=');
         $oRulesSet = new DBObjectSet($oRulesFilter);
         while ($oAuditRule = $oRulesSet->fetch()) {
             $aRow = array();
             $aRow['description'] = $oAuditRule->GetName();
             if ($iCount == 0) {
                 // nothing to check, really !
                 $aRow['nb_errors'] = "<a href=\"audit.php?operation=errors&category=" . $oAuditCategory->GetKey() . "&rule=" . $oAuditRule->GetKey() . "\">0</a>";
                 $aRow['percent_ok'] = '100.00';
                 $aRow['class'] = GetReportColor($iCount, 0);
             } else {
                 try {
                     $oFilter = GetRuleResultFilter($oAuditRule->GetKey(), $oDefinitionFilter, $oAppContext);
Ejemplo n.º 4
0
 protected function DoExecute()
 {
     foreach (MetaModel::GetClasses() as $sClassName) {
         if (MetaModel::HasTable($sClassName)) {
             continue;
         }
         $oNobody = MetaModel::GetObject($sClassName, 123);
         $oBaby = new $sClassName();
         $oFilter = new DBObjectSearch($sClassName);
         // Challenge reversibility of OQL / filter object
         //
         $sExpr1 = $oFilter->ToOQL();
         $oNewFilter = DBObjectSearch::FromOQL($sExpr1);
         $sExpr2 = $oNewFilter->ToOQL();
         if ($sExpr1 != $sExpr2) {
             $this->ReportError("Found two different OQL expression out of the (same?) filter: <em>{$sExpr1}</em> != <em>{$sExpr2}</em>");
         }
         // Use the filter (perform the query)
         //
         $oSet = new CMDBObjectSet($oFilter);
         $this->ReportSuccess('Found ' . $oSet->Count() . " objects of class {$sClassName}");
     }
     return true;
 }
    /**
     * Display a form for modifying several objects at once
     * The form will be submitted to the current page, with the specified additional values	 
     */
    public static function DisplayBulkModifyForm($oP, $sClass, $aSelectedObj, $sCustomOperation, $sCancelUrl, $aExcludeAttributes = array(), $aContextData = array())
    {
        if (count($aSelectedObj) > 0) {
            $iAllowedCount = count($aSelectedObj);
            $sSelectedObj = implode(',', $aSelectedObj);
            $sOQL = "SELECT {$sClass} WHERE id IN (" . $sSelectedObj . ")";
            $oSet = new CMDBObjectSet(DBObjectSearch::FromOQL($sOQL));
            // Compute the distribution of the values for each field to determine which of the "scalar" fields are homogenous
            $aList = MetaModel::ListAttributeDefs($sClass);
            $aValues = array();
            foreach ($aList as $sAttCode => $oAttDef) {
                if ($oAttDef->IsScalar()) {
                    $aValues[$sAttCode] = array();
                }
            }
            while ($oObj = $oSet->Fetch()) {
                foreach ($aList as $sAttCode => $oAttDef) {
                    if ($oAttDef->IsScalar() && $oAttDef->IsWritable()) {
                        $currValue = $oObj->Get($sAttCode);
                        if ($oAttDef instanceof AttributeCaseLog) {
                            $currValue = ' ';
                            // Don't put an empty string, in case the field would be considered as mandatory...
                        }
                        if (is_object($currValue)) {
                            continue;
                        }
                        // Skip non scalar values...
                        if (!array_key_exists($currValue, $aValues[$sAttCode])) {
                            $aValues[$sAttCode][$currValue] = array('count' => 1, 'display' => $oObj->GetAsHTML($sAttCode));
                        } else {
                            $aValues[$sAttCode][$currValue]['count']++;
                        }
                    }
                }
            }
            // Now create an object that has values for the homogenous values only
            $oDummyObj = new $sClass();
            // @@ What if the class is abstract ?
            $aComments = array();
            function MyComparison($a, $b)
            {
                if ($a['count'] == $b['count']) {
                    return 0;
                }
                return $a['count'] > $b['count'] ? -1 : 1;
            }
            $iFormId = cmdbAbstractObject::GetNextFormId();
            // Identifier that prefixes all the form fields
            $sReadyScript = '';
            $aDependsOn = array();
            $sFormPrefix = '2_';
            foreach ($aList as $sAttCode => $oAttDef) {
                $aPrerequisites = MetaModel::GetPrerequisiteAttributes($sClass, $sAttCode);
                // List of attributes that are needed for the current one
                if (count($aPrerequisites) > 0) {
                    // When 'enabling' a field, all its prerequisites must be enabled too
                    $sFieldList = "['{$sFormPrefix}" . implode("','{$sFormPrefix}", $aPrerequisites) . "']";
                    $oP->add_ready_script("\$('#enable_{$sFormPrefix}{$sAttCode}').bind('change', function(evt, sFormId) { return PropagateCheckBox( this.checked, {$sFieldList}, true); } );\n");
                }
                $aDependents = MetaModel::GetDependentAttributes($sClass, $sAttCode);
                // List of attributes that are needed for the current one
                if (count($aDependents) > 0) {
                    // When 'disabling' a field, all its dependent fields must be disabled too
                    $sFieldList = "['{$sFormPrefix}" . implode("','{$sFormPrefix}", $aDependents) . "']";
                    $oP->add_ready_script("\$('#enable_{$sFormPrefix}{$sAttCode}').bind('change', function(evt, sFormId) { return PropagateCheckBox( this.checked, {$sFieldList}, false); } );\n");
                }
                if ($oAttDef->IsScalar() && $oAttDef->IsWritable()) {
                    if ($oAttDef->GetEditClass() == 'One Way Password') {
                        $sTip = "Unknown values";
                        $sReadyScript .= "\$('#multi_values_{$sAttCode}').qtip( { content: '{$sTip}', show: 'mouseover', hide: 'mouseout', style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );";
                        $oDummyObj->Set($sAttCode, null);
                        $aComments[$sAttCode] = '<input type="checkbox" id="enable_' . $iFormId . '_' . $sAttCode . '" onClick="ToogleField(this.checked, \'' . $iFormId . '_' . $sAttCode . '\')"/>';
                        $aComments[$sAttCode] .= '<div class="multi_values" id="multi_values_' . $sAttCode . '"> ? </div>';
                        $sReadyScript .= 'ToogleField(false, \'' . $iFormId . '_' . $sAttCode . '\');' . "\n";
                    } else {
                        $iCount = count($aValues[$sAttCode]);
                        if ($iCount == 1) {
                            // Homogenous value
                            reset($aValues[$sAttCode]);
                            $aKeys = array_keys($aValues[$sAttCode]);
                            $currValue = $aKeys[0];
                            // The only value is the first key
                            //echo "<p>current value for $sAttCode : $currValue</p>";
                            $oDummyObj->Set($sAttCode, $currValue);
                            $aComments[$sAttCode] = '';
                            if ($sAttCode != MetaModel::GetStateAttributeCode($sClass)) {
                                $aComments[$sAttCode] .= '<input type="checkbox" checked id="enable_' . $iFormId . '_' . $sAttCode . '"  onClick="ToogleField(this.checked, \'' . $iFormId . '_' . $sAttCode . '\')"/>';
                            }
                            $aComments[$sAttCode] .= '<div class="mono_value">1</div>';
                        } else {
                            // Non-homogenous value
                            $aMultiValues = $aValues[$sAttCode];
                            uasort($aMultiValues, 'MyComparison');
                            $iMaxCount = 5;
                            $sTip = "<p><b>" . Dict::Format('UI:BulkModify_Count_DistinctValues', $iCount) . "</b><ul>";
                            $index = 0;
                            foreach ($aMultiValues as $sCurrValue => $aVal) {
                                $sDisplayValue = empty($aVal['display']) ? '<i>' . Dict::S('Enum:Undefined') . '</i>' : str_replace(array("\n", "\r"), " ", $aVal['display']);
                                $sTip .= "<li>" . Dict::Format('UI:BulkModify:Value_Exists_N_Times', $sDisplayValue, $aVal['count']) . "</li>";
                                $index++;
                                if ($iMaxCount == $index) {
                                    $sTip .= "<li>" . Dict::Format('UI:BulkModify:N_MoreValues', count($aMultiValues) - $iMaxCount) . "</li>";
                                    break;
                                }
                            }
                            $sTip .= "</ul></p>";
                            $sTip = addslashes($sTip);
                            $sReadyScript .= "\$('#multi_values_{$sAttCode}').qtip( { content: '{$sTip}', show: 'mouseover', hide: 'mouseout', style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );";
                            $oDummyObj->Set($sAttCode, null);
                            $aComments[$sAttCode] = '';
                            if ($sAttCode != MetaModel::GetStateAttributeCode($sClass)) {
                                $aComments[$sAttCode] .= '<input type="checkbox" id="enable_' . $iFormId . '_' . $sAttCode . '" onClick="ToogleField(this.checked, \'' . $iFormId . '_' . $sAttCode . '\')"/>';
                            }
                            $aComments[$sAttCode] .= '<div class="multi_values" id="multi_values_' . $sAttCode . '">' . $iCount . '</div>';
                        }
                        $sReadyScript .= 'ToogleField(' . ($iCount == 1 ? 'true' : 'false') . ', \'' . $iFormId . '_' . $sAttCode . '\');' . "\n";
                    }
                }
            }
            $sStateAttCode = MetaModel::GetStateAttributeCode($sClass);
            if ($sStateAttCode != '' && $oDummyObj->GetState() == '') {
                // Hmmm, it's not gonna work like this ! Set a default value for the "state"
                // Maybe we should use the "state" that is the most common among the objects...
                $aMultiValues = $aValues[$sStateAttCode];
                uasort($aMultiValues, 'MyComparison');
                foreach ($aMultiValues as $sCurrValue => $aVal) {
                    $oDummyObj->Set($sStateAttCode, $sCurrValue);
                    break;
                }
                //$oStateAtt = MetaModel::GetAttributeDef($sClass, $sStateAttCode);
                //$oDummyObj->Set($sStateAttCode, $oStateAtt->GetDefaultValue());
            }
            $oP->add("<div class=\"page_header\">\n");
            $oP->add("<h1>" . $oDummyObj->GetIcon() . "&nbsp;" . Dict::Format('UI:Modify_M_ObjectsOf_Class_OutOf_N', $iAllowedCount, $sClass, $iAllowedCount) . "</h1>\n");
            $oP->add("</div>\n");
            $oP->add("<div class=\"wizContainer\">\n");
            $sDisableFields = json_encode($aExcludeAttributes);
            $aParams = array('fieldsComments' => $aComments, 'noRelations' => true, 'custom_operation' => $sCustomOperation, 'custom_button' => Dict::S('UI:Button:PreviewModifications'), 'selectObj' => $sSelectedObj, 'preview_mode' => true, 'disabled_fields' => $sDisableFields, 'disable_plugins' => true);
            $aParams = $aParams + $aContextData;
            // merge keeping associations
            $oDummyObj->DisplayModifyForm($oP, $aParams);
            $oP->add("</div>\n");
            $oP->add_ready_script($sReadyScript);
            $oP->add_ready_script(<<<EOF
\$('.wizContainer button.cancel').unbind('click');
\$('.wizContainer button.cancel').click( function() { window.location.href = '{$sCancelUrl}'; } );
EOF
);
        } else {
            $oP->p("No object selected !, nothing to do");
        }
    }
Ejemplo n.º 6
0
     $sName = utils::ReadParam('q', '');
     $iMaxCount = utils::ReadParam('max', 30);
     $iCount = 0;
     $oFilter = new DBObjectSearch($sClass);
     $oFilter->AddCondition($sAttCode, $sName, 'Begins with');
     //$oFilter->AddCondition('org_id', $sOrg, '=');
     $oSet = new CMDBObjectSet($oFilter, array($sAttCode => true));
     while ($iCount < $iMaxCount && ($oObj = $oSet->fetch())) {
         $oPage->add($oObj->GetAsHTML($sAttCode) . "|" . $oObj->GetKey() . "\n");
         $iCount++;
     }
     break;
 case 'combo_options':
     $oPage->SetContentType('text/html');
     $oFilter = CMDBSearchFilter::FromOQL($sFilter);
     $oSet = new CMDBObjectSet($oFilter);
     while ($oObj = $oSet->fetch()) {
         $oPage->add('<option title="Here is more information..." value="' . $oObj->GetKey() . '">' . $oObj->GetName() . '</option>');
     }
     break;
 case 'display_document':
     $id = utils::ReadParam('id', '');
     $sField = utils::ReadParam('field', '');
     if (!empty($sClass) && !empty($id) && !empty($sField)) {
         DownloadDocument($oPage, $sClass, $id, $sField, 'inline');
     }
     break;
 case 'download_document':
     $id = utils::ReadParam('id', '');
     $sField = utils::ReadParam('field', '');
     $iCacheSec = (int) utils::ReadParam('cache', 0);
Ejemplo n.º 7
0
 /**
  * Renders the "Actions" popup menu for the given set of objects
  * 
  * Note that the menu links containing (or ending) with a hash (#) will have their fragment
  * part (whatever is after the hash) dynamically replaced (by javascript) when the menu is
  * displayed, to correspond to the current hash/fragment in the page. This allows modifying
  * an object in with the same tab active by default as the tab that was active when selecting
  * the "Modify..." action.
  */
 public function GetRenderContent(WebPage $oPage, $aExtraParams = array(), $sId)
 {
     if ($this->m_sStyle == 'popup') {
         $this->m_sStyle = 'list';
     }
     $sHtml = '';
     $oAppContext = new ApplicationContext();
     $sContext = $oAppContext->GetForLink();
     if (!empty($sContext)) {
         $sContext = '&' . $sContext;
     }
     $sClass = $this->m_oFilter->GetClass();
     $oReflectionClass = new ReflectionClass($sClass);
     $oSet = new CMDBObjectSet($this->m_oFilter);
     $sFilter = $this->m_oFilter->serialize();
     $sFilterDesc = $this->m_oFilter->ToOql(true);
     $aActions = array();
     $sUIPage = cmdbAbstractObject::ComputeStandardUIPage($sClass);
     $sRootUrl = utils::GetAbsoluteUrlAppRoot();
     // 1:n links, populate the target object as a default value when creating a new linked object
     if (isset($aExtraParams['target_attr'])) {
         $aExtraParams['default'][$aExtraParams['target_attr']] = $aExtraParams['object_id'];
     }
     $sDefault = '';
     if (!empty($aExtraParams['default'])) {
         foreach ($aExtraParams['default'] as $sKey => $sValue) {
             $sDefault .= "&default[{$sKey}]={$sValue}";
         }
     }
     $bIsCreationAllowed = UserRights::IsActionAllowed($sClass, UR_ACTION_CREATE) == UR_ALLOWED_YES && $oReflectionClass->IsSubclassOf('cmdbAbstractObject');
     switch ($oSet->Count()) {
         case 0:
             // No object in the set, the only possible action is "new"
             if ($bIsCreationAllowed) {
                 $aActions['UI:Menu:New'] = array('label' => Dict::S('UI:Menu:New'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=new&class={$sClass}{$sContext}{$sDefault}");
             }
             break;
         case 1:
             $oObj = $oSet->Fetch();
             $id = $oObj->GetKey();
             $bLocked = false;
             if (MetaModel::GetConfig()->Get('concurrent_lock_enabled')) {
                 $aLockInfo = iTopOwnershipLock::IsLocked(get_class($oObj), $id);
                 if ($aLockInfo['locked']) {
                     $bLocked = true;
                     //$this->AddMenuSeparator($aActions);
                     //$aActions['concurrent_lock_unlock'] = array ('label' => Dict::S('UI:Menu:ReleaseConcurrentLock'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=kill_lock&class=$sClass&id=$id{$sContext}");
                 }
             }
             $bRawModifiedAllowed = UserRights::IsActionAllowed($sClass, UR_ACTION_MODIFY, $oSet) == UR_ALLOWED_YES && $oReflectionClass->IsSubclassOf('cmdbAbstractObject');
             $bIsModifyAllowed = !$bLocked && $bRawModifiedAllowed;
             $bIsDeleteAllowed = !$bLocked && UserRights::IsActionAllowed($sClass, UR_ACTION_DELETE, $oSet);
             // Just one object in the set, possible actions are "new / clone / modify and delete"
             if (!isset($aExtraParams['link_attr'])) {
                 if ($bIsModifyAllowed) {
                     $aActions['UI:Menu:Modify'] = array('label' => Dict::S('UI:Menu:Modify'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=modify&class={$sClass}&id={$id}{$sContext}#");
                 }
                 if ($bIsCreationAllowed) {
                     $aActions['UI:Menu:New'] = array('label' => Dict::S('UI:Menu:New'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=new&class={$sClass}{$sContext}{$sDefault}");
                 }
                 if ($bIsDeleteAllowed) {
                     $aActions['UI:Menu:Delete'] = array('label' => Dict::S('UI:Menu:Delete'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=delete&class={$sClass}&id={$id}{$sContext}");
                 }
                 // Transitions / Stimuli
                 if (!$bLocked) {
                     $aTransitions = $oObj->EnumTransitions();
                     if (count($aTransitions)) {
                         $this->AddMenuSeparator($aActions);
                         $aStimuli = Metamodel::EnumStimuli(get_class($oObj));
                         foreach ($aTransitions as $sStimulusCode => $aTransitionDef) {
                             $iActionAllowed = get_class($aStimuli[$sStimulusCode]) == 'StimulusUserAction' ? UserRights::IsStimulusAllowed($sClass, $sStimulusCode, $oSet) : UR_ALLOWED_NO;
                             switch ($iActionAllowed) {
                                 case UR_ALLOWED_YES:
                                     $aActions[$sStimulusCode] = array('label' => $aStimuli[$sStimulusCode]->GetLabel(), 'url' => "{$sRootUrl}pages/UI.php?operation=stimulus&stimulus={$sStimulusCode}&class={$sClass}&id={$id}{$sContext}");
                                     break;
                                 default:
                                     // Do nothing
                             }
                         }
                     }
                 }
                 // Relations...
                 $aRelations = MetaModel::EnumRelationsEx($sClass);
                 if (count($aRelations)) {
                     $this->AddMenuSeparator($aActions);
                     foreach ($aRelations as $sRelationCode => $aRelationInfo) {
                         if (array_key_exists('down', $aRelationInfo)) {
                             $aActions[$sRelationCode . '_down'] = array('label' => $aRelationInfo['down'], 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=swf_navigator&relation={$sRelationCode}&direction=down&class={$sClass}&id={$id}{$sContext}");
                         }
                         if (array_key_exists('up', $aRelationInfo)) {
                             $aActions[$sRelationCode . '_up'] = array('label' => $aRelationInfo['up'], 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=swf_navigator&relation={$sRelationCode}&direction=up&class={$sClass}&id={$id}{$sContext}");
                         }
                     }
                 }
                 if ($bLocked && $bRawModifiedAllowed) {
                     // Add a special menu to kill the lock, but only to allowed users who can also modify this object
                     $aAllowedProfiles = MetaModel::GetConfig()->Get('concurrent_lock_override_profiles');
                     $bCanKill = false;
                     $oUser = UserRights::GetUserObject();
                     $aUserProfiles = array();
                     if (!is_null($oUser)) {
                         $oProfileSet = $oUser->Get('profile_list');
                         while ($oProfile = $oProfileSet->Fetch()) {
                             $aUserProfiles[$oProfile->Get('profile')] = true;
                         }
                     }
                     foreach ($aAllowedProfiles as $sProfile) {
                         if (array_key_exists($sProfile, $aUserProfiles)) {
                             $bCanKill = true;
                             break;
                         }
                     }
                     if ($bCanKill) {
                         $this->AddMenuSeparator($aActions);
                         $aActions['concurrent_lock_unlock'] = array('label' => Dict::S('UI:Menu:KillConcurrentLock'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=kill_lock&class={$sClass}&id={$id}{$sContext}");
                     }
                 }
                 /*
                 $this->AddMenuSeparator($aActions);
                 // Static menus: Email this page & CSV Export
                 $sUrl = ApplicationContext::MakeObjectUrl($sClass, $id);
                 $aActions['UI:Menu:EMail'] = array ('label' => Dict::S('UI:Menu:EMail'), 'url' => "mailto:?subject=".urlencode($oObj->GetRawName())."&body=".urlencode($sUrl));
                 $aActions['UI:Menu:CSVExport'] = array ('label' => Dict::S('UI:Menu:CSVExport'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=search&filter=".urlencode($sFilter)."&format=csv{$sContext}");
                 // The style tells us whether the menu is displayed on a list of one object, or on the details of the given object 
                 if ($this->m_sStyle == 'list')
                 {
                 	// Actions specific to the list
                 	$sOQL = addslashes($sFilterDesc);
                 	$aActions['UI:Menu:AddToDashboard'] = array ('label' => Dict::S('UI:Menu:AddToDashboard'), 'url' => "#", 'onclick' => "return DashletCreationDlg('$sOQL')");
                 }
                 */
             }
             $this->AddMenuSeparator($aActions);
             foreach (MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance) {
                 $oSet->Rewind();
                 foreach ($oExtensionInstance->EnumAllowedActions($oSet) as $sLabel => $sUrl) {
                     $aActions[$sLabel] = array('label' => $sLabel, 'url' => $sUrl);
                 }
             }
             break;
         default:
             // Check rights
             // New / Modify
             $bIsModifyAllowed = UserRights::IsActionAllowed($sClass, UR_ACTION_MODIFY, $oSet) && $oReflectionClass->IsSubclassOf('cmdbAbstractObject');
             $bIsBulkModifyAllowed = !MetaModel::IsAbstract($sClass) && UserRights::IsActionAllowed($sClass, UR_ACTION_BULK_MODIFY, $oSet) && $oReflectionClass->IsSubclassOf('cmdbAbstractObject');
             $bIsBulkDeleteAllowed = UserRights::IsActionAllowed($sClass, UR_ACTION_BULK_DELETE, $oSet);
             if (isset($aExtraParams['link_attr'])) {
                 $id = $aExtraParams['object_id'];
                 $sTargetAttr = $aExtraParams['target_attr'];
                 $oAttDef = MetaModel::GetAttributeDef($sClass, $sTargetAttr);
                 $sTargetClass = $oAttDef->GetTargetClass();
                 $bIsDeleteAllowed = UserRights::IsActionAllowed($sClass, UR_ACTION_DELETE, $oSet);
                 if ($bIsModifyAllowed) {
                     $aActions['UI:Menu:Add'] = array('label' => Dict::S('UI:Menu:Add'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=modify_links&class={$sClass}&link_attr=" . $aExtraParams['link_attr'] . "&target_class={$sTargetClass}&id={$id}&addObjects=true{$sContext}");
                 }
                 if ($bIsBulkModifyAllowed) {
                     $aActions['UI:Menu:Manage'] = array('label' => Dict::S('UI:Menu:Manage'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=modify_links&class={$sClass}&link_attr=" . $aExtraParams['link_attr'] . "&target_class={$sTargetClass}&id={$id}{$sContext}");
                 }
                 //if ($bIsBulkDeleteAllowed) { $aActions[] = array ('label' => 'Remove All...', 'url' => "#"); }
             } else {
                 // many objects in the set, possible actions are: new / modify all / delete all
                 if ($bIsCreationAllowed) {
                     $aActions['UI:Menu:New'] = array('label' => Dict::S('UI:Menu:New'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=new&class={$sClass}{$sContext}{$sDefault}");
                 }
                 if ($bIsBulkModifyAllowed) {
                     $aActions['UI:Menu:ModifyAll'] = array('label' => Dict::S('UI:Menu:ModifyAll'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=select_for_modify_all&class={$sClass}&filter=" . urlencode($sFilter) . "{$sContext}");
                 }
                 if ($bIsBulkDeleteAllowed) {
                     $aActions['UI:Menu:BulkDelete'] = array('label' => Dict::S('UI:Menu:BulkDelete'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=select_for_deletion&filter=" . urlencode($sFilter) . "{$sContext}");
                 }
                 // Stimuli
                 $aStates = MetaModel::EnumStates($sClass);
                 // Do not perform time consuming computations if there are too may objects in the list
                 $iLimit = MetaModel::GetConfig()->Get('complex_actions_limit');
                 if (count($aStates) > 0 && ($iLimit == 0 || $oSet->Count() < $iLimit)) {
                     // Life cycle actions may be available... if all objects are in the same state
                     //
                     // Group by <state>
                     $oGroupByExp = new FieldExpression(MetaModel::GetStateAttributeCode($sClass), $this->m_oFilter->GetClassAlias());
                     $aGroupBy = array('__state__' => $oGroupByExp);
                     $aQueryParams = array();
                     if (isset($aExtraParams['query_params'])) {
                         $aQueryParams = $aExtraParams['query_params'];
                     }
                     $sSql = $this->m_oFilter->MakeGroupByQuery($aQueryParams, $aGroupBy);
                     $aRes = CMDBSource::QueryToArray($sSql);
                     if (count($aRes) == 1) {
                         // All objects are in the same state...
                         $sState = $aRes[0]['__state__'];
                         $aTransitions = Metamodel::EnumTransitions($sClass, $sState);
                         if (count($aTransitions)) {
                             $this->AddMenuSeparator($aActions);
                             $aStimuli = Metamodel::EnumStimuli($sClass);
                             foreach ($aTransitions as $sStimulusCode => $aTransitionDef) {
                                 $oSet->Rewind();
                                 // As soon as the user rights implementation will browse the object set,
                                 // then we might consider using OptimizeColumnLoad() here
                                 $iActionAllowed = UserRights::IsStimulusAllowed($sClass, $sStimulusCode, $oSet);
                                 $iActionAllowed = get_class($aStimuli[$sStimulusCode]) == 'StimulusUserAction' ? $iActionAllowed : UR_ALLOWED_NO;
                                 switch ($iActionAllowed) {
                                     case UR_ALLOWED_YES:
                                     case UR_ALLOWED_DEPENDS:
                                         $aActions[$sStimulusCode] = array('label' => $aStimuli[$sStimulusCode]->GetLabel(), 'url' => "{$sRootUrl}pages/UI.php?operation=select_bulk_stimulus&stimulus={$sStimulusCode}&state={$sState}&class={$sClass}&filter=" . urlencode($sFilter) . "{$sContext}");
                                         break;
                                     default:
                                         // Do nothing
                                 }
                             }
                         }
                     }
                 }
                 /*
                 $this->AddMenuSeparator($aActions);
                 $sUrl = utils::GetAbsoluteUrlAppRoot();
                 $aActions['UI:Menu:EMail'] = array ('label' => Dict::S('UI:Menu:EMail'), 'url' => "mailto:?subject=$sFilterDesc&body=".urlencode("{$sUrl}pages/$sUIPage?operation=search&filter=".urlencode($sFilter)."{$sContext}"));
                 $aActions['UI:Menu:CSVExport'] = array ('label' => Dict::S('UI:Menu:CSVExport'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=search&filter=".urlencode($sFilter)."&format=csv{$sContext}");
                 $sOQL = addslashes($sFilterDesc);
                 $aActions['UI:Menu:AddToDashboard'] = array ('label' => Dict::S('UI:Menu:AddToDashboard'), 'url' => "#", 'onclick' => "return DashletCreationDlg('$sOQL')");
                 */
             }
     }
     $this->AddMenuSeparator($aActions);
     foreach (MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance) {
         $oSet->Rewind();
         foreach ($oExtensionInstance->EnumAllowedActions($oSet) as $sLabel => $data) {
             if (is_array($data)) {
                 // New plugins can provide javascript handlers via the 'onclick' property
                 //TODO: enable extension of different menus by checking the 'target' property ??
                 $aActions[$sLabel] = array('label' => $sLabel, 'url' => isset($data['url']) ? $data['url'] : '#', 'onclick' => isset($data['onclick']) ? $data['onclick'] : '');
             } else {
                 // Backward compatibility with old plugins
                 $aActions[$sLabel] = array('label' => $sLabel, 'url' => $data);
             }
         }
     }
     // New extensions based on iPopupMenuItem interface
     switch ($this->m_sStyle) {
         case 'list':
             $oSet->Rewind();
             $param = $oSet;
             $iMenuId = iPopupMenuExtension::MENU_OBJLIST_ACTIONS;
             break;
         case 'details':
             $oSet->Rewind();
             $param = $oSet->Fetch();
             $iMenuId = iPopupMenuExtension::MENU_OBJDETAILS_ACTIONS;
             break;
     }
     utils::GetPopupMenuItems($oPage, $iMenuId, $param, $aActions);
     $aFavoriteActions = array();
     $aCallSpec = array($sClass, 'GetShortcutActions');
     if (is_callable($aCallSpec)) {
         $aShortcutActions = call_user_func($aCallSpec, $sClass);
         foreach ($aActions as $key => $aAction) {
             if (in_array($key, $aShortcutActions)) {
                 $aFavoriteActions[] = $aAction;
                 unset($aActions[$key]);
             }
         }
     } else {
         $aShortcutActions = array();
     }
     if (count($aFavoriteActions) > 0) {
         $sHtml .= "<div class=\"itop_popup actions_menu\"><ul>\n<li>" . Dict::S('UI:Menu:OtherActions') . "\n<ul>\n";
     } else {
         $sHtml .= "<div class=\"itop_popup actions_menu\"><ul>\n<li>" . Dict::S('UI:Menu:Actions') . "\n<ul>\n";
     }
     $sHtml .= $oPage->RenderPopupMenuItems($aActions, $aFavoriteActions);
     static $bPopupScript = false;
     if (!$bPopupScript) {
         // Output this once per page...
         $oPage->add_ready_script("\$(\"div.itop_popup>ul\").popupmenu();\n");
         $bPopupScript = true;
     }
     return $sHtml;
 }
Ejemplo n.º 8
0
 public function GetSiloSelectionForm()
 {
     // List of visible Organizations
     $iCount = 0;
     $oSet = null;
     if (MetaModel::IsValidClass('Organization')) {
         // Display the list of *favorite* organizations... but keeping in mind what is the real number of organizations
         $aFavoriteOrgs = appUserPreferences::GetPref('favorite_orgs', null);
         $oSearchFilter = new DBObjectSearch('Organization');
         $oSearchFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', true);
         $oSet = new CMDBObjectSet($oSearchFilter);
         $iCount = $oSet->Count();
         // total number of existing Orgs
         // Now get the list of Orgs to be displayed in the menu
         $oSearchFilter = DBObjectSearch::FromOQL(ApplicationMenu::GetFavoriteSiloQuery());
         $oSearchFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', true);
         if (!empty($aFavoriteOrgs)) {
             $oSearchFilter->AddCondition('id', $aFavoriteOrgs, 'IN');
         }
         $oSet = new CMDBObjectSet($oSearchFilter);
         // List of favorite orgs
     }
     switch ($iCount) {
         case 0:
             // No such dimension/silo => nothing to select
             $sHtml = '<div id="SiloSelection"><!-- nothing to select --></div>';
             break;
         case 1:
             // Only one possible choice... no selection, but display the value
             $oOrg = $oSet->Fetch();
             $sHtml = '<div id="SiloSelection">' . $oOrg->GetName() . '</div>';
             $sHtml .= '';
             break;
         default:
             $sHtml = '';
             $oAppContext = new ApplicationContext();
             $iCurrentOrganization = $oAppContext->GetCurrentValue('org_id');
             $sHtml = '<div id="SiloSelection">';
             $sHtml .= '<form style="display:inline" action="' . utils::GetAbsoluteUrlAppRoot() . 'pages/UI.php">';
             //<select class="org_combo" name="c[org_id]" title="Pick an organization" onChange="this.form.submit();">';
             $sFavoriteOrgs = '';
             $oWidget = new UIExtKeyWidget('Organization', 'org_id', '', true);
             $sHtml .= $oWidget->Display($this, 50, false, '', $oSet, $iCurrentOrganization, 'org_id', false, 'c[org_id]', '', array('iFieldSize' => 20, 'iMinChars' => MetaModel::GetConfig()->Get('min_autocomplete_chars'), 'sDefaultValue' => Dict::S('UI:AllOrganizations')), null, 'select', false);
             $this->add_ready_script('$("#org_id").bind("extkeychange", function() { $("#SiloSelection form").submit(); } )');
             $this->add_ready_script("\$('#label_org_id').click( function() { \$(this).val(''); \$('#org_id').val(''); return true; } );\n");
             // Add other dimensions/context information to this form
             $oAppContext->Reset('org_id');
             // org_id is handled above and we want to be able to change it here !
             $oAppContext->Reset('menu');
             // don't pass the menu, since a menu may expect more parameters
             $sHtml .= $oAppContext->GetForForm();
             // Pass what remains, if anything...
             $sHtml .= '</form>';
             $sHtml .= '</div>';
     }
     return $sHtml;
 }
 function DisplayBareRelations(WebPage $oPage, $bEditMode = false)
 {
     parent::DisplayBareRelations($oPage, $bEditMode);
     if (!$bEditMode) {
         $oPage->SetCurrentTab(Dict::S('Class:Subnet/Tab:IPUsage'));
         $bit_ip = ip2long($this->Get('ip'));
         $bit_mask = ip2long($this->Get('ip_mask'));
         $iIPMin = sprintf('%u', $bit_ip & $bit_mask | 1);
         // exclude the first one: identifies the subnet itself
         $iIPMax = sprintf('%u', ($bit_ip | ~$bit_mask) & 0xfffffffe);
         // exclude the last one : broadcast address
         $sIPMin = long2ip($iIPMin);
         $sIPMax = long2ip($iIPMax);
         $oPage->p(Dict::Format('Class:Subnet/Tab:IPUsage-explain', $sIPMin, $sIPMax));
         $oIfFilter = DBObjectSearch::FromOQL("SELECT IPInterface AS if WHERE INET_ATON(if.ipaddress) >= INET_ATON('{$sIPMin}') AND INET_ATON(if.ipaddress) <= INET_ATON('{$sIPMax}')");
         $oIfSet = new CMDBObjectSet($oIfFilter);
         $oBlock = new DisplayBlock($oIfFilter, 'list', false);
         $oBlock->Display($oPage, 'nwif', array('menu' => false));
         $iCountUsed = $oIfSet->Count();
         $iCountRange = $iIPMax - $iIPMin;
         // On 32-bit systems the substraction will be computed using floats for values greater than PHP_MAX_INT;
         $iFreeCount = $iCountRange - $iCountUsed;
         $oPage->SetCurrentTab(Dict::S('Class:Subnet/Tab:FreeIPs'));
         $oPage->p(Dict::Format('Class:Subnet/Tab:FreeIPs-count', $iFreeCount));
         $oPage->p(Dict::S('Class:Subnet/Tab:FreeIPs-explain'));
         $aUsedIPs = $oIfSet->GetColumnAsArray('ipaddress', false);
         $iAnIP = $iIPMin;
         $iFound = 0;
         while ($iFound < min($iFreeCount, 10) && $iAnIP <= $iIPMax) {
             $sAnIP = long2ip($iAnIP);
             if (!in_array($sAnIP, $aUsedIPs)) {
                 $iFound++;
                 $oPage->p($sAnIP);
             } else {
             }
             $iAnIP++;
         }
     }
 }
 /**
  * Search for objects to be linked to the current object (i.e "remote" objects)
  * @param WebPage $oP The page used for the output (usually an AjaxWebPage)
  * @param string $sRemoteClass Name of the "remote" class to perform the search on, must be a derived class of m_sRemoteClass
  * @param Array $aAlreadyLinkedIds List of IDs of objects of "remote" class already linked, to be filtered out of the search
  */
 public function SearchObjectsToAdd(WebPage $oP, $sRemoteClass = '', $aAlreadyLinkedIds = array())
 {
     if ($sRemoteClass != '') {
         // assert(MetaModel::IsParentClass($this->m_sRemoteClass, $sRemoteClass));
         $oFilter = new DBObjectSearch($sRemoteClass);
     } else {
         // No remote class specified use the one defined in the linkedset
         $oFilter = new DBObjectSearch($this->m_sRemoteClass);
     }
     if (!$this->m_bDuplicatesAllowed && count($aAlreadyLinkedIds) > 0) {
         // Positive IDs correspond to existing link records
         // negative IDs correspond to "remote" objects to be linked
         $aLinkIds = array();
         $aRemoteObjIds = array();
         foreach ($aAlreadyLinkedIds as $iId) {
             if ($iId > 0) {
                 $aLinkIds[] = $iId;
             } else {
                 $aRemoteObjIds[] = -$iId;
             }
         }
         if (count($aLinkIds) > 0) {
             // Search for the links to find to which "remote" object they are linked
             $oLinkFilter = new DBObjectSearch($this->m_sLinkedClass);
             $oLinkFilter->AddCondition('id', $aLinkIds, 'IN');
             $oLinkSet = new CMDBObjectSet($oLinkFilter);
             while ($oLink = $oLinkSet->Fetch()) {
                 $aRemoteObjIds[] = $oLink->Get($this->m_sExtKeyToRemote);
             }
         }
         $oFilter->AddCondition('id', $aRemoteObjIds, 'NOTIN');
     }
     $oSet = new CMDBObjectSet($oFilter);
     $oBlock = new DisplayBlock($oFilter, 'list', false);
     $oBlock->Display($oP, "ResultsToAdd_{$this->m_sAttCode}", array('menu' => false, 'cssCount' => '#count_' . $this->m_sAttCode . $this->m_sNameSuffix, 'selection_mode' => true, 'table_id' => 'add_' . $this->m_sAttCode));
     // Don't display the 'Actions' menu on the results
 }
 /**
  * Search for an organization with the given code in the database
  *
  * @param string $Id The organization Id to look for
  * @return cmdbOrganization the organization if it exists, null otherwise
  */
 protected function GetOrganization($sId)
 {
     $oOrg = null;
     $oFilter = new CMDBSearchFilter('bizOrganization');
     $oFilter->AddCondition('id', $sId, '=');
     $oSet = new CMDBObjectSet($oFilter);
     if ($oSet->Count() > 0) {
         $oOrg = $oSet->Fetch();
         // Let's take the first one found
     }
     return $oOrg;
 }
Ejemplo n.º 12
0
 function test_linkedset()
 {
     echo "<h4>Linked set attributes</h4>\n";
     $oObj = MetaModel::GetObject("cmdbContact", 18);
     echo "<h5>Current workshops</h5>\n";
     $oSetWorkshopsCurr = $oObj->Get("myworkshops");
     $this->show_list($oSetWorkshopsCurr);
     echo "<h5>Setting workshops</h5>\n";
     $oNewLink = new cmdbLiens();
     $oNewLink->Set('toworkshop', 2);
     $oNewLink->Set('function', 'mafonctioooon');
     $oNewLink->Set('a1', 'tralala1');
     $oNewLink->Set('a2', 'F7M');
     $oSetWorkshops = CMDBObjectSet::FromArray("cmdbLiens", array($oNewLink));
     $oObj->Set("myworkshops", $oSetWorkshops);
     $this->show_list($oSetWorkshops);
     echo "<h5>New workshops</h5>\n";
     $oSetWorkshopsCurr = $oObj->Get("myworkshops");
     $this->show_list($oSetWorkshopsCurr);
     $oMyChange = MetaModel::NewObject("CMDBChange");
     $oMyChange->Set("date", time());
     $oMyChange->Set("userinfo", "test_linkedset / Made by robot #" . rand(1, 100));
     $iChangeId = $oMyChange->DBInsert();
     $oObj->DBUpdateTracked($oMyChange);
     $oObj = MetaModel::GetObject("cmdbContact", 18);
     echo "<h5>After the write</h5>\n";
     $oSetWorkshopsCurr = $oObj->Get("myworkshops");
     $this->show_list($oSetWorkshopsCurr);
 }
Ejemplo n.º 13
0
function DisplayNavigatorGroupTab($oP, $aGroups, $sRelation, $oObj)
{
    if (count($aGroups) > 0) {
        $oP->SetCurrentTab(Dict::S('UI:RelationGroups'));
        $oP->add("<div id=\"impacted_groupss\" style=\"width:100%;background-color:#fff;padding:10px;\">");
        $iBlock = 1;
        // Zero is not a valid blockid
        foreach ($aGroups as $idx => $aObjects) {
            $sListClass = get_class(current($aObjects));
            $oSet = CMDBObjectSet::FromArray($sListClass, $aObjects);
            $oP->add("<h1>" . Dict::Format('UI:RelationGroupNumber_N', 1 + $idx) . "</h1>\n");
            $oP->add("<div id=\"relation_group_{$idx}\" class=\"page_header\">\n");
            $oP->add("<h2>" . MetaModel::GetClassIcon($sListClass) . "&nbsp;<span class=\"hilite\">" . Dict::Format('UI:Search:Count_ObjectsOf_Class_Found', count($aObjects), Metamodel::GetName($sListClass)) . "</h2>\n");
            $oP->add("</div>\n");
            $oBlock = DisplayBlock::FromObjectSet($oSet, 'list');
            $oBlock->Display($oP, 'group_' . $iBlock++);
            $oP->p('&nbsp;');
            // Some space ?
        }
        $oP->add("</div>");
    }
}
Ejemplo n.º 14
0
 public function Process(CMDBChange $oChange = null)
 {
     // Note: $oChange can be null, in which case the aim is to check what would be done
     // Debug...
     //
     if (false) {
         echo "<pre>\n";
         echo "Attributes:\n";
         print_r($this->m_aAttList);
         echo "ExtKeys:\n";
         print_r($this->m_aExtKeys);
         echo "Reconciliation:\n";
         print_r($this->m_aReconcilKeys);
         echo "Synchro scope:\n";
         print_r($this->m_sSynchroScope);
         echo "Synchro changes:\n";
         print_r($this->m_aOnDisappear);
         //echo "Data:\n";
         //print_r($this->m_aData);
         echo "</pre>\n";
         exit;
     }
     $aResult = array();
     if (!is_null($this->m_sDateFormat) && strlen($this->m_sDateFormat) > 0) {
         // Translate dates from the source data
         //
         foreach ($this->m_aAttList as $sAttCode => $iCol) {
             $oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
             if ($oAttDef instanceof AttributeDateTime) {
                 foreach ($this->m_aData as $iRow => $aRowData) {
                     $sNewDate = utils::StringToTime($this->m_aData[$iRow][$iCol], $this->m_sDateFormat);
                     if ($sNewDate !== false) {
                         // Todo - improve the reporting
                         $this->m_aData[$iRow][$iCol] = $sNewDate;
                     } else {
                         // Leave the cell unchanged
                         $aResult[$iRow]["__STATUS__"] = new RowStatus_Issue(Dict::S('UI:CSVReport-Row-Issue-DateFormat'));
                         $aResult[$iRow][$sAttCode] = new CellStatus_Issue(null, $this->m_aData[$iRow][$iCol], Dict::S('UI:CSVReport-Row-Issue-DateFormat'));
                     }
                 }
             }
         }
     }
     // Compute the results
     //
     if (!is_null($this->m_sSynchroScope)) {
         $aVisited = array();
     }
     $iPreviousTimeLimit = ini_get('max_execution_time');
     $iLoopTimeLimit = MetaModel::GetConfig()->Get('max_execution_time_per_loop');
     foreach ($this->m_aData as $iRow => $aRowData) {
         set_time_limit($iLoopTimeLimit);
         if (isset($aResult[$iRow]["__STATUS__"])) {
             // An issue at the earlier steps - skip the rest
             continue;
         }
         try {
             $oReconciliationFilter = new DBObjectSearch($this->m_sClass);
             $bSkipQuery = false;
             foreach ($this->m_aReconcilKeys as $sAttCode) {
                 $valuecondition = null;
                 if (array_key_exists($sAttCode, $this->m_aExtKeys)) {
                     if ($this->IsNullExternalKeySpec($aRowData, $sAttCode)) {
                         $oExtKey = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
                         if ($oExtKey->IsNullAllowed()) {
                             $valuecondition = $oExtKey->GetNullValue();
                             $aResult[$iRow][$sAttCode] = new CellStatus_Void($oExtKey->GetNullValue());
                         } else {
                             $aResult[$iRow][$sAttCode] = new CellStatus_NullIssue();
                         }
                     } else {
                         // The value has to be found or verified
                         list($sQuery, $aMatches) = $this->ResolveExternalKey($aRowData, $sAttCode, $aResult[$iRow]);
                         if (count($aMatches) == 1) {
                             $oRemoteObj = reset($aMatches);
                             // first item
                             $valuecondition = $oRemoteObj->GetKey();
                             $aResult[$iRow][$sAttCode] = new CellStatus_Void($oRemoteObj->GetKey());
                         } elseif (count($aMatches) == 0) {
                             $aResult[$iRow][$sAttCode] = new CellStatus_SearchIssue();
                         } else {
                             $aResult[$iRow][$sAttCode] = new CellStatus_Ambiguous(null, count($aMatches), $sQuery);
                         }
                     }
                 } else {
                     // The value is given in the data row
                     $iCol = $this->m_aAttList[$sAttCode];
                     if ($sAttCode == 'id') {
                         $valuecondition = $aRowData[$iCol];
                     } else {
                         $oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
                         $valuecondition = $oAttDef->MakeValueFromString($aRowData[$iCol], $this->m_bLocalizedValues);
                     }
                 }
                 if (is_null($valuecondition)) {
                     $bSkipQuery = true;
                 } else {
                     $oReconciliationFilter->AddCondition($sAttCode, $valuecondition, '=');
                 }
             }
             if ($bSkipQuery) {
                 $aResult[$iRow]["__STATUS__"] = new RowStatus_Issue(Dict::S('UI:CSVReport-Row-Issue-Reconciliation'));
             } else {
                 $oReconciliationSet = new CMDBObjectSet($oReconciliationFilter);
                 switch ($oReconciliationSet->Count()) {
                     case 0:
                         $oTargetObj = $this->CreateObject($aResult, $iRow, $aRowData, $oChange);
                         // $aResult[$iRow]["__STATUS__"]=> set in CreateObject
                         $aVisited[] = $oTargetObj->GetKey();
                         break;
                     case 1:
                         $oTargetObj = $oReconciliationSet->Fetch();
                         $this->UpdateObject($aResult, $iRow, $oTargetObj, $aRowData, $oChange);
                         // $aResult[$iRow]["__STATUS__"]=> set in UpdateObject
                         if (!is_null($this->m_sSynchroScope)) {
                             $aVisited[] = $oTargetObj->GetKey();
                         }
                         break;
                     default:
                         // Found several matches, ambiguous
                         $aResult[$iRow]["__STATUS__"] = new RowStatus_Issue(Dict::S('UI:CSVReport-Row-Issue-Ambiguous'));
                         $aResult[$iRow]["id"] = new CellStatus_Ambiguous(0, $oReconciliationSet->Count(), $oReconciliationFilter->ToOql());
                         $aResult[$iRow]["finalclass"] = 'n/a';
                 }
             }
         } catch (Exception $e) {
             $aResult[$iRow]["__STATUS__"] = new RowStatus_Issue(Dict::Format('UI:CSVReport-Row-Issue-Internal', get_class($e), $e->getMessage()));
         }
     }
     if (!is_null($this->m_sSynchroScope)) {
         // Compute the delta between the scope and visited objects
         $oScopeSearch = DBObjectSearch::FromOQL($this->m_sSynchroScope);
         $oScopeSet = new DBObjectSet($oScopeSearch);
         while ($oObj = $oScopeSet->Fetch()) {
             $iObj = $oObj->GetKey();
             if (!in_array($iObj, $aVisited)) {
                 set_time_limit($iLoopTimeLimit);
                 $iRow++;
                 $this->UpdateMissingObject($aResult, $iRow, $oObj, $oChange);
             }
         }
     }
     set_time_limit($iPreviousTimeLimit);
     // Fill in the blanks - the result matrix is expected to be 100% complete
     //
     foreach ($this->m_aData as $iRow => $aRowData) {
         foreach ($this->m_aAttList as $iCol) {
             if (!array_key_exists($iCol, $aResult[$iRow])) {
                 $aResult[$iRow][$iCol] = new CellStatus_Void($aRowData[$iCol]);
             }
         }
         foreach ($this->m_aExtKeys as $sAttCode => $aForeignAtts) {
             if (!array_key_exists($sAttCode, $aResult[$iRow])) {
                 $aResult[$iRow][$sAttCode] = new CellStatus_Void('n/a');
             }
             foreach ($aForeignAtts as $sForeignAttCode => $iCol) {
                 if (!array_key_exists($iCol, $aResult[$iRow])) {
                     // The foreign attribute is one of our reconciliation key
                     $aResult[$iRow][$iCol] = new CellStatus_Void($aRowData[$iCol]);
                 }
             }
         }
     }
     return $aResult;
 }
Ejemplo n.º 15
0
/**
 * Validate the parameters and create the ticket object (based on the page's POSTed parameters)
 * @param WebPage $oP The current web page for the  output
 * @param Organization $oUserOrg The organization of the current user
 * @return void
 */
function DoCreateRequest($oP, $oUserOrg)
{
    $aParameters = $oP->ReadAllParams(PORTAL_ALL_PARAMS . ',template_id');
    $sTransactionId = utils::ReadPostedParam('transaction_id', '');
    if (!utils::IsTransactionValid($sTransactionId)) {
        $oP->add("<h1>" . Dict::S('UI:Error:ObjectAlreadyCreated') . "</h1>\n");
        //ShowOngoingTickets($oP);
        return;
    }
    // Validate the parameters
    // 1) ServiceCategory
    $oSearch = DBObjectSearch::FromOQL(PORTAL_VALIDATE_SERVICECATEGORY_QUERY);
    $oSearch->AllowAllData();
    // In case the user has the rights on his org only
    $oSet = new CMDBObjectSet($oSearch, array(), array('id' => $aParameters['service_id'], 'org_id' => $oUserOrg->GetKey()));
    if ($oSet->Count() != 1) {
        // Invalid service for the current user !
        throw new Exception("Invalid Service Category: id={$aParameters['service_id']} - count: " . $oSet->Count());
    }
    $oServiceCategory = $oSet->Fetch();
    // 2) Service Subcategory
    $oSearch = DBObjectSearch::FromOQL(PORTAL_VALIDATE_SERVICESUBCATEGORY_QUERY);
    RestrictSubcategories($oSearch);
    $oSearch->AllowAllData();
    // In case the user has the rights on his org only
    $oSet = new CMDBObjectSet($oSearch, array(), array('service_id' => $aParameters['service_id'], 'id' => $aParameters['servicesubcategory_id'], 'org_id' => $oUserOrg->GetKey()));
    if ($oSet->Count() != 1) {
        // Invalid subcategory
        throw new Exception("Invalid ServiceSubcategory: id={$aParameters['servicesubcategory_id']} for service category " . $oServiceCategory->GetName() . "({$aParameters['service_id']}) - count: " . $oSet->Count());
    }
    $oServiceSubCategory = $oSet->Fetch();
    $sClass = ComputeClass($oServiceSubCategory->GetKey());
    $oRequest = MetaModel::NewObject($sClass);
    $aAttList = array_merge(explode(',', GetConstant($sClass, 'FORM_ATTRIBUTES')), array('service_id', 'servicesubcategory_id'));
    $oRequest->UpdateObjectFromPostedForm('', $aAttList);
    $oRequest->Set('org_id', $oUserOrg->GetKey());
    $oRequest->Set('caller_id', UserRights::GetContactId());
    if (isset($aParameters['moreinfo'])) {
        // There is a template, insert it into the description
        $sLogAttCode = GetConstant($sClass, 'PUBLIC_LOG');
        $oRequest->Set($sLogAttCode, $aParameters['moreinfo']);
    }
    $sTypeAttCode = GetConstant($sClass, 'TYPE');
    if ($sTypeAttCode != '' && PORTAL_SET_TYPE_FROM != '') {
        $oRequest->Set($sTypeAttCode, $oServiceSubCategory->Get(PORTAL_SET_TYPE_FROM));
    }
    if (MetaModel::IsValidAttCode($sClass, 'origin')) {
        $oRequest->Set('origin', 'portal');
    }
    $oAttPlugin = new AttachmentPlugIn();
    $oAttPlugin->OnFormSubmit($oRequest);
    list($bRes, $aIssues) = $oRequest->CheckToWrite();
    if ($bRes) {
        if (isset($aParameters['template_id'])) {
            $oTemplate = MetaModel::GetObject('Template', $aParameters['template_id']);
            $sLogAttCode = GetConstant($sClass, 'PUBLIC_LOG');
            $oRequest->Set($sLogAttCode, $oTemplate->GetPostedValuesAsText($oRequest) . "\n");
            $oRequest->DBInsertNoReload();
            $oTemplate->RecordExtraDataFromPostedForm($oRequest);
        } else {
            $oRequest->DBInsertNoReload();
        }
        $oP->add("<h1>" . Dict::Format('UI:Title:Object_Of_Class_Created', $oRequest->GetName(), MetaModel::GetName($sClass)) . "</h1>\n");
        //DisplayObject($oP, $oRequest, $oUserOrg);
        ShowOngoingTickets($oP);
    } else {
        RequestCreationForm($oP, $oUserOrg);
        $sIssueDesc = Dict::Format('UI:ObjectCouldNotBeWritten', implode(', ', $aIssues));
        $oP->add_ready_script("alert('" . addslashes($sIssueDesc) . "');");
    }
}
 public function MakeValueFromString($sProposedValue, $bLocalizedValue = false, $sSepItem = null, $sSepAttribute = null, $sSepValue = null, $sAttributeQualifier = null)
 {
     if (is_null($sSepItem) || empty($sSepItem)) {
         $sSepItem = MetaModel::GetConfig()->Get('link_set_item_separator');
     }
     if (is_null($sSepAttribute) || empty($sSepAttribute)) {
         $sSepAttribute = MetaModel::GetConfig()->Get('link_set_attribute_separator');
     }
     if (is_null($sSepValue) || empty($sSepValue)) {
         $sSepValue = MetaModel::GetConfig()->Get('link_set_value_separator');
     }
     if (is_null($sAttributeQualifier) || empty($sAttributeQualifier)) {
         $sAttributeQualifier = MetaModel::GetConfig()->Get('link_set_attribute_qualifier');
     }
     $sTargetClass = $this->Get('linked_class');
     $sInput = str_replace($sSepItem, "\n", $sProposedValue);
     $oCSVParser = new CSVParser($sInput, $sSepAttribute, $sAttributeQualifier);
     $aInput = $oCSVParser->ToArray(0);
     $aLinks = array();
     foreach ($aInput as $aRow) {
         // 1st - get the values, split the extkey->searchkey specs, and eventually get the finalclass value
         $aExtKeys = array();
         $aValues = array();
         foreach ($aRow as $sCell) {
             $iSepPos = strpos($sCell, $sSepValue);
             if ($iSepPos === false) {
                 // Houston...
                 throw new CoreException('Wrong format for link attribute specification', array('value' => $sCell));
             }
             $sAttCode = trim(substr($sCell, 0, $iSepPos));
             $sValue = substr($sCell, $iSepPos + strlen($sSepValue));
             if (preg_match('/^(.+)->(.+)$/', $sAttCode, $aMatches)) {
                 $sKeyAttCode = $aMatches[1];
                 $sRemoteAttCode = $aMatches[2];
                 $aExtKeys[$sKeyAttCode][$sRemoteAttCode] = $sValue;
                 if (!MetaModel::IsValidAttCode($sTargetClass, $sKeyAttCode)) {
                     throw new CoreException('Wrong attribute code for link attribute specification', array('class' => $sTargetClass, 'attcode' => $sKeyAttCode));
                 }
                 $oKeyAttDef = MetaModel::GetAttributeDef($sTargetClass, $sKeyAttCode);
                 $sRemoteClass = $oKeyAttDef->GetTargetClass();
                 if (!MetaModel::IsValidAttCode($sRemoteClass, $sRemoteAttCode)) {
                     throw new CoreException('Wrong attribute code for link attribute specification', array('class' => $sRemoteClass, 'attcode' => $sRemoteAttCode));
                 }
             } else {
                 if (!MetaModel::IsValidAttCode($sTargetClass, $sAttCode)) {
                     throw new CoreException('Wrong attribute code for link attribute specification', array('class' => $sTargetClass, 'attcode' => $sAttCode));
                 }
                 $oAttDef = MetaModel::GetAttributeDef($sTargetClass, $sAttCode);
                 $aValues[$sAttCode] = $oAttDef->MakeValueFromString($sValue, $bLocalizedValue, $sSepItem, $sSepAttribute, $sSepValue, $sAttributeQualifier);
             }
         }
         // 2nd - Instanciate the object and set the value
         if (isset($aValues['finalclass'])) {
             $sLinkClass = $aValues['finalclass'];
             if (!is_subclass_of($sLinkClass, $sTargetClass)) {
                 throw new CoreException('Wrong class for link attribute specification', array('requested_class' => $sLinkClass, 'expected_class' => $sTargetClass));
             }
         } elseif (MetaModel::IsAbstract($sTargetClass)) {
             throw new CoreException('Missing finalclass for link attribute specification');
         } else {
             $sLinkClass = $sTargetClass;
         }
         $oLink = MetaModel::NewObject($sLinkClass);
         foreach ($aValues as $sAttCode => $sValue) {
             $oLink->Set($sAttCode, $sValue);
         }
         // 3rd - Set external keys from search conditions
         foreach ($aExtKeys as $sKeyAttCode => $aReconciliation) {
             $oKeyAttDef = MetaModel::GetAttributeDef($sTargetClass, $sKeyAttCode);
             $sKeyClass = $oKeyAttDef->GetTargetClass();
             $oExtKeyFilter = new DBObjectSearch($sKeyClass);
             $aReconciliationDesc = array();
             foreach ($aReconciliation as $sRemoteAttCode => $sValue) {
                 $oExtKeyFilter->AddCondition($sRemoteAttCode, $sValue, '=');
                 $aReconciliationDesc[] = "{$sRemoteAttCode}={$sValue}";
             }
             $oExtKeySet = new CMDBObjectSet($oExtKeyFilter);
             switch ($oExtKeySet->Count()) {
                 case 0:
                     $sReconciliationDesc = implode(', ', $aReconciliationDesc);
                     throw new CoreException("Found no match", array('ext_key' => $sKeyAttCode, 'reconciliation' => $sReconciliationDesc));
                     break;
                 case 1:
                     $oRemoteObj = $oExtKeySet->Fetch();
                     $oLink->Set($sKeyAttCode, $oRemoteObj->GetKey());
                     break;
                 default:
                     $sReconciliationDesc = implode(', ', $aReconciliationDesc);
                     throw new CoreException("Found several matches", array('ext_key' => $sKeyAttCode, 'reconciliation' => $sReconciliationDesc));
                     // Found several matches, ambiguous
             }
         }
         // Check (roughly) if such a link is valid
         $aErrors = array();
         foreach (MetaModel::ListAttributeDefs($sTargetClass) as $sAttCode => $oAttDef) {
             if ($oAttDef->IsExternalKey()) {
                 if ($oAttDef->GetTargetClass() == $this->GetHostClass() || is_subclass_of($this->GetHostClass(), $oAttDef->GetTargetClass())) {
                     continue;
                     // Don't check the key to self
                 }
             }
             if ($oAttDef->IsWritable() && $oAttDef->IsNull($oLink->Get($sAttCode)) && !$oAttDef->IsNullAllowed()) {
                 $aErrors[] = $sAttCode;
             }
         }
         if (count($aErrors) > 0) {
             throw new CoreException("Missing value for mandatory attribute(s): " . implode(', ', $aErrors));
         }
         $aLinks[] = $oLink;
     }
     $oSet = DBObjectSet::FromArray($sTargetClass, $aLinks);
     return $oSet;
 }
 /**
  * Read the context directly in the PHP parameters (either POST or GET)
  * return nothing
  */
 protected function ReadContext()
 {
     if (!isset(self::$aDefaultValues)) {
         self::$aDefaultValues = array();
         $aContext = utils::ReadParam('c', array(), false, 'context_param');
         foreach ($this->aNames as $sName) {
             $sValue = isset($aContext[$sName]) ? $aContext[$sName] : '';
             // TO DO: check if some of the context parameters are mandatory (or have default values)
             if (!empty($sValue)) {
                 self::$aDefaultValues[$sName] = $sValue;
             }
             // Hmm, there must be a better (more generic) way to handle the case below:
             // When there is only one possible (allowed) organization, the context must be
             // fixed to this org
             if ($sName == 'org_id') {
                 if (MetaModel::IsValidClass('Organization')) {
                     $oSearchFilter = new DBObjectSearch('Organization');
                     $oSearchFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', true);
                     $oSet = new CMDBObjectSet($oSearchFilter);
                     $iCount = $oSet->Count();
                     if ($iCount == 1) {
                         // Only one possible value for org_id, set it in the context
                         $oOrg = $oSet->Fetch();
                         self::$aDefaultValues[$sName] = $oOrg->GetKey();
                     }
                 }
             }
         }
     }
     $this->aValues = self::$aDefaultValues;
 }
    /**
     * Displays the status (SynchroLog) of the datasource in a graphical manner
     * @param $oPage WebPage
     * @return void
     */
    protected function DisplayStatusTab(WebPage $oPage)
    {
        $oPage->SetCurrentTab(Dict::S('Core:SynchroStatus'));
        $sSelectSynchroLog = 'SELECT SynchroLog WHERE sync_source_id = :source_id';
        $oSetSynchroLog = new CMDBObjectSet(DBObjectSearch::FromOQL($sSelectSynchroLog), array('start_date' => false), array('source_id' => $this->GetKey()));
        $oSetSynchroLog->SetLimit(100);
        // Display only the 100 latest runs
        if ($oSetSynchroLog->Count() > 0) {
            $oLastLog = $oSetSynchroLog->Fetch();
            $sStartDate = $oLastLog->Get('start_date');
            $oLastLog->Get('stats_nb_replica_seen');
            $iLastLog = 0;
            $iDSid = $this->GetKey();
            if ($oLastLog->Get('status') == 'running') {
                // Still running !
                $oPage->p('<h2>' . Dict::Format('Core:Synchro:SynchroRunningStartedOn_Date', $sStartDate) . '</h2>');
            } else {
                $sEndDate = $oLastLog->Get('end_date');
                $iLastLog = $oLastLog->GetKey();
                $oPage->p('<h2>' . Dict::Format('Core:Synchro:SynchroEndedOn_Date', $sEndDate) . '</h2>');
                $sOQL = "SELECT SynchroReplica WHERE sync_source_id={$iDSid}";
                $oSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL));
                $iCountAllReplicas = $oSet->Count();
                $sAllReplicas = "<a href=\"../synchro/replica.php?operation=oql&datasource={$iDSid}&oql={$sOQL}\">{$iCountAllReplicas}</a>";
                $sOQL = "SELECT SynchroReplica WHERE sync_source_id={$iDSid} AND status_last_error !=''";
                $oSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL));
                $iCountAllErrors = $oSet->Count();
                $sAllErrors = "<a href=\"../synchro/replica.php?operation=oql&datasource={$iDSid}&oql={$sOQL}\">{$iCountAllErrors}</a>";
                $sOQL = "SELECT SynchroReplica WHERE sync_source_id={$iDSid} AND status_last_warning !=''";
                $oSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL));
                $iCountAllWarnings = $oSet->Count();
                $sAllWarnings = "<a href=\"../synchro/replica.php?operation=oql&datasource={$iDSid}&oql={$sOQL}\">{$iCountAllWarnings}</a>";
                $oPage->p('<h2>' . Dict::Format('Core:Synchro:ListReplicas_AllReplicas_Errors_Warnings', $sAllReplicas, $sAllErrors, $sAllWarnings) . '</h2>');
            }
            $oPage->add('<table class="synoptics"><tr><td style="color:#333;vertical-align:top">');
            // List all the log entries for the user to select
            $oPage->add('<h2 style="line-height:55px;">' . Dict::S('Core:Synchro:History') . '</h2>');
            $oSetSynchroLog->Rewind();
            $oPage->add('<select size="25" onChange="UpdateSynoptics(this.value);">');
            $sSelected = ' selected';
            // First log is selected by default
            $sScript = "var aSynchroLog = {\n";
            while ($oLog = $oSetSynchroLog->Fetch()) {
                $sLogTitle = Dict::Format('Core:SynchroLogTitle', $oLog->Get('status'), $oLog->Get('start_date'));
                $oPage->add('<option value="' . $oLog->GetKey() . '"' . $sSelected . '>' . $sLogTitle . '</option>');
                $sSelected = '';
                // only the first log is selected by default
                $aData = $this->ProcessLog($oLog);
                $sScript .= '"' . $oLog->GetKey() . '": ' . json_encode($aData) . ",\n";
            }
            $sScript .= "end: 'Done'";
            $sScript .= "};\n";
            $sScript .= <<<EOF
\t\t\tvar sLastLog = '{$iLastLog}';
\tfunction ToggleSynoptics(sId, bShow)
\t{
\t\tif (bShow)
\t\t{
\t\t\t\$(sId).show();
\t\t}
\t\telse
\t\t{
\t\t\t\$(sId).hide();
\t\t}
\t}
\t
\tfunction UpdateSynoptics(id)
\t{
\t\tvar aValues = aSynchroLog[id];
\t\tif (aValues == undefined) return;
\t\t
\t\tfor (var sKey in aValues)
\t\t{
\t\t\t\$('#c_'+sKey).html(aValues[sKey]);
\t\t\tvar fOpacity = (aValues[sKey] == 0) ? 0.3 : 1;
\t\t\t\$('#'+sKey).fadeTo("slow", fOpacity);
\t\t}
\t\t//alert('id = '+id+', lastLog='+sLastLog+', id==sLastLog: '+(id==sLastLog)+' obj_updated_errors:  '+aValues['obj_updated_errors']);
\t\tif ( (id == sLastLog) && (aValues['obj_new_errors'] > 0) )
\t\t{
\t\t\t\$('#new_errors_link').show();
\t\t}
\t\telse
\t\t{
\t\t\t\$('#new_errors_link').hide();
\t\t}
\t\t
\t\tif ( (id == sLastLog) && (aValues['obj_updated_errors'] > 0) )
\t\t{
\t\t\t\$('#updated_errors_link').show();
\t\t}
\t\telse
\t\t{
\t\t\t\$('#updated_errors_link').hide();
\t\t}
\t\t
\t\tif ( (id == sLastLog) && (aValues['obj_disappeared_errors'] > 0) )
\t\t{
\t\t\t\$('#disappeared_errors_link').show();
\t\t}
\t\telse
\t\t{
\t\t\t\$('#disappeared_errors_link').hide();
\t\t}
\t\t
\t\tToggleSynoptics('#cw_obj_created_warnings', aValues['obj_created_warnings'] > 0);
\t\tToggleSynoptics('#cw_obj_new_updated_warnings', aValues['obj_new_updated_warnings'] > 0);
\t\tToggleSynoptics('#cw_obj_new_unchanged_warnings', aValues['obj_new_unchanged_warnings'] > 0);
\t\tToggleSynoptics('#cw_obj_updated_warnings', aValues['obj_updated_warnings'] > 0);
\t\tToggleSynoptics('#cw_obj_unchanged_warnings', aValues['obj_unchanged_warnings'] > 0);
\t}
EOF;
            $oPage->add_script($sScript);
            $oPage->add('</select>');
            $oPage->add('</td><td style="vertical-align:top;">');
            // Now build the big "synoptics" view
            $aData = $this->ProcessLog($oLastLog);
            $sNbReplica = $this->GetIcon() . "&nbsp;" . Dict::Format('Core:Synchro:Nb_Replica', "<span id=\"c_nb_replica_total\">{$aData['nb_replica_total']}</span>");
            $sNbObjects = MetaModel::GetClassIcon($this->GetTargetClass()) . "&nbsp;" . Dict::Format('Core:Synchro:Nb_Class:Objects', $this->GetTargetClass(), "<span id=\"c_nb_obj_total\">{$aData['nb_obj_total']}</span>");
            $oPage->add(<<<EOF
\t<table class="synoptics">
\t<tr class="synoptics_header">
\t<td>{$sNbReplica}</td><td>&nbsp;</td><td>{$sNbObjects}</td>
\t</tr>
\t<tr>
EOF
);
            $sBaseOQL = "SELECT SynchroReplica WHERE sync_source_id=" . $this->GetKey() . " AND status_last_error!=''";
            $oPage->add($this->HtmlBox('repl_ignored', $aData, '#999') . '<td colspan="2">&nbsp;</td>');
            $oPage->add("</tr>\n<tr>");
            $oPage->add($this->HtmlBox('repl_disappeared', $aData, '#630', 'rowspan="4"') . '<td rowspan="4" class="arrow">=&gt;</td>' . $this->HtmlBox('obj_disappeared_no_action', $aData, '#333'));
            $oPage->add("</tr>\n<tr>");
            $oPage->add($this->HtmlBox('obj_deleted', $aData, '#000'));
            $oPage->add("</tr>\n<tr>");
            $oPage->add($this->HtmlBox('obj_obsoleted', $aData, '#630'));
            $oPage->add("</tr>\n<tr>");
            $sOQL = urlencode($sBaseOQL . " AND status='obsolete'");
            $oPage->add($this->HtmlBox('obj_disappeared_errors', $aData, '#C00', '', " <a style=\"color:#fff\" href=\"../synchro/replica.php?operation=oql&datasource={$iDSid}&oql={$sOQL}\" id=\"disappeared_errors_link\">Show</a>"));
            $oPage->add("</tr>\n<tr>");
            $oPage->add($this->HtmlBox('repl_existing', $aData, '#093', 'rowspan="3"') . '<td rowspan="3" class="arrow">=&gt;</td>' . $this->HtmlBox('obj_unchanged', $aData, '#393'));
            $oPage->add("</tr>\n<tr>");
            $oPage->add($this->HtmlBox('obj_updated', $aData, '#3C3'));
            $oPage->add("</tr>\n<tr>");
            $sOQL = urlencode($sBaseOQL . " AND status='modified'");
            $oPage->add($this->HtmlBox('obj_updated_errors', $aData, '#C00', '', " <a style=\"color:#fff\" href=\"../synchro/replica.php?operation=oql&datasource={$iDSid}&oql={$sOQL}\" id=\"updated_errors_link\">Show</a>"));
            $oPage->add("</tr>\n<tr>");
            $oPage->add($this->HtmlBox('repl_new', $aData, '#339', 'rowspan="4"') . '<td rowspan="4" class="arrow">=&gt;</td>' . $this->HtmlBox('obj_new_unchanged', $aData, '#393'));
            $oPage->add("</tr>\n<tr>");
            $oPage->add($this->HtmlBox('obj_new_updated', $aData, '#3C3'));
            $oPage->add("</tr>\n<tr>");
            $oPage->add($this->HtmlBox('obj_created', $aData, '#339'));
            $oPage->add("</tr>\n<tr>");
            $sOQL = urlencode($sBaseOQL . " AND status='new'");
            $oPage->add($this->HtmlBox('obj_new_errors', $aData, '#C00', '', " <a style=\"color:#fff\" href=\"../synchro/replica.php?operation=oql&datasource={$iDSid}&oql={$sOQL}\" id=\"new_errors_link\">Show</a>"));
            $oPage->add("</tr>\n</table>\n");
            $oPage->add('</td></tr></table>');
            $oPage->add_ready_script("UpdateSynoptics('{$iLastLog}')");
        } else {
            $oPage->p('<h2>' . Dict::S('Core:Synchro:NeverRun') . '</h2>');
        }
    }
Ejemplo n.º 19
0
 public static function FromArrayAssoc($aClasses, $aObjects)
 {
     // In a perfect world, we should create a complete tree of DBObjectSearch,
     // but as we lack most of the information related to the objects,
     // let's create one search definition
     $sClass = reset($aClasses);
     $sAlias = key($aClasses);
     $oFilter = new DBObjectSearch($sClass, $sAlias);
     $oRetSet = new CMDBObjectSet($oFilter);
     $oRetSet->m_bLoaded = true;
     // no DB load
     foreach ($aObjects as $rowIndex => $aObjectsByClassAlias) {
         $oRetSet->AddObjectExtended($aObjectsByClassAlias);
     }
     return $oRetSet;
 }
Ejemplo n.º 20
0
    // Not a valid relation, use the default one instead
    $sRelation = 'impacts';
}
try {
    if ($id != 0) {
        switch ($sFormat) {
            case 'html':
                $oPage->SetContentType('text/html');
                $oObj = MetaModel::GetObject($sClass, $id, true);
                $aResults = array();
                $iMaxRecursionDepth = MetaModel::GetConfig()->Get('relations_max_depth', 20);
                $oObj->GetRelatedObjects($sRelation, $iMaxRecursionDepth, $aResults);
                $iBlock = 1;
                // Zero is not a valid blockid
                foreach ($aResults as $sClass => $aObjects) {
                    $oSet = CMDBObjectSet::FromArray($sClass, $aObjects);
                    $oPage->add("<h1>" . MetaModel::GetRelationDescription($sRelation) . ' ' . $oObj->GetName() . "</h1>\n");
                    $oPage->add("<div class=\"page_header\">\n");
                    $oPage->add("<h2>" . MetaModel::GetClassIcon($sClass) . "&nbsp;<span class=\"hilite\">" . Dict::Format('UI:Search:Count_ObjectsOf_Class_Found', count($aObjects), Metamodel::GetName($sClass)) . "</h2>\n");
                    $oPage->add("</div>\n");
                    $oBlock = DisplayBlock::FromObjectSet($oSet, 'list');
                    $oBlock->Display($oPage, $iBlock++);
                    $oPage->P('&nbsp;');
                    // Some space ?
                }
                break;
            case 'xml':
            default:
                $oPage->SetContentType('text/xml');
                $oObj = MetaModel::GetObject($sClass, $id, true);
                // Build the root XML part
 function DisplayBareRelations(WebPage $oPage, $bEditMode = false)
 {
     parent::DisplayBareRelations($oPage, $bEditMode);
     if (!$bEditMode) {
         if (MetaModel::IsValidClass('KnownError')) {
             //Search for known errors
             $oPage->SetCurrentTab(Dict::S('Class:UserRequest:KnownErrorList'));
             $iTicketID = $this->GetKey();
             $oKnownErrorSet = new CMDBObjectSet(DBObjectSearch::FromOQL("SELECT KnownError AS ke JOIN lnkErrorToFunctionalCI AS l1 ON l1.error_id=ke.id JOIN FunctionalCI AS ci ON l1.functionalci_id=ci.id JOIN lnkFunctionalCIToTicket AS l2 ON l2.functionalci_id=ci.id WHERE l2.ticket_id={$iTicketID}"));
             $iNumberKE = $oKnownErrorSet->count();
             if ($iNumberKE > 0) {
                 $oPage->SetCurrentTab(Dict::S('Class:UserRequest:KnownErrorList') . " ({$iNumberKE})");
             } else {
                 $oPage->SetCurrentTab(Dict::S('Class:UserRequest:KnownErrorList'));
             }
             self::DisplaySet($oPage, $oKnownErrorSet, array('menu' => false));
         }
     }
 }
Ejemplo n.º 22
0
             }
         }
     }
 }
 // Read query parameters
 //
 $aArgs = array();
 foreach ($oFilter->GetQueryParams() as $sParam => $foo) {
     $value = utils::ReadParam('arg_' . $sParam, null, true, 'raw_data');
     if (!is_null($value)) {
         $aArgs[$sParam] = $value;
     }
 }
 $oFilter->SetInternalParams($aArgs);
 if ($oFilter) {
     $oSet = new CMDBObjectSet($oFilter, array(), $aArgs);
     $oSet->OptimizeColumnLoad($aAliasToFields);
     switch ($sFormat) {
         case 'html':
             $oP = new NiceWebPage("iTop - Export");
             $oP->add_style('body { overflow: auto; }');
             // Show scroll bars if needed
             // Integration within MS-Excel web queries + HTTPS + IIS:
             // MS-IIS set these header values with no-cache... while Excel fails to do the job if using HTTPS
             // Then the fix is to force the reset of header values Pragma and Cache-control
             header("Pragma:", true);
             header("Cache-control:", true);
             // The HTML output is made for pages located in the /pages/ folder
             // since this page is in a different folder, let's adjust the HTML 'base' attribute
             // to make the relative hyperlinks in the page work
             $sUrl = utils::GetAbsoluteUrlAppRoot();
Ejemplo n.º 23
0
function DisplayNavigatorListTab($oP, $aResults, $sRelation, $oObj)
{
    $oP->SetCurrentTab(Dict::S('UI:RelationshipList'));
    $oP->add("<div id=\"impacted_objects\" style=\"width:100%;background-color:#fff;padding:10px;\">");
    $iBlock = 1;
    // Zero is not a valid blockid
    foreach ($aResults as $sListClass => $aObjects) {
        $oSet = CMDBObjectSet::FromArray($sListClass, $aObjects);
        $oP->add("<h1>" . MetaModel::GetRelationDescription($sRelation) . ' ' . $oObj->GetName() . "</h1>\n");
        $oP->add("<div class=\"page_header\">\n");
        $oP->add("<h2>" . MetaModel::GetClassIcon($sListClass) . "&nbsp;<span class=\"hilite\">" . Dict::Format('UI:Search:Count_ObjectsOf_Class_Found', count($aObjects), Metamodel::GetName($sListClass)) . "</h2>\n");
        $oP->add("</div>\n");
        $oBlock = DisplayBlock::FromObjectSet($oSet, 'list');
        $oBlock->Display($oP, $iBlock++);
        $oP->P('&nbsp;');
        // Some space ?
    }
    $oP->add("</div>");
}
Ejemplo n.º 24
0
 /**
  * Helper to link objects
  *
  * @param string sLinkAttCode
  * @param string sLinkedClass
  * @param array $aLinkList
  * @param DBObject oTargetObj
  * @param WebServiceResult oRes
  *
  * @return array List of objects that could not be found
  */
 protected function AddLinkedObjects($sLinkAttCode, $sParamName, $sLinkedClass, $aLinkList, &$oTargetObj, &$oRes)
 {
     $oLinkAtt = MetaModel::GetAttributeDef(get_class($oTargetObj), $sLinkAttCode);
     $sLinkClass = $oLinkAtt->GetLinkedClass();
     $sExtKeyToItem = $oLinkAtt->GetExtKeyToRemote();
     $aItemsFound = array();
     $aItemsNotFound = array();
     if (is_null($aLinkList)) {
         return $aItemsNotFound;
     }
     foreach ($aLinkList as $aItemData) {
         if (!array_key_exists('class', $aItemData)) {
             $oRes->LogWarning("Parameter {$sParamName}: missing 'class' specification");
             continue;
             // skip
         }
         $sTargetClass = $aItemData['class'];
         if (!MetaModel::IsValidClass($sTargetClass)) {
             $oRes->LogError("Parameter {$sParamName}: invalid class '{$sTargetClass}'");
             continue;
             // skip
         }
         if (!MetaModel::IsParentClass($sLinkedClass, $sTargetClass)) {
             $oRes->LogError("Parameter {$sParamName}: '{$sTargetClass}' is not a child class of '{$sLinkedClass}'");
             continue;
             // skip
         }
         $oReconFilter = new CMDBSearchFilter($sTargetClass);
         $aCIStringDesc = array();
         foreach ($aItemData['search'] as $sAttCode => $value) {
             if (!MetaModel::IsValidFilterCode($sTargetClass, $sAttCode)) {
                 $aCodes = array_keys(MetaModel::GetClassFilterDefs($sTargetClass));
                 $oRes->LogError("Parameter {$sParamName}: '{$sAttCode}' is not a valid filter code for class '{$sTargetClass}', expecting a value in {" . implode(', ', $aCodes) . "}");
                 continue 2;
                 // skip the entire item
             }
             $aCIStringDesc[] = "{$sAttCode}: {$value}";
             // The attribute is one of our reconciliation key
             $oReconFilter->AddCondition($sAttCode, $value, '=');
         }
         if (count($aCIStringDesc) == 1) {
             // take the last and unique value to describe the object
             $sItemDesc = $value;
         } else {
             // describe the object by the given keys
             $sItemDesc = $sTargetClass . '(' . implode('/', $aCIStringDesc) . ')';
         }
         $oExtObjects = new CMDBObjectSet($oReconFilter);
         switch ($oExtObjects->Count()) {
             case 0:
                 $oRes->LogWarning("Parameter {$sParamName}: object to link {$sLinkedClass} / {$sItemDesc} could not be found (searched: '" . $oReconFilter->ToOQL(true) . "')");
                 $aItemsNotFound[] = $sItemDesc;
                 break;
             case 1:
                 $aItemsFound[] = array('object' => $oExtObjects->Fetch(), 'link_values' => @$aItemData['link_values'], 'desc' => $sItemDesc);
                 break;
             default:
                 $oRes->LogWarning("Parameter {$sParamName}: Found " . $oExtObjects->Count() . " matches for item '{$sItemDesc}' (searched: '" . $oReconFilter->ToOQL(true) . "')");
                 $aItemsNotFound[] = $sItemDesc;
         }
     }
     if (count($aItemsFound) > 0) {
         $aLinks = array();
         foreach ($aItemsFound as $aItemData) {
             $oLink = MetaModel::NewObject($sLinkClass);
             $oLink->Set($sExtKeyToItem, $aItemData['object']->GetKey());
             foreach ($aItemData['link_values'] as $sKey => $value) {
                 if (!MetaModel::IsValidAttCode($sLinkClass, $sKey)) {
                     $oRes->LogWarning("Parameter {$sParamName}: Attaching item '" . $aItemData['desc'] . "', the attribute code '{$sKey}' is not valid ; check the class '{$sLinkClass}'");
                 } else {
                     $oLink->Set($sKey, $value);
                 }
             }
             $aLinks[] = $oLink;
         }
         $oImpactedInfraSet = DBObjectSet::FromArray($sLinkClass, $aLinks);
         $oTargetObj->Set($sLinkAttCode, $oImpactedInfraSet);
     }
     return $aItemsNotFound;
 }
Ejemplo n.º 25
0
 public function GetReferencingObjects($bAllowAllData = false)
 {
     $aDependentObjects = array();
     $aRererencingMe = MetaModel::EnumReferencingClasses(get_class($this));
     foreach ($aRererencingMe as $sRemoteClass => $aExtKeys) {
         foreach ($aExtKeys as $sExtKeyAttCode => $oExtKeyAttDef) {
             // skip if this external key is behind an external field
             if (!$oExtKeyAttDef->IsExternalKey(EXTKEY_ABSOLUTE)) {
                 continue;
             }
             $oSearch = new DBObjectSearch($sRemoteClass);
             $oSearch->AddCondition($sExtKeyAttCode, $this->GetKey(), '=');
             if ($bAllowAllData) {
                 $oSearch->AllowAllData();
             }
             $oSet = new CMDBObjectSet($oSearch);
             if ($oSet->Count() > 0) {
                 $aDependentObjects[$sRemoteClass][$sExtKeyAttCode] = array('attribute' => $oExtKeyAttDef, 'objects' => $oSet);
             }
         }
     }
     return $aDependentObjects;
 }
Ejemplo n.º 26
0
 static function ParseJsonSet($oMe, $sLinkClass, $sExtKeyToMe, $sJsonSet)
 {
     $aSet = json_decode($sJsonSet, true);
     // true means hash array instead of object
     $oSet = CMDBObjectSet::FromScratch($sLinkClass);
     foreach ($aSet as $aLinkObj) {
         $oLink = MetaModel::NewObject($sLinkClass);
         foreach ($aLinkObj as $sAttCode => $value) {
             $oAttDef = MetaModel::GetAttributeDef($sLinkClass, $sAttCode);
             if ($oAttDef->IsExternalKey() && $value != '' && $value > 0) {
                 // For external keys: load the target object so that external fields
                 // get filled too
                 $oTargetObj = MetaModel::GetObject($oAttDef->GetTargetClass(), $value);
                 $oLink->Set($sAttCode, $oTargetObj);
             }
             $oLink->Set($sAttCode, $value);
         }
         $oLink->Set($sExtKeyToMe, $oMe->GetKey());
         $oSet->AddObject($oLink);
     }
     return $oSet;
 }
Ejemplo n.º 27
0
 private static function MakeQuery(&$oBuild, DBObjectSearch $oFilter, $aAttToLoad = null, $aValues = array(), $bIsMainQueryUNUSED = false)
 {
     // Note: query class might be different than the class of the filter
     // -> this occurs when we are linking our class to an external class (referenced by, or pointing to)
     $sClass = $oFilter->GetFirstJoinedClass();
     $sClassAlias = $oFilter->GetFirstJoinedClassAlias();
     $bIsOnQueriedClass = array_key_exists($sClassAlias, $oBuild->GetRootFilter()->GetSelectedClasses());
     self::DbgTrace("Entering: " . $oFilter->ToOQL() . ", " . ($bIsOnQueriedClass ? "MAIN" : "SECONDARY"));
     $sRootClass = self::GetRootClass($sClass);
     $sKeyField = self::DBGetKey($sClass);
     if ($bIsOnQueriedClass) {
         // default to the whole list of attributes + the very std id/finalclass
         $oBuild->m_oQBExpressions->AddSelect($sClassAlias . 'id', new FieldExpression('id', $sClassAlias));
         if (is_null($aAttToLoad) || !array_key_exists($sClassAlias, $aAttToLoad)) {
             $aAttList = self::ListAttributeDefs($sClass);
         } else {
             $aAttList = $aAttToLoad[$sClassAlias];
         }
         foreach ($aAttList as $sAttCode => $oAttDef) {
             if (!$oAttDef->IsScalar()) {
                 continue;
             }
             // keep because it can be used for sorting - if (!$oAttDef->LoadInObject()) continue;
             foreach ($oAttDef->GetSQLExpressions() as $sColId => $sSQLExpr) {
                 $oBuild->m_oQBExpressions->AddSelect($sClassAlias . $sAttCode . $sColId, new FieldExpression($sAttCode . $sColId, $sClassAlias));
             }
         }
         // Transform the full text condition into additional condition expression
         $aFullText = $oFilter->GetCriteria_FullText();
         if (count($aFullText) > 0) {
             $aFullTextFields = array();
             foreach (self::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) {
                 if (!$oAttDef->IsScalar()) {
                     continue;
                 }
                 if ($oAttDef->IsExternalKey()) {
                     continue;
                 }
                 $aFullTextFields[] = new FieldExpression($sAttCode, $sClassAlias);
             }
             $oTextFields = new CharConcatWSExpression(' ', $aFullTextFields);
             foreach ($aFullText as $sFTNeedle) {
                 $oNewCond = new BinaryExpression($oTextFields, 'LIKE', new ScalarExpression("%{$sFTNeedle}%"));
                 $oBuild->m_oQBExpressions->AddCondition($oNewCond);
             }
         }
     }
     //echo "<p>oQBExpr ".__LINE__.": <pre>\n".print_r($oBuild->m_oQBExpressions, true)."</pre></p>\n";
     $aExpectedAtts = array();
     // array of (attcode => fieldexpression)
     //echo "<p>".__LINE__.": GetUnresolvedFields($sClassAlias, ...)</p>\n";
     $oBuild->m_oQBExpressions->GetUnresolvedFields($sClassAlias, $aExpectedAtts);
     // Compute a clear view of required joins (from the current class)
     // Build the list of external keys:
     // -> ext keys required by an explicit join
     // -> ext keys mentionned in a 'pointing to' condition
     // -> ext keys required for an external field
     // -> ext keys required for a friendly name
     //
     $aExtKeys = array();
     // array of sTableClass => array of (sAttCode (keys) => array of (sAttCode (fields)=> oAttDef))
     //
     // Optimization: could be partially computed once for all (cached) ?
     //
     if ($bIsOnQueriedClass) {
         // Get all Ext keys for the queried class (??)
         foreach (self::GetKeysList($sClass) as $sKeyAttCode) {
             $sKeyTableClass = self::$m_aAttribOrigins[$sClass][$sKeyAttCode];
             $aExtKeys[$sKeyTableClass][$sKeyAttCode] = array();
         }
     }
     // Get all Ext keys used by the filter
     foreach ($oFilter->GetCriteria_PointingTo() as $sKeyAttCode => $aPointingTo) {
         if (array_key_exists(TREE_OPERATOR_EQUALS, $aPointingTo)) {
             $sKeyTableClass = self::$m_aAttribOrigins[$sClass][$sKeyAttCode];
             $aExtKeys[$sKeyTableClass][$sKeyAttCode] = array();
         }
     }
     $aFNJoinAlias = array();
     // array of (subclass => alias)
     if (array_key_exists('friendlyname', $aExpectedAtts)) {
         // To optimize: detect a restriction on child classes in the condition expression
         //    e.g. SELECT FunctionalCI WHERE finalclass IN ('Server', 'VirtualMachine')
         $oNameExpression = self::GetExtendedNameExpression($sClass);
         $aNameFields = array();
         $oNameExpression->GetUnresolvedFields('', $aNameFields);
         $aTranslateNameFields = array();
         foreach ($aNameFields as $sSubClass => $aFields) {
             foreach ($aFields as $sAttCode => $oField) {
                 $oAttDef = self::GetAttributeDef($sSubClass, $sAttCode);
                 if ($oAttDef->IsExternalKey()) {
                     $sClassOfAttribute = self::$m_aAttribOrigins[$sSubClass][$sAttCode];
                     $aExtKeys[$sClassOfAttribute][$sAttCode] = array();
                 } elseif ($oAttDef->IsExternalField() || $oAttDef instanceof AttributeFriendlyName) {
                     $sKeyAttCode = $oAttDef->GetKeyAttCode();
                     $sClassOfAttribute = self::$m_aAttribOrigins[$sSubClass][$sKeyAttCode];
                     $aExtKeys[$sClassOfAttribute][$sKeyAttCode][$sAttCode] = $oAttDef;
                 } else {
                     $sClassOfAttribute = self::GetAttributeOrigin($sSubClass, $sAttCode);
                 }
                 if (self::IsParentClass($sClassOfAttribute, $sClass)) {
                     // The attribute is part of the standard query
                     //
                     $sAliasForAttribute = $sClassAlias;
                 } else {
                     // The attribute will be available from an additional outer join
                     // For each subclass (table) one single join is enough
                     //
                     if (!array_key_exists($sClassOfAttribute, $aFNJoinAlias)) {
                         $sAliasForAttribute = $oBuild->GenerateClassAlias($sClassAlias . '_fn_' . $sClassOfAttribute, $sClassOfAttribute);
                         $aFNJoinAlias[$sClassOfAttribute] = $sAliasForAttribute;
                     } else {
                         $sAliasForAttribute = $aFNJoinAlias[$sClassOfAttribute];
                     }
                 }
                 $aTranslateNameFields[$sSubClass][$sAttCode] = new FieldExpression($sAttCode, $sAliasForAttribute);
             }
         }
         $oNameExpression = $oNameExpression->Translate($aTranslateNameFields, false);
         $aTranslateNow = array();
         $aTranslateNow[$sClassAlias]['friendlyname'] = $oNameExpression;
         $oBuild->m_oQBExpressions->Translate($aTranslateNow, false);
     }
     // Add the ext fields used in the select (eventually adds an external key)
     foreach (self::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) {
         if ($oAttDef->IsExternalField() || $oAttDef instanceof AttributeFriendlyName) {
             if (array_key_exists($sAttCode, $aExpectedAtts)) {
                 $sKeyAttCode = $oAttDef->GetKeyAttCode();
                 if ($sKeyAttCode != 'id') {
                     // Add the external attribute
                     $sKeyTableClass = self::$m_aAttribOrigins[$sClass][$sKeyAttCode];
                     $aExtKeys[$sKeyTableClass][$sKeyAttCode][$sAttCode] = $oAttDef;
                 }
             }
         }
     }
     // First query built upon on the leaf (ie current) class
     //
     self::DbgTrace("Main (=leaf) class, call MakeQuerySingleTable()");
     if (self::HasTable($sClass)) {
         $oSelectBase = self::MakeQuerySingleTable($oBuild, $oFilter, $sClass, $aExtKeys, $aValues);
     } else {
         $oSelectBase = null;
         // As the join will not filter on the expected classes, we have to specify it explicitely
         $sExpectedClasses = implode("', '", self::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL));
         $oFinalClassRestriction = Expression::FromOQL("`{$sClassAlias}`.finalclass IN ('{$sExpectedClasses}')");
         $oBuild->m_oQBExpressions->AddCondition($oFinalClassRestriction);
     }
     // Then we join the queries of the eventual parent classes (compound model)
     foreach (self::EnumParentClasses($sClass) as $sParentClass) {
         if (!self::HasTable($sParentClass)) {
             continue;
         }
         self::DbgTrace("Parent class: {$sParentClass}... let's call MakeQuerySingleTable()");
         $oSelectParentTable = self::MakeQuerySingleTable($oBuild, $oFilter, $sParentClass, $aExtKeys, $aValues);
         if (is_null($oSelectBase)) {
             $oSelectBase = $oSelectParentTable;
         } else {
             $oSelectBase->AddInnerJoin($oSelectParentTable, $sKeyField, self::DBGetKey($sParentClass));
         }
     }
     // Filter on objects referencing me
     foreach ($oFilter->GetCriteria_ReferencedBy() as $sForeignClass => $aKeysAndFilters) {
         foreach ($aKeysAndFilters as $sForeignKeyAttCode => $oForeignFilter) {
             $oForeignKeyAttDef = self::GetAttributeDef($sForeignClass, $sForeignKeyAttCode);
             self::DbgTrace("Referenced by foreign key: {$sForeignKeyAttCode}... let's call MakeQuery()");
             //self::DbgTrace($oForeignFilter);
             //self::DbgTrace($oForeignFilter->ToOQL());
             //self::DbgTrace($oSelectForeign);
             //self::DbgTrace($oSelectForeign->RenderSelect(array()));
             $sForeignClassAlias = $oForeignFilter->GetFirstJoinedClassAlias();
             $oBuild->m_oQBExpressions->PushJoinField(new FieldExpression($sForeignKeyAttCode, $sForeignClassAlias));
             $oSelectForeign = self::MakeQuery($oBuild, $oForeignFilter, $aAttToLoad);
             $oJoinExpr = $oBuild->m_oQBExpressions->PopJoinField();
             $sForeignKeyTable = $oJoinExpr->GetParent();
             $sForeignKeyColumn = $oJoinExpr->GetName();
             $oSelectBase->AddInnerJoin($oSelectForeign, $sKeyField, $sForeignKeyColumn, $sForeignKeyTable);
         }
     }
     // Filter on related objects
     //
     foreach ($oFilter->GetCriteria_RelatedTo() as $aCritInfo) {
         $oSubFilter = $aCritInfo['flt'];
         $sRelCode = $aCritInfo['relcode'];
         $iMaxDepth = $aCritInfo['maxdepth'];
         // Get the starting point objects
         $oStartSet = new CMDBObjectSet($oSubFilter);
         // Get the objects related to those objects... recursively...
         $aRelatedObjs = $oStartSet->GetRelatedObjects($sRelCode, $iMaxDepth);
         $aRestriction = array_key_exists($sRootClass, $aRelatedObjs) ? $aRelatedObjs[$sRootClass] : array();
         // #@# todo - related objects and expressions...
         // Create condition
         if (count($aRestriction) > 0) {
             $oSelectBase->AddCondition($sKeyField . ' IN (' . implode(', ', CMDBSource::Quote(array_keys($aRestriction), true)) . ')');
         } else {
             // Quick N'dirty -> generate an empty set
             $oSelectBase->AddCondition('false');
         }
     }
     // Additional JOINS for Friendly names
     //
     foreach ($aFNJoinAlias as $sSubClass => $sSubClassAlias) {
         $oSubClassFilter = new DBObjectSearch($sSubClass, $sSubClassAlias);
         $oSelectFN = self::MakeQuerySingleTable($oBuild, $oSubClassFilter, $sSubClass, $aExtKeys, array());
         $oSelectBase->AddLeftJoin($oSelectFN, $sKeyField, self::DBGetKey($sSubClass));
     }
     // That's all... cross fingers and we'll get some working query
     //MyHelpers::var_dump_html($oSelectBase, true);
     //MyHelpers::var_dump_html($oSelectBase->RenderSelect(), true);
     if (self::$m_bDebugQuery) {
         $oSelectBase->DisplayHtml();
     }
     return $oSelectBase;
 }