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)."; }
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"; }
$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);
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() . " " . 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"); } }
$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);
/** * 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; }
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; }
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); }
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) . " <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(' '); // Some space ? } $oP->add("</div>"); } }
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; }
/** * 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() . " " . Dict::Format('Core:Synchro:Nb_Replica', "<span id=\"c_nb_replica_total\">{$aData['nb_replica_total']}</span>"); $sNbObjects = MetaModel::GetClassIcon($this->GetTargetClass()) . " " . 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> </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"> </td>'); $oPage->add("</tr>\n<tr>"); $oPage->add($this->HtmlBox('repl_disappeared', $aData, '#630', 'rowspan="4"') . '<td rowspan="4" class="arrow">=></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">=></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">=></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>'); } }
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; }
// 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) . " <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(' '); // 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)); } } }
} } } } // 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();
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) . " <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(' '); // Some space ? } $oP->add("</div>"); }
/** * 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; }
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; }
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; }
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; }