/** * Fills the given XML node with te details of the specified object */ function AddNodeDetails(&$oNode, $oObj) { $aZlist = MetaModel::GetZListItems(get_class($oObj), 'list'); $aLabels = array(); $index = 0; foreach ($aZlist as $sAttCode) { $oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode); $aLabels[] = $oAttDef->GetLabel(); if (!$oAttDef->IsLinkSet()) { $oNode->SetAttribute('att_' . $index, $oObj->GetAsHTML($sAttCode)); } $index++; } $oNode->SetAttribute('zlist', implode(',', $aLabels)); }
protected function SuggestField($sClass, $sAttCode) { switch ($sAttCode) { case 'id': // replace 'id' by 'friendlyname' $sAttCode = 'friendlyname'; break; default: $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); if ($oAttDef instanceof AttributeExternalKey) { $sAttCode .= '_friendlyname'; } } return parent::SuggestField($sClass, $sAttCode); }
/** * Adds the context parameters to the audit query */ function FilterByContext(DBSearch &$oFilter, ApplicationContext $oAppContext) { $sObjClass = $oFilter->GetClass(); $aContextParams = $oAppContext->GetNames(); $aCallSpec = array($sObjClass, 'MapContextParam'); if (is_callable($aCallSpec)) { foreach ($aContextParams as $sParamName) { $sValue = $oAppContext->GetCurrentValue($sParamName, null); if ($sValue != null) { $sAttCode = call_user_func($aCallSpec, $sParamName); // Returns null when there is no mapping for this parameter if ($sAttCode != null && MetaModel::IsValidAttCode($sObjClass, $sAttCode)) { // Check if the condition points to a hierarchical key if ($sAttCode == 'id') { // Filtering on the objects themselves $sHierarchicalKeyCode = MetaModel::IsHierarchicalClass($sObjClass); if ($sHierarchicalKeyCode !== false) { $oRootFilter = new DBObjectSearch($sObjClass); $oRootFilter->AddCondition($sAttCode, $sValue); $oFilter->AddCondition_PointingTo($oRootFilter, $sHierarchicalKeyCode, TREE_OPERATOR_BELOW); // Use the 'below' operator by default $bConditionAdded = true; } } else { $oAttDef = MetaModel::GetAttributeDef($sObjClass, $sAttCode); $bConditionAdded = false; if ($oAttDef->IsExternalKey()) { $sHierarchicalKeyCode = MetaModel::IsHierarchicalClass($oAttDef->GetTargetClass()); if ($sHierarchicalKeyCode !== false) { $oRootFilter = new DBObjectSearch($oAttDef->GetTargetClass()); $oRootFilter->AddCondition('id', $sValue); $oHKFilter = new DBObjectSearch($oAttDef->GetTargetClass()); $oHKFilter->AddCondition_PointingTo($oRootFilter, $sHierarchicalKeyCode, TREE_OPERATOR_BELOW); // Use the 'below' operator by default $oFilter->AddCondition_PointingTo($oHKFilter, $sAttCode); $bConditionAdded = true; } } } if (!$bConditionAdded) { $oFilter->AddCondition($sAttCode, $sValue); } } } } } }
/** * Helper to make an output value for a given attribute * * @param DBObject $oObject The object being reported * @param string $sAttCode The attribute code (must be valid) * @param boolean $bExtendedOutput Output all of the link set attributes ? * @return string A scalar representation of the value */ protected function MakeResultValue(DBObject $oObject, $sAttCode, $bExtendedOutput = false) { if ($sAttCode == 'id') { $value = $oObject->GetKey(); } else { $sClass = get_class($oObject); $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); if ($oAttDef instanceof AttributeLinkedSet) { // Iterate on the set and build an array of array of attcode=>value $oSet = $oObject->Get($sAttCode); $value = array(); while ($oLnk = $oSet->Fetch()) { $sLnkRefClass = $bExtendedOutput ? get_class($oLnk) : $oAttDef->GetLinkedClass(); $aLnkValues = array(); foreach (MetaModel::ListAttributeDefs($sLnkRefClass) as $sLnkAttCode => $oLnkAttDef) { // Skip attributes pointing to the current object (redundant data) if ($sLnkAttCode == $oAttDef->GetExtKeyToMe()) { continue; } // Skip any attribute of the link that points to the current object $oLnkAttDef = MetaModel::GetAttributeDef($sLnkRefClass, $sLnkAttCode); if (method_exists($oLnkAttDef, 'GetKeyAttCode')) { if ($oLnkAttDef->GetKeyAttCode() == $oAttDef->GetExtKeyToMe()) { continue; } } $aLnkValues[$sLnkAttCode] = $this->MakeResultValue($oLnk, $sLnkAttCode, $bExtendedOutput); } $value[] = $aLnkValues; } } else { $value = $oAttDef->GetForJSON($oObject->Get($sAttCode)); } } return $value; }
function DisplayBareProperties(WebPage $oPage, $bEditMode = false, $sPrefix = '', $aExtraParams = array()) { $aFieldsMap = parent::DisplayBareProperties($oPage, $bEditMode, $sPrefix, $aExtraParams); if (!$bEditMode) { $sFields = trim($this->Get('fields')); $bExportV1Recommended = $sFields == ''; if ($bExportV1Recommended) { $oFieldAttDef = MetaModel::GetAttributeDef('QueryOQL', 'fields'); $oPage->add('<div class="message message_error" style="padding-left: 30px;"><div style="padding: 10px;">' . Dict::Format('UI:Query:UrlV1', $oFieldAttDef->GetLabel()) . '</div></div>'); $sUrl = utils::GetAbsoluteUrlAppRoot() . 'webservices/export.php?format=spreadsheet&login_mode=basic&query=' . $this->GetKey(); } else { $sUrl = utils::GetAbsoluteUrlAppRoot() . 'webservices/export-v2.php?format=spreadsheet&login_mode=basic&query=' . $this->GetKey(); } $sOql = $this->Get('oql'); $sMessage = null; try { $oSearch = DBObjectSearch::FromOQL($sOql); $aParameters = $oSearch->GetQueryParams(); foreach ($aParameters as $sParam => $val) { $sUrl .= '&arg_' . $sParam . '=["' . $sParam . '"]'; } $oPage->p(Dict::S('UI:Query:UrlForExcel') . ':<br/><textarea cols="80" rows="3" READONLY>' . $sUrl . '</textarea>'); if (count($aParameters) == 0) { $oBlock = new DisplayBlock($oSearch, 'list'); $aExtraParams = array('table_id' => 'query_preview_' . $this->getKey()); $sBlockId = 'block_query_preview_' . $this->GetKey(); // make a unique id (edition occuring in the same DOM) $oBlock->Display($oPage, $sBlockId, $aExtraParams); } } catch (OQLException $e) { $sMessage = '<div class="message message_error" style="padding-left: 30px;"><div style="padding: 10px;">' . Dict::Format('UI:RunQuery:Error', $e->getHtmlDesc()) . '</div></div>'; $oPage->p($sMessage); } } return $aFieldsMap; }
public function GetTooltip($aContextDefs) { $sHtml = ''; $oCurrObj = $this->GetProperty('object'); $sSubClass = get_class($oCurrObj); $sHtml .= $oCurrObj->GetHyperlink() . "<hr/>"; $aContextRootCauses = $this->GetProperty('context_root_causes'); if (!is_null($aContextRootCauses)) { foreach ($aContextRootCauses as $key => $aObjects) { $aContext = $aContextDefs[$key]; $aRootCauses = array(); foreach ($aObjects as $oRootCause) { $aRootCauses[] = $oRootCause->GetHyperlink(); } $sHtml .= '<p><img style="max-height: 24px; vertical-align:bottom;" src="' . utils::GetAbsoluteUrlModulesRoot() . $aContext['icon'] . '" title="' . htmlentities(Dict::S($aContext['dict'])) . '"> ' . implode(', ', $aRootCauses) . '</p>'; } $sHtml .= '<hr/>'; } $sHtml .= '<table><tbody>'; foreach (MetaModel::GetZListItems($sSubClass, 'list') as $sAttCode) { $oAttDef = MetaModel::GetAttributeDef($sSubClass, $sAttCode); $sHtml .= '<tr><td>' . $oAttDef->GetLabel() . ': </td><td>' . $oCurrObj->GetAsHtml($sAttCode) . '</td></tr>'; } $sHtml .= '</tbody></table>'; return $sHtml; }
public function unserialize($sData) { $aData = unserialize($sData); $this->iDefaultPageSize = $aData['iDefaultPageSize']; $this->aColumns = $aData['aColumns']; foreach ($this->aClassAliases as $sAlias => $sClass) { foreach ($this->aColumns[$sAlias] as $sAttCode => $aData) { $aFieldData = false; if ($sAttCode == '_key_') { $aFieldData = $this->GetFieldData($sAlias, $sAttCode, null, true, $aData['sort']); } else { if (MetaModel::isValidAttCode($sClass, $sAttCode)) { $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); $aFieldData = $this->GetFieldData($sAlias, $sAttCode, $oAttDef, true, $aData['sort']); } } if ($aFieldData) { $this->aColumns[$sAlias][$sAttCode] = $aFieldData; } else { unset($this->aColumns[$sAlias][$sAttCode]); } } } $this->FixVisibleColumns(); }
/** * Common to the recording of link set changes (add/remove/modify) */ private function PrepareChangeOpLinkSet($iLinkSetOwnerId, $oLinkSet, $sChangeOpClass, $aOriginalValues = null) { if ($iLinkSetOwnerId <= 0) { return null; } if (!is_subclass_of($oLinkSet->GetHostClass(), 'CMDBObject')) { // The link set owner class does not keep track of its history return null; } // Determine the linked item class and id // if ($oLinkSet->IsIndirect()) { // The "item" is on the other end (N-N links) $sExtKeyToRemote = $oLinkSet->GetExtKeyToRemote(); $oExtKeyToRemote = MetaModel::GetAttributeDef(get_class($this), $sExtKeyToRemote); $sItemClass = $oExtKeyToRemote->GetTargetClass(); if ($aOriginalValues) { // Get the value from the original values $iItemId = $aOriginalValues[$sExtKeyToRemote]; } else { $iItemId = $this->Get($sExtKeyToRemote); } } else { // I am the "item" (1-N links) $sItemClass = get_class($this); $iItemId = $this->GetKey(); } // Get the remote object, to determine its exact class // Possible optimization: implement a tool in MetaModel, to get the final class of an object (not always querying + query reduced to a select on the root table! $oOwner = MetaModel::GetObject($oLinkSet->GetHostClass(), $iLinkSetOwnerId, false); if ($oOwner) { $sLinkSetOwnerClass = get_class($oOwner); $oMyChangeOp = MetaModel::NewObject($sChangeOpClass); $oMyChangeOp->Set("objclass", $sLinkSetOwnerClass); $oMyChangeOp->Set("objkey", $iLinkSetOwnerId); $oMyChangeOp->Set("attcode", $oLinkSet->GetCode()); $oMyChangeOp->Set("item_class", $sItemClass); $oMyChangeOp->Set("item_id", $iItemId); return $oMyChangeOp; } else { // Depending on the deletion order, it may happen that the id is already invalid... ignore return null; } }
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; }
protected function DisplaySearchField($sClass, $sAttSpec, $aExtraParams, $sPrefix, $sFieldName = null, $aFilterParams = array()) { if (is_null($sFieldName)) { $sFieldName = str_replace('->', PARAM_ARROW_SEP, $sAttSpec); } $iPos = strpos($sAttSpec, '->'); if ($iPos !== false) { $sAttCode = substr($sAttSpec, 0, $iPos); $sSubSpec = substr($sAttSpec, $iPos + 2); if (!MetaModel::IsValidAttCode($sClass, $sAttCode)) { throw new Exception("Invalid attribute code '{$sClass}/{$sAttCode}' in search specification '{$sAttSpec}'"); } $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); if ($oAttDef->IsLinkSet()) { $sTargetClass = $oAttDef->GetLinkedClass(); } elseif ($oAttDef->IsExternalKey(EXTKEY_ABSOLUTE)) { $sTargetClass = $oAttDef->GetTargetClass(EXTKEY_ABSOLUTE); } else { throw new Exception("Attribute specification '{$sAttSpec}', '{$sAttCode}' should be either a link set or an external key"); } $this->DisplaySearchField($sTargetClass, $sSubSpec, $aExtraParams, $sPrefix, $sFieldName, $aFilterParams); } else { // $sAttSpec is an attribute code // $this->add('<span style="white-space: nowrap;padding:5px;display:inline-block;">'); $sFilterValue = ''; $sFilterValue = utils::ReadParam($sPrefix . $sFieldName, '', false, 'raw_data'); $sFilterOpCode = null; // Use the default 'loose' OpCode $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttSpec); if ($oAttDef->IsExternalKey()) { $sTargetClass = $oAttDef->GetTargetClass(); $sFilterDefName = 'PORTAL_TICKETS_SEARCH_FILTER_' . $sAttSpec; if (defined($sFilterDefName)) { try { $oFitlerWithParams = DBObjectSearch::FromOQL(constant($sFilterDefName)); $sFilterOQL = $oFitlerWithParams->ToOQL(true, $aFilterParams); $oAllowedValues = new DBObjectSet(DBObjectSearch::FromOQL($sFilterOQL), array(), $aFilterParams); } catch (OQLException $e) { throw new Exception("Incorrect filter '{$sFilterDefName}' for attribute '{$sAttcode}': " . $e->getMessage()); } } else { $oAllowedValues = new DBObjectSet(new DBObjectSearch($sTargetClass)); } $iFieldSize = $oAttDef->GetMaxSize(); $iMaxComboLength = $oAttDef->GetMaximumComboLength(); $this->add("<label>" . MetaModel::GetFilterLabel($sClass, $sAttSpec) . ":</label> "); //$oWidget = UIExtKeyWidget::DIsplayFromAttCode($sAttSpec, $sClass, $oAttDef->GetLabel(), $oAllowedValues, $sFilterValue, $sPrefix.$sFieldName, false, '', $sPrefix, ''); //$this->add($oWidget->Display($this, $aExtraParams, true /* bSearchMode */)); $aExtKeyParams = $aExtraParams; $aExtKeyParams['iFieldSize'] = $oAttDef->GetMaxSize(); $aExtKeyParams['iMinChars'] = $oAttDef->GetMinAutoCompleteChars(); // DisplayFromAttCode($this, $sAttCode, $sClass, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName = '', $sFormPrefix = '', $aArgs, $bSearchMode = false) $sHtml = UIExtKeyWidget::DisplayFromAttCode($this, $sAttSpec, $sClass, $oAttDef->GetLabel(), $oAllowedValues, $sFilterValue, $sPrefix . $sFieldName, false, $sPrefix . $sFieldName, $sPrefix, $aExtKeyParams, true); $this->add($sHtml); } else { $aAllowedValues = MetaModel::GetAllowedValues_flt($sClass, $sAttSpec, $aExtraParams); if (is_null($aAllowedValues)) { // Any value is possible, display an input box $sSanitizedValue = htmlentities($sFilterValue, ENT_QUOTES, 'UTF-8'); $this->add("<label>" . MetaModel::GetFilterLabel($sClass, $sAttSpec) . ":</label> <input class=\"textSearch\" name=\"{$sPrefix}{$sFieldName}\" value=\"{$sSanitizedValue}\"/>\n"); } else { //Enum field or external key, display a combo $sValue = "<select name=\"{$sPrefix}{$sFieldName}\">\n"; $sValue .= "<option value=\"\">" . Dict::S('UI:SearchValue:Any') . "</option>\n"; foreach ($aAllowedValues as $key => $value) { if ($sFilterValue == $key) { $sSelected = ' selected'; } else { $sSelected = ''; } $sValue .= "<option value=\"{$key}\"{$sSelected}>{$value}</option>\n"; } $sValue .= "</select>\n"; $this->add("<label>" . MetaModel::GetFilterLabel($sClass, $sAttSpec) . ":</label> {$sValue}\n"); } } unset($aExtraParams[$sFieldName]); $this->add('</span> '); $sTip = $oAttDef->GetHelpOnSmartSearch(); if (strlen($sTip) > 0) { $sTip = addslashes($sTip); $sTip = str_replace(array("\n", "\r"), " ", $sTip); // :input does represent in form visible input (INPUT, SELECT, TEXTAREA) $this->add_ready_script("\$(':input[name={$sPrefix}{$sFieldName}]').qtip( { content: '{$sTip}', show: 'mouseover', hide: 'mouseout', style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );"); } } }
/** * 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; }
if ($oObj->IsNew()) { $iFlags = $oObj->GetInitialStateAttributeFlags($sAttCode); } else { $iFlags = $oObj->GetAttributeFlags($sAttCode); } if ($iFlags & OPT_ATT_READONLY) { $sHTMLValue = "<span id=\"field_{$sId}\">" . $oObj->GetAsHTML($sAttCode); $sHTMLValue .= '<input type="hidden" id="' . $sId . '" name="attr_' . $sFormPrefix . $sAttCode . '" value="' . htmlentities($oObj->Get($sAttCode), ENT_QUOTES, 'UTF-8') . '"/></span>'; $oWizardHelper->SetAllowedValuesHtml($sAttCode, $sHTMLValue); } else { // It may happen that the field we'd like to update does not // exist in the form. For example, if the field should be hidden/read-only // in the current state of the object $value = $oObj->Get($sAttCode); $displayValue = $oObj->GetEditValue($sAttCode); $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); if (!$oAttDef->IsWritable()) { // Even non-writable fields (like AttributeExternal) can be refreshed $sHTMLValue = $oObj->GetAsHTML($sAttCode); } else { $iFlags = MetaModel::GetAttributeFlags($sClass, $oObj->GetState(), $sAttCode); $sHTMLValue = cmdbAbstractObject::GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef, $value, $displayValue, $sId, '', $iFlags, array('this' => $oObj, 'formPrefix' => $sFormPrefix)); // Make sure that we immediately validate the field when we reload it $oPage->add_ready_script("\$('#{$sId}').trigger('validate');"); } $oWizardHelper->SetAllowedValuesHtml($sAttCode, $sHTMLValue); } } } $oPage->add_script("oWizardHelper{$sFormPrefix}.m_oData=" . $oWizardHelper->ToJSON() . ";\noWizardHelper{$sFormPrefix}.UpdateFields();\n"); break;
function DisplayBareRelations(WebPage $oPage, $bEditMode = false) { parent::DisplayBareRelations($oPage, $bEditMode); $sTicketListAttCode = 'tickets_list'; if (MetaModel::IsValidAttCode(get_class($this), $sTicketListAttCode)) { // Display one list per leaf class (the only way to display the status as of now) $oAttDef = MetaModel::GetAttributeDef(get_class($this), $sTicketListAttCode); $sLnkClass = $oAttDef->GetLinkedClass(); $sExtKeyToMe = $oAttDef->GetExtKeyToMe(); $sExtKeyToRemote = $oAttDef->GetExtKeyToRemote(); $iTotal = 0; $aSearches = array(); foreach (MetaModel::EnumChildClasses('Ticket') as $sSubClass) { if (!MetaModel::HasChildrenClasses($sSubClass)) { $sStateAttCode = MetaModel::GetStateAttributeCode($sSubClass); if ($sStateAttCode != '') { $oSearch = DBSearch::FromOQL("SELECT {$sSubClass} AS t JOIN {$sLnkClass} AS lnk ON lnk.{$sExtKeyToRemote} = t.id WHERE {$sExtKeyToMe} = :myself AND {$sStateAttCode} NOT IN ('rejected', 'resolved', 'closed')", array('myself' => $this->GetKey())); $aSearches[$sSubClass] = $oSearch; $oSet = new DBObjectSet($oSearch); $iTotal += $oSet->Count(); } } } $sCount = $iTotal > 0 ? ' (' . $iTotal . ')' : ''; $oPage->SetCurrentTab(Dict::S('Class:FunctionalCI/Tab:OpenedTickets') . $sCount); foreach ($aSearches as $sSubClass => $oSearch) { $sBlockId = __CLASS__ . '_opened_' . $sSubClass; $oPage->add('<fieldset>'); $oPage->add('<legend>' . MetaModel::GetName($sSubClass) . '</legend>'); $oBlock = new DisplayBlock($oSearch, 'list', false); $oBlock->Display($oPage, $sBlockId, array('menu' => false)); $oPage->add('</fieldset>'); } } }
public function GetDescription($sDefault = null) { $sLabel = parent::GetDescription(''); if (strlen($sLabel) == 0) { $sKeyAttCode = $this->Get("extkey_attcode"); if ($sKeyAttCode == 'id') { return Dict::S('Core:FriendlyName-Description'); } else { $oExtKeyAttDef = MetaModel::GetAttributeDef($this->GetHostClass(), $sKeyAttCode); $sLabel = $oExtKeyAttDef->GetDescription(''); } } return $sLabel; }
public function CheckProjectionSpec($oProjectionSpec, $sProjectedClass) { $sExpression = $oProjectionSpec->Get('value'); $sAttribute = $oProjectionSpec->Get('attribute'); // Shortcut: "any value" or "no value" means no projection if (empty($sExpression)) { return; } if ($sExpression == '<any>') { return; } // 1st - compute the data type for the dimension // $sType = $this->Get('type'); if (MetaModel::IsValidClass($sType)) { $sExpectedType = $sType; } else { $sExpectedType = '_scalar_'; } // 2nd - compute the data type for the projection // $sTargetClass = ''; if ($sExpression == '<this>' || $sExpression == '<user>') { $sTargetClass = $sProjectedClass; } elseif ($sExpression == '<any>') { $sTargetClass = ''; } else { // Evaluate wether it is a constant or not try { $oObjectSearch = DBObjectSearch::FromOQL_AllData($sExpression); $sTargetClass = $oObjectSearch->GetClass(); } catch (OqlException $e) { } } if (empty($sTargetClass)) { $sFoundType = '_void_'; } else { if (empty($sAttribute)) { $sFoundType = $sTargetClass; } else { if (!MetaModel::IsValidAttCode($sTargetClass, $sAttribute)) { throw new CoreException('Unkown attribute code in projection specification', array('found' => $sAttribute, 'expecting' => MetaModel::GetAttributesList($sTargetClass), 'class' => $sTargetClass, 'projection' => $oProjectionSpec)); } $oAttDef = MetaModel::GetAttributeDef($sTargetClass, $sAttribute); if ($oAttDef->IsExternalKey()) { $sFoundType = $oAttDef->GetTargetClass(); } else { $sFoundType = '_scalar_'; } } } // Compare the dimension type and projection type if ($sFoundType != '_void_' && $sFoundType != $sExpectedType) { throw new CoreException('Wrong type in projection specification', array('found' => $sFoundType, 'expecting' => $sExpectedType, 'expression' => $sExpression, 'attribute' => $sAttribute, 'projection' => $oProjectionSpec)); } }
/** * Create form to apply a stimulus * @param WebPage $oP The current web page * @param Object $oObj The target object * @param String $sStimulusCode Stimulus that will be applied * @param Array $aEditAtt List of attributes to edit * @return void */ function MakeStimulusForm(WebPage $oP, $oObj, $sStimulusCode, $aEditAtt) { static $bHasStimulusForm = false; $sDialogId = $sStimulusCode . "_dialog"; $sFormId = $sStimulusCode . "_form"; $sCancelButtonLabel = Dict::S('UI:Button:Cancel'); $oP->add('<div id="' . $sDialogId . '" style="display: none;">'); $sClass = get_class($oObj); $oP->add('<form id="' . $sFormId . '" method="post">'); $sTransactionId = utils::GetNewTransactionId(); $oP->add("<input type=\"hidden\" id=\"transaction_id\" name=\"transaction_id\" value=\"{$sTransactionId}\">\n"); $oP->add("<input type=\"hidden\" name=\"class\" value=\"{$sClass}\">"); $oP->add("<input type=\"hidden\" name=\"id\" value=\"" . $oObj->GetKey() . "\">"); $oP->add("<input type=\"hidden\" name=\"operation\" value=\"update_request\">"); $oP->add("<input type=\"hidden\" id=\"stimulus_to_apply\" name=\"apply_stimulus\" value=\"{$sStimulusCode}\">\n"); foreach ($aEditAtt as $sAttCode) { $sValue = $oObj->Get($sAttCode); $sDisplayValue = $oObj->GetEditValue($sAttCode); $aArgs = array('this' => $oObj, 'formPrefix' => ''); $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); $sInputId = 'input_' . $sAttCode; $sHTMLValue = "<span id=\"field_{$sStimulusCode}_{$sInputId}\">" . cmdbAbstractObject::GetFormElementForField($oP, $sClass, $sAttCode, $oAttDef, $sValue, $sDisplayValue, $sInputId, '', 0, $aArgs) . '</span>'; $oP->add('<h1>' . MetaModel::GetLabel($sClass, $sAttCode) . '</h1>'); $oP->add($sHTMLValue); } $oP->add('</form>'); $oP->add('</div>'); if (!$bHasStimulusForm) { $bHasStimulusForm = true; $oP->add_script(<<<EOF function RunStimulusDialog(sStimulusCode, sTitle, sOkButtonLabel) { \tvar sWidth = 'auto'; \tif (sStimulusCode == 'ev_reopen') \t{ \t\t// Avoid having a dialog spanning the complete width of the window \t\t// just because it contains a CaseLog entry \t\tsWidth = '80%'; \t} \t\t\t\t \t\$('#'+sStimulusCode+'_dialog').dialog({ \t\theight: 'auto', \t\twidth: sWidth, \t\tmodal: true, \t\ttitle: sTitle, \t\tbuttons: [ \t\t{ text: sOkButtonLabel, click: function() { \t\t\t\$(this).find('#'+sStimulusCode+'_form').submit(); \t\t} }, \t\t{ text: "{$sCancelButtonLabel}", click: function() { \t\t\t\$(this).dialog( "close" ); \t\t} } \t\t] \t}); \t// Start the validation \tCheckFields(sStimulusCode+'_form', false); \t\$('#'+sStimulusCode+'_form').submit( function() { \t\treturn OnSubmit(sStimulusCode+'_form'); \t}); } EOF ); } }
/** * Interpret the Rest/Json value and get a valid attribute value * * @param string $sClass Name of the class * @param string $sAttCode Attribute code * @param mixed $value Depending on the type of attribute (a scalar, or search criteria, or list of related objects...) * @return mixed The value that can be used with DBObject::Set() * @throws Exception If the specification of the value is not valid. * @api */ public static function MakeValue($sClass, $sAttCode, $value) { try { if (!MetaModel::IsValidAttCode($sClass, $sAttCode)) { throw new Exception("Unknown attribute"); } $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); if ($oAttDef instanceof AttributeExternalKey) { $oExtKeyObject = static::FindObjectFromKey($oAttDef->GetTargetClass(), $value, true); $value = $oExtKeyObject != null ? $oExtKeyObject->GetKey() : 0; } elseif ($oAttDef instanceof AttributeLinkedSet) { if (!is_array($value)) { throw new Exception("A link set must be defined by an array of objects"); } $sLnkClass = $oAttDef->GetLinkedClass(); $aLinks = array(); foreach ($value as $oValues) { $oLnk = static::MakeObjectFromFields($sLnkClass, $oValues); $aLinks[] = $oLnk; } $value = DBObjectSet::FromArray($sLnkClass, $aLinks); } else { $value = $oAttDef->FromJSONToValue($value); } } catch (Exception $e) { throw new Exception("{$sAttCode}: " . $e->getMessage(), $e->getCode()); } return $value; }
public static function FromLinkSet($oObject, $sLinkSetAttCode, $sExtKeyToRemote) { $oLinkAttCode = MetaModel::GetAttributeDef(get_class($oObject), $sLinkSetAttCode); $oExtKeyAttDef = MetaModel::GetAttributeDef($oLinkAttCode->GetLinkedClass(), $sExtKeyToRemote); $sTargetClass = $oExtKeyAttDef->GetTargetClass(); $oLinkSet = $oObject->Get($sLinkSetAttCode); $aTargets = array(); while ($oLink = $oLinkSet->Fetch()) { $aTargets[] = MetaModel::GetObject($sTargetClass, $oLink->Get($sExtKeyToRemote)); } return self::FromArray($sTargetClass, $aTargets); }
protected function MakeSQLObjectQuerySingleTable(&$oBuild, $aAttToLoad, $sTableClass, $aExtKeys, $aValues) { // $aExtKeys is an array of sTableClass => array of (sAttCode (keys) => array of sAttCode (fields)) //echo "MakeSQLObjectQuery($sTableClass)-liste des clefs externes($sTableClass): <pre>".print_r($aExtKeys, true)."</pre><br/>\n"; // Prepare the query for a single table (compound objects) // Ignores the items (attributes/filters) that are not on the target table // Perform an (inner or left) join for every external key (and specify the expected fields) // // Returns an SQLQuery // $sTargetClass = $this->GetFirstJoinedClass(); $sTargetAlias = $this->GetFirstJoinedClassAlias(); $sTable = MetaModel::DBGetTable($sTableClass); $sTableAlias = $oBuild->GenerateTableAlias($sTargetAlias . '_' . $sTable, $sTable); $aTranslation = array(); $aExpectedAtts = array(); $oBuild->m_oQBExpressions->GetUnresolvedFields($sTargetAlias, $aExpectedAtts); $bIsOnQueriedClass = array_key_exists($sTargetAlias, $oBuild->GetRootFilter()->GetSelectedClasses()); self::DbgTrace("Entering: tableclass={$sTableClass}, filter=" . $this->ToOQL() . ", " . ($bIsOnQueriedClass ? "MAIN" : "SECONDARY")); // 1 - SELECT and UPDATE // // Note: no need for any values nor fields for foreign Classes (ie not the queried Class) // $aUpdateValues = array(); // 1/a - Get the key and friendly name // // We need one pkey to be the key, let's take the first one available $oSelectedIdField = null; $oIdField = new FieldExpressionResolved(MetaModel::DBGetKey($sTableClass), $sTableAlias); $aTranslation[$sTargetAlias]['id'] = $oIdField; if ($bIsOnQueriedClass) { // Add this field to the list of queried fields (required for the COUNT to work fine) $oSelectedIdField = $oIdField; } // 1/b - Get the other attributes // foreach (MetaModel::ListAttributeDefs($sTableClass) as $sAttCode => $oAttDef) { // Skip this attribute if not defined in this table if (MetaModel::GetAttributeOrigin($sTargetClass, $sAttCode) != $sTableClass) { continue; } // Skip this attribute if not made of SQL columns if (count($oAttDef->GetSQLExpressions()) == 0) { continue; } // Update... // if ($bIsOnQueriedClass && array_key_exists($sAttCode, $aValues)) { assert($oAttDef->IsDirectField()); foreach ($oAttDef->GetSQLValues($aValues[$sAttCode]) as $sColumn => $sValue) { $aUpdateValues[$sColumn] = $sValue; } } } // 2 - The SQL query, for this table only // $oSelectBase = new SQLObjectQuery($sTable, $sTableAlias, array(), $bIsOnQueriedClass, $aUpdateValues, $oSelectedIdField); // 3 - Resolve expected expressions (translation table: alias.attcode => table.column) // foreach (MetaModel::ListAttributeDefs($sTableClass) as $sAttCode => $oAttDef) { // Skip this attribute if not defined in this table if (MetaModel::GetAttributeOrigin($sTargetClass, $sAttCode) != $sTableClass) { continue; } // Select... // if ($oAttDef->IsExternalField()) { // skip, this will be handled in the joined tables (done hereabove) } else { //echo "<p>MakeSQLObjectQuerySingleTable: Field $sAttCode is part of the table $sTable (named: $sTableAlias)</p>"; // standard field, or external key // add it to the output foreach ($oAttDef->GetSQLExpressions() as $sColId => $sSQLExpr) { if (array_key_exists($sAttCode . $sColId, $aExpectedAtts)) { $oFieldSQLExp = new FieldExpressionResolved($sSQLExpr, $sTableAlias); foreach (MetaModel::EnumPlugins('iQueryModifier') as $sPluginClass => $oQueryModifier) { $oFieldSQLExp = $oQueryModifier->GetFieldExpression($oBuild, $sTargetClass, $sAttCode, $sColId, $oFieldSQLExp, $oSelectBase); } $aTranslation[$sTargetAlias][$sAttCode . $sColId] = $oFieldSQLExp; } } } } //echo "MakeSQLObjectQuery- Classe $sTableClass<br/>\n"; // 4 - The external keys -> joins... // $aAllPointingTo = $this->GetCriteria_PointingTo(); if (array_key_exists($sTableClass, $aExtKeys)) { foreach ($aExtKeys[$sTableClass] as $sKeyAttCode => $aExtFields) { $oKeyAttDef = MetaModel::GetAttributeDef($sTableClass, $sKeyAttCode); $aPointingTo = $this->GetCriteria_PointingTo($sKeyAttCode); //echo "MakeSQLObjectQuery-Cle '$sKeyAttCode'<br/>\n"; if (!array_key_exists(TREE_OPERATOR_EQUALS, $aPointingTo)) { //echo "MakeSQLObjectQuery-Ajoutons l'operateur TREE_OPERATOR_EQUALS pour $sKeyAttCode<br/>\n"; // The join was not explicitely defined in the filter, // we need to do it now $sKeyClass = $oKeyAttDef->GetTargetClass(); $sKeyClassAlias = $oBuild->GenerateClassAlias($sKeyClass . '_' . $sKeyAttCode, $sKeyClass); $oExtFilter = new DBObjectSearch($sKeyClass, $sKeyClassAlias); $aAllPointingTo[$sKeyAttCode][TREE_OPERATOR_EQUALS][$sKeyClassAlias] = $oExtFilter; } } } //echo "MakeSQLObjectQuery-liste des clefs de jointure: <pre>".print_r(array_keys($aAllPointingTo), true)."</pre><br/>\n"; foreach ($aAllPointingTo as $sKeyAttCode => $aPointingTo) { foreach ($aPointingTo as $iOperatorCode => $aFilter) { foreach ($aFilter as $oExtFilter) { if (!MetaModel::IsValidAttCode($sTableClass, $sKeyAttCode)) { continue; } // Not defined in the class, skip it // The aliases should not conflict because normalization occured while building the filter $oKeyAttDef = MetaModel::GetAttributeDef($sTableClass, $sKeyAttCode); $sKeyClass = $oExtFilter->GetFirstJoinedClass(); $sKeyClassAlias = $oExtFilter->GetFirstJoinedClassAlias(); //echo "MakeSQLObjectQuery-$sTableClass::$sKeyAttCode Foreach PointingTo($iOperatorCode) <span style=\"color:red\">$sKeyClass (alias:$sKeyClassAlias)</span><br/>\n"; // Note: there is no search condition in $oExtFilter, because normalization did merge the condition onto the top of the filter tree //echo "MakeSQLObjectQuery-array_key_exists($sTableClass, \$aExtKeys)<br/>\n"; if ($iOperatorCode == TREE_OPERATOR_EQUALS) { if (array_key_exists($sTableClass, $aExtKeys) && array_key_exists($sKeyAttCode, $aExtKeys[$sTableClass])) { // Specify expected attributes for the target class query // ... and use the current alias ! $aTranslateNow = array(); // Translation for external fields - must be performed before the join is done (recursion...) foreach ($aExtKeys[$sTableClass][$sKeyAttCode] as $sAttCode => $oAtt) { //echo "MakeSQLObjectQuery aExtKeys[$sTableClass][$sKeyAttCode] => $sAttCode-oAtt: <pre>".print_r($oAtt, true)."</pre><br/>\n"; if ($oAtt instanceof AttributeFriendlyName) { // Note: for a given ext key, there is one single attribute "friendly name" $aTranslateNow[$sTargetAlias][$sAttCode] = new FieldExpression('friendlyname', $sKeyClassAlias); //echo "<p><b>aTranslateNow[$sTargetAlias][$sAttCode] = new FieldExpression('friendlyname', $sKeyClassAlias);</b></p>\n"; } else { $sExtAttCode = $oAtt->GetExtAttCode(); // Translate mainclass.extfield => remoteclassalias.remotefieldcode $oRemoteAttDef = MetaModel::GetAttributeDef($sKeyClass, $sExtAttCode); foreach ($oRemoteAttDef->GetSQLExpressions() as $sColId => $sRemoteAttExpr) { $aTranslateNow[$sTargetAlias][$sAttCode . $sColId] = new FieldExpression($sExtAttCode, $sKeyClassAlias); //echo "<p><b>aTranslateNow[$sTargetAlias][$sAttCode.$sColId] = new FieldExpression($sExtAttCode, $sKeyClassAlias);</b></p>\n"; } //echo "<p><b>ExtAttr2: $sTargetAlias.$sAttCode to $sKeyClassAlias.$sRemoteAttExpr (class: $sKeyClass)</b></p>\n"; } } if ($oKeyAttDef instanceof AttributeObjectKey) { // Add the condition: `$sTargetAlias`.$sClassAttCode IN (subclasses of $sKeyClass') $sClassAttCode = $oKeyAttDef->Get('class_attcode'); $oClassAttDef = MetaModel::GetAttributeDef($sTargetClass, $sClassAttCode); foreach ($oClassAttDef->GetSQLExpressions() as $sColId => $sSQLExpr) { $aTranslateNow[$sTargetAlias][$sClassAttCode . $sColId] = new FieldExpressionResolved($sSQLExpr, $sTableAlias); } $oClassListExpr = ListExpression::FromScalars(MetaModel::EnumChildClasses($sKeyClass, ENUM_CHILD_CLASSES_ALL)); $oClassExpr = new FieldExpression($sClassAttCode, $sTargetAlias); $oClassRestriction = new BinaryExpression($oClassExpr, 'IN', $oClassListExpr); $oBuild->m_oQBExpressions->AddCondition($oClassRestriction); } // Translate prior to recursing // //echo "<p>oQBExpr ".__LINE__.": <pre>\n".print_r($oBuild->m_oQBExpressions, true)."\n".print_r($aTranslateNow, true)."</pre></p>\n"; $oBuild->m_oQBExpressions->Translate($aTranslateNow, false); //echo "<p>oQBExpr ".__LINE__.": <pre>\n".print_r($oBuild->m_oQBExpressions, true)."</pre></p>\n"; //echo "<p>External key $sKeyAttCode (class: $sKeyClass), call MakeSQLObjectQuery()/p>\n"; self::DbgTrace("External key {$sKeyAttCode} (class: {$sKeyClass}), call MakeSQLObjectQuery()"); $oBuild->m_oQBExpressions->PushJoinField(new FieldExpression('id', $sKeyClassAlias)); //echo "<p>Recursive MakeSQLObjectQuery ".__LINE__.": <pre>\n".print_r($oBuild->GetRootFilter()->GetSelectedClasses(), true)."</pre></p>\n"; $oSelectExtKey = $oExtFilter->MakeSQLObjectQuery($oBuild, $aAttToLoad); $oJoinExpr = $oBuild->m_oQBExpressions->PopJoinField(); $sExternalKeyTable = $oJoinExpr->GetParent(); $sExternalKeyField = $oJoinExpr->GetName(); $aCols = $oKeyAttDef->GetSQLExpressions(); // Workaround a PHP bug: sometimes issuing a Notice if invoking current(somefunc()) $sLocalKeyField = current($aCols); // get the first column for an external key self::DbgTrace("External key {$sKeyAttCode}, Join on {$sLocalKeyField} = {$sExternalKeyField}"); if ($oKeyAttDef->IsNullAllowed()) { $oSelectBase->AddLeftJoin($oSelectExtKey, $sLocalKeyField, $sExternalKeyField, $sExternalKeyTable); } else { $oSelectBase->AddInnerJoin($oSelectExtKey, $sLocalKeyField, $sExternalKeyField, $sExternalKeyTable); } } } elseif (MetaModel::GetAttributeOrigin($sKeyClass, $sKeyAttCode) == $sTableClass) { $oBuild->m_oQBExpressions->PushJoinField(new FieldExpression($sKeyAttCode, $sKeyClassAlias)); $oSelectExtKey = $oExtFilter->MakeSQLObjectQuery($oBuild, $aAttToLoad); $oJoinExpr = $oBuild->m_oQBExpressions->PopJoinField(); $sExternalKeyTable = $oJoinExpr->GetParent(); $sExternalKeyField = $oJoinExpr->GetName(); $sLeftIndex = $sExternalKeyField . '_left'; // TODO use GetSQLLeft() $sRightIndex = $sExternalKeyField . '_right'; // TODO use GetSQLRight() $LocalKeyLeft = $oKeyAttDef->GetSQLLeft(); $LocalKeyRight = $oKeyAttDef->GetSQLRight(); $oSelectBase->AddInnerJoinTree($oSelectExtKey, $LocalKeyLeft, $LocalKeyRight, $sLeftIndex, $sRightIndex, $sExternalKeyTable, $iOperatorCode); } } } } // Translate the selected columns // //echo "<p>oQBExpr ".__LINE__.": <pre>\n".print_r($oBuild->m_oQBExpressions, true)."</pre></p>\n"; $oBuild->m_oQBExpressions->Translate($aTranslation, false); //echo "<p>oQBExpr ".__LINE__.": <pre>\n".print_r($oBuild->m_oQBExpressions, true)."</pre></p>\n"; //MyHelpers::var_dump_html($oSelectBase->RenderSelect()); return $oSelectBase; }
/** * 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; }
/** * Describe (as a text string) the modifications corresponding to this change */ public function GetDescription() { $sResult = ''; $oTargetObjectClass = $this->Get('objclass'); $oTargetObjectKey = $this->Get('objkey'); $oTargetSearch = new DBObjectSearch($oTargetObjectClass); $oTargetSearch->AddCondition('id', $oTargetObjectKey, '='); $oMonoObjectSet = new DBObjectSet($oTargetSearch); if (UserRights::IsActionAllowedOnAttribute($this->Get('objclass'), $this->Get('attcode'), UR_ACTION_READ, $oMonoObjectSet) == UR_ALLOWED_YES) { if (!MetaModel::IsValidAttCode($this->Get('objclass'), $this->Get('attcode'))) { return ''; } // Protects against renamed attributes... $oAttDef = MetaModel::GetAttributeDef($this->Get('objclass'), $this->Get('attcode')); $sAttName = $oAttDef->GetLabel(); $sLinkClass = $oAttDef->GetLinkedClass(); $aLinkClasses = MetaModel::EnumChildClasses($sLinkClass, ENUM_CHILD_CLASSES_ALL); // Search for changes on the corresponding link // $oSearch = new DBObjectSearch('CMDBChangeOpSetAttribute'); $oSearch->AddCondition('change', $this->Get('change'), '='); $oSearch->AddCondition('objkey', $this->Get('link_id'), '='); if (count($aLinkClasses) == 1) { // Faster than the whole building of the expression below for just one value ?? $oSearch->AddCondition('objclass', $sLinkClass, '='); } else { $oField = new FieldExpression('objclass', $oSearch->GetClassAlias()); $sListExpr = '(' . implode(', ', CMDBSource::Quote($aLinkClasses)) . ')'; $sOQLCondition = $oField->Render() . " IN {$sListExpr}"; $oNewCondition = Expression::FromOQL($sOQLCondition); $oSearch->AddConditionExpression($oNewCondition); } $oSet = new DBObjectSet($oSearch); $aChanges = array(); while ($oChangeOp = $oSet->Fetch()) { $aChanges[] = $oChangeOp->GetDescription(); } if (count($aChanges) == 0) { return ''; } $sItemDesc = MetaModel::GetHyperLink($this->Get('item_class'), $this->Get('item_id')); $sResult = $sAttName . ' - '; $sResult .= Dict::Format('Change:LinkSet:Modified', $sItemDesc); $sResult .= ' : ' . implode(', ', $aChanges); } return $sResult; }
/** * Prepare structures in memory, to speedup the processing of a given replica */ public function PrepareProcessing($bFirstPass = true) { if ($this->m_oDataSource->Get('status') == 'obsolete') { throw new SynchroExceptionNotStarted(Dict::S('Core:SyncDataSourceObsolete')); } if (!UserRights::IsAdministrator() && $this->m_oDataSource->Get('user_id') != UserRights::GetUserId()) { throw new SynchroExceptionNotStarted(Dict::S('Core:SyncDataSourceAccessRestriction')); } // Get the list of SQL columns $sClass = $this->m_oDataSource->GetTargetClass(); $aAttCodesExpected = array(); $aAttCodesToReconcile = array(); $aAttCodesToUpdate = array(); $sSelectAtt = "SELECT SynchroAttribute WHERE sync_source_id = :source_id AND (update = 1 OR reconcile = 1)"; $oSetAtt = new DBObjectSet(DBObjectSearch::FromOQL($sSelectAtt), array(), array('source_id' => $this->m_oDataSource->GetKey())); while ($oSyncAtt = $oSetAtt->Fetch()) { if ($oSyncAtt->Get('update')) { $aAttCodesToUpdate[$oSyncAtt->Get('attcode')] = $oSyncAtt; } if ($oSyncAtt->Get('reconcile')) { $aAttCodesToReconcile[$oSyncAtt->Get('attcode')] = $oSyncAtt; } $aAttCodesExpected[$oSyncAtt->Get('attcode')] = $oSyncAtt; } $aColumns = $this->m_oDataSource->GetSQLColumns(array_keys($aAttCodesExpected)); $aExtDataFields = array_keys($aColumns); $aExtDataFields[] = 'primary_key'; $this->m_aExtDataSpec = array('table' => $this->m_oDataSource->GetDataTable(), 'join_key' => 'id', 'fields' => $aExtDataFields); // Get the list of attributes, determine reconciliation keys and update targets // if ($this->m_oDataSource->Get('reconciliation_policy') == 'use_attributes') { $this->m_aReconciliationKeys = $aAttCodesToReconcile; } elseif ($this->m_oDataSource->Get('reconciliation_policy') == 'use_primary_key') { // Override the settings made at the attribute level ! $this->m_aReconciliationKeys = array("primary_key" => null); } if ($bFirstPass) { $this->m_oStatLog->AddTrace("Update of: {" . implode(', ', array_keys($aAttCodesToUpdate)) . "}"); $this->m_oStatLog->AddTrace("Reconciliation on: {" . implode(', ', array_keys($this->m_aReconciliationKeys)) . "}"); } if (count($aAttCodesToUpdate) == 0) { $this->m_oStatLog->AddTrace("No attribute to update"); throw new SynchroExceptionNotStarted('There is no attribute to update'); } if (count($this->m_aReconciliationKeys) == 0) { $this->m_oStatLog->AddTrace("No attribute for reconciliation"); throw new SynchroExceptionNotStarted('No attribute for reconciliation'); } $this->m_aAttributes = array(); foreach ($aAttCodesToUpdate as $sAttCode => $oSyncAtt) { $oAttDef = MetaModel::GetAttributeDef($this->m_oDataSource->GetTargetClass(), $sAttCode); if ($oAttDef->IsWritable()) { $this->m_aAttributes[$sAttCode] = $oSyncAtt; } } // Compute and keep track of the limit date taken into account for obsoleting replicas // if ($this->m_oLastFullLoadStartDate == null) { // No previous import known, use the full_load_periodicity value... and the current date $this->m_oLastFullLoadStartDate = new DateTime(); // Now $iLoadPeriodicity = $this->m_oDataSource->Get('full_load_periodicity'); // Duration in seconds if ($iLoadPeriodicity > 0) { $sInterval = "-{$iLoadPeriodicity} seconds"; $this->m_oLastFullLoadStartDate->Modify($sInterval); } else { $this->m_oLastFullLoadStartDate = new DateTime('1970-01-01'); } } if ($bFirstPass) { $this->m_oStatLog->AddTrace("Limit Date: " . $this->m_oLastFullLoadStartDate->Format('Y-m-d H:i:s')); } }
public function GetAttributeProperty($sClass, $sAttCode, $sPropName, $default = null) { $ret = $default; $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); $aParams = $oAttDef->GetParams(); if (array_key_exists($sPropName, $aParams)) { $ret = $aParams[$sPropName]; } if ($oAttDef instanceof AttributeHierarchicalKey) { if ($sPropName == 'targetclass') { $ret = $sClass; } } return $ret; }
/** * Compute the order of the fields & pages in the wizard * @param $oPage iTopWebPage The current page (used to display error messages) * @param $sClass string Name of the class * @param $sStateCode string Code of the target state of the object * @return hash Two dimensional array: each element represents the list of fields for a given page */ protected function ComputeWizardStructure() { $aWizardSteps = array('mandatory' => array(), 'optional' => array()); $aFieldsDone = array(); // Store all the fields that are already covered by a previous step of the wizard $aStates = MetaModel::EnumStates($this->m_sClass); $sStateAttCode = MetaModel::GetStateAttributeCode($this->m_sClass); $aMandatoryAttributes = array(); // Some attributes are always mandatory independently of the state machine (if any) foreach (MetaModel::GetAttributesList($this->m_sClass) as $sAttCode) { $oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode); if (!$oAttDef->IsExternalField() && !$oAttDef->IsNullAllowed() && $oAttDef->IsWritable() && $sAttCode != $sStateAttCode) { $aMandatoryAttributes[$sAttCode] = OPT_ATT_MANDATORY; } } // Now check the attributes that are mandatory in the specified state if (!empty($this->m_sTargetState) && count($aStates[$this->m_sTargetState]['attribute_list']) > 0) { // Check all the fields that *must* be included in the wizard for this // particular target state $aFields = array(); foreach ($aStates[$this->m_sTargetState]['attribute_list'] as $sAttCode => $iOptions) { if (isset($aMandatoryAttributes[$sAttCode]) && $aMandatoryAttributes[$sAttCode] & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT)) { $aMandatoryAttributes[$sAttCode] |= $iOptions; } else { $aMandatoryAttributes[$sAttCode] = $iOptions; } } } // Check all the fields that *must* be included in the wizard // i.e. all mandatory, must-change or must-prompt fields that are // not also read-only or hidden. // Some fields may be required (null not allowed) from the database // perspective, but hidden or read-only from the user interface perspective $aFields = array(); foreach ($aMandatoryAttributes as $sAttCode => $iOptions) { if ($iOptions & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT) && !($iOptions & (OPT_ATT_READONLY | OPT_ATT_HIDDEN))) { $oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode); $aPrerequisites = $oAttDef->GetPrerequisiteAttributes(); $aFields[$sAttCode] = array(); foreach ($aPrerequisites as $sCode) { $aFields[$sAttCode][$sCode] = ''; } } } // Now use the dependencies between the fields to order them // Start from the order of the 'details' $aList = MetaModel::FlattenZlist(MetaModel::GetZListItems($this->m_sClass, 'details')); $index = 0; $aOrder = array(); foreach ($aFields as $sAttCode => $void) { $aOrder[$sAttCode] = 999; // At the end of the list... } foreach ($aList as $sAttCode) { if (array_key_exists($sAttCode, $aFields)) { $aOrder[$sAttCode] = $index; } $index++; } foreach ($aFields as $sAttCode => $aDependencies) { // All fields with no remaining dependencies can be entered at this // step of the wizard if (count($aDependencies) > 0) { $iMaxPos = 0; // Remove this field from the dependencies of the other fields foreach ($aDependencies as $sDependentAttCode => $void) { // position the current field after the ones it depends on $iMaxPos = max($iMaxPos, 1 + $aOrder[$sDependentAttCode]); } } } asort($aOrder); $aCurrentStep = array(); foreach ($aOrder as $sAttCode => $rank) { $aCurrentStep[] = $sAttCode; $aFieldsDone[$sAttCode] = ''; } $aWizardSteps['mandatory'][] = $aCurrentStep; // Now computes the steps to fill the optional fields $aFields = array(); // reset foreach (MetaModel::ListAttributeDefs($this->m_sClass) as $sAttCode => $oAttDef) { $iOptions = isset($aStates[$this->m_sTargetState]['attribute_list'][$sAttCode]) ? $aStates[$this->m_sTargetState]['attribute_list'][$sAttCode] : 0; if ($sStateAttCode != $sAttCode && !$oAttDef->IsExternalField() && ($iOptions & (OPT_ATT_HIDDEN | OPT_ATT_READONLY)) == 0 && !isset($aFieldsDone[$sAttCode])) { // 'State', external fields, read-only and hidden fields // and fields that are already listed in the wizard // are removed from the 'optional' part of the wizard $oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode); $aPrerequisites = $oAttDef->GetPrerequisiteAttributes(); $aFields[$sAttCode] = array(); foreach ($aPrerequisites as $sCode) { if (!isset($aFieldsDone[$sCode])) { // retain only the dependencies that were not covered // in the 'mandatory' part of the wizard $aFields[$sAttCode][$sCode] = ''; } } } } // Now use the dependencies between the fields to order them while (count($aFields) > 0) { $aCurrentStep = array(); foreach ($aFields as $sAttCode => $aDependencies) { // All fields with no remaining dependencies can be entered at this // step of the wizard if (count($aDependencies) == 0) { $aCurrentStep[] = $sAttCode; $aFieldsDone[$sAttCode] = ''; unset($aFields[$sAttCode]); // Remove this field from the dependencies of the other fields foreach ($aFields as $sUpdatedCode => $aDummy) { // remove the dependency unset($aFields[$sUpdatedCode][$sAttCode]); } } } if (count($aCurrentStep) == 0) { // This step of the wizard would contain NO field ! $this->m_oPage->add(Dict::S('UI:Error:WizardCircularReferenceInDependencies')); print_r($aFields); break; } $aWizardSteps['optional'][] = $aCurrentStep; } return $aWizardSteps; }
/** * Find redundancy settings that can be viewed and modified in a tab * Settings are distributed to the corresponding link set attribute so as to be shown in the relevant tab */ protected function FindVisibleRedundancySettings() { $aRet = array(); foreach (MetaModel::ListAttributeDefs(get_class($this)) as $sAttCode => $oAttDef) { if ($oAttDef instanceof AttributeRedundancySettings) { if ($oAttDef->IsVisible()) { $aQueryInfo = $oAttDef->GetRelationQueryData(); if (isset($aQueryInfo['sAttribute'])) { $oUpperAttDef = MetaModel::GetAttributeDef($aQueryInfo['sFromClass'], $aQueryInfo['sAttribute']); $oHostAttDef = $oUpperAttDef->GetMirrorLinkAttribute(); if ($oHostAttDef) { $sHostAttCode = $oHostAttDef->GetCode(); $aRet[$sHostAttCode][] = $oAttDef; } } } } } return $aRet; }
/** * Get the form to create a new object of the 'target' class */ public function GetObjectCreationForm(WebPage $oPage, $oCurrObject) { // Set all the default values in an object and clone this "default" object $oNewObj = MetaModel::NewObject($this->sTargetClass); // 1st - set context values $oAppContext = new ApplicationContext(); $oAppContext->InitObjectFromContext($oNewObj); // 2nd set the default values from the constraint on the external key... if any if ($oCurrObject != null && $this->sAttCode != '') { $oAttDef = MetaModel::GetAttributeDef(get_class($oCurrObject), $this->sAttCode); $aParams = array('this' => $oCurrObject); $oSet = $oAttDef->GetAllowedValuesAsObjectSet($aParams); $aConsts = $oSet->ListConstantFields(); $sClassAlias = $oSet->GetFilter()->GetClassAlias(); if (isset($aConsts[$sClassAlias])) { foreach ($aConsts[$sClassAlias] as $sAttCode => $value) { $oNewObj->Set($sAttCode, $value); } } } // 3rd - set values from the page argument 'default' $oNewObj->UpdateObjectFromArg('default'); $sDialogTitle = ''; $oPage->add('<div id="ac_create_' . $this->iId . '"><div class="wizContainer" style="vertical-align:top;"><div id="dcr_' . $this->iId . '">'); $oPage->add("<h1>" . MetaModel::GetClassIcon($this->sTargetClass) . " " . Dict::Format('UI:CreationTitle_Class', MetaModel::GetName($this->sTargetClass)) . "</h1>\n"); cmdbAbstractObject::DisplayCreationForm($oPage, $this->sTargetClass, $oNewObj, array(), array('formPrefix' => $this->iId, 'noRelations' => true)); $oPage->add('</div></div></div>'); // $oPage->add_ready_script("\$('#ac_create_$this->iId').dialog({ width: $(window).width()*0.8, height: 'auto', autoOpen: false, modal: true, title: '$sDialogTitle'});\n"); $oPage->add_ready_script("\$('#ac_create_{$this->iId}').dialog({ width: 'auto', height: 'auto', maxHeight: \$(window).height() - 50, autoOpen: false, modal: true, title: '{$sDialogTitle}'});\n"); $oPage->add_ready_script("\$('#dcr_{$this->iId} form').removeAttr('onsubmit');"); $oPage->add_ready_script("\$('#dcr_{$this->iId} form').bind('submit.uilinksWizard', oACWidget_{$this->iId}.DoCreateObject);"); }
/** * Helper to modify an enum value * The change is made in the datamodel definition, but the value has to be changed in the DB as well * Must be called BEFORE DB update, i.e within an implementation of BeforeDatabaseCreation() * This helper does change ONE value at a time * * @param string $sClass A valid class name * @param string $sAttCode The enum attribute code * @param string $sFrom Original value (already INVALID in the current datamodel) * @param string $sTo New value (valid in the current datamodel) * @return void */ public static function RenameEnumValueInDB($sClass, $sAttCode, $sFrom, $sTo) { try { $sOriginClass = MetaModel::GetAttributeOrigin($sClass, $sAttCode); $sTableName = MetaModel::DBGetTable($sOriginClass); $oAttDef = MetaModel::GetAttributeDef($sOriginClass, $sAttCode); if ($oAttDef instanceof AttributeEnum) { $oValDef = $oAttDef->GetValuesDef(); if ($oValDef) { $aNewValues = array_keys($oValDef->GetValues(array(), "")); if (in_array($sTo, $aNewValues)) { $sEnumCol = $oAttDef->Get("sql"); $aFields = CMDBSource::QueryToArray("SHOW COLUMNS FROM `{$sTableName}` WHERE Field = '{$sEnumCol}'"); if (isset($aFields[0]['Type'])) { $sColType = $aFields[0]['Type']; // Note: the parsing should rely on str_getcsv (requires PHP 5.3) to cope with escaped string if (preg_match("/^enum\\(\\'(.*)\\'\\)\$/", $sColType, $aMatches)) { $aCurrentValues = explode("','", $aMatches[1]); } } if (!in_array($sFrom, $aNewValues)) { if (!in_array($sTo, $aCurrentValues)) { $sNullSpec = $oAttDef->IsNullAllowed() ? 'NULL' : 'NOT NULL'; if (strtolower($sTo) == strtolower($sFrom)) { SetupPage::log_info("Changing enum in DB - {$sClass}::{$sAttCode} from '{$sFrom}' to '{$sTo}' (just a change in the case)"); $aTargetValues = array(); foreach ($aCurrentValues as $sValue) { if ($sValue == $sFrom) { $sValue = $sTo; } $aTargetValues[] = $sValue; } $sColumnDefinition = "ENUM(" . implode(",", CMDBSource::Quote($aTargetValues)) . ") {$sNullSpec}"; $sRepair = "ALTER TABLE `{$sTableName}` MODIFY `{$sEnumCol}` {$sColumnDefinition}"; CMDBSource::Query($sRepair); } else { // 1st - Allow both values in the column definition // SetupPage::log_info("Changing enum in DB - {$sClass}::{$sAttCode} from '{$sFrom}' to '{$sTo}'"); $aAllValues = $aCurrentValues; $aAllValues[] = $sTo; $sColumnDefinition = "ENUM(" . implode(",", CMDBSource::Quote($aAllValues)) . ") {$sNullSpec}"; $sRepair = "ALTER TABLE `{$sTableName}` MODIFY `{$sEnumCol}` {$sColumnDefinition}"; CMDBSource::Query($sRepair); // 2nd - Change the old value into the new value // $sRepair = "UPDATE `{$sTableName}` SET `{$sEnumCol}` = '{$sTo}' WHERE `{$sEnumCol}` = BINARY '{$sFrom}'"; CMDBSource::Query($sRepair); $iAffectedRows = CMDBSource::AffectedRows(); SetupPage::log_info("Changing enum in DB - {$iAffectedRows} rows updated"); // 3rd - Remove the useless value from the column definition // $aTargetValues = array(); foreach ($aCurrentValues as $sValue) { if ($sValue == $sFrom) { $sValue = $sTo; } $aTargetValues[] = $sValue; } $sColumnDefinition = "ENUM(" . implode(",", CMDBSource::Quote($aTargetValues)) . ") {$sNullSpec}"; $sRepair = "ALTER TABLE `{$sTableName}` MODIFY `{$sEnumCol}` {$sColumnDefinition}"; CMDBSource::Query($sRepair); SetupPage::log_info("Changing enum in DB - removed useless value '{$sFrom}'"); } } } else { SetupPage::log_warning("Changing enum in DB - {$sClass}::{$sAttCode} - '{$sFrom}' is still a valid value (" . implode(', ', $aNewValues) . ")"); } } else { SetupPage::log_warning("Changing enum in DB - {$sClass}::{$sAttCode} - '{$sTo}' is not a known value (" . implode(', ', $aNewValues) . ")"); } } } } catch (Exception $e) { SetupPage::log_warning("Changing enum in DB - {$sClass}::{$sAttCode} - '{$sTo}' failed. Reason " . $e->getMessage()); } }
/** * @param hash $aOrderBy Array of '[<classalias>.]attcode' => bAscending */ public function MakeSelectQuery($aOrderBy = array(), $aArgs = array(), $aAttToLoad = null, $aExtendedDataSpec = null, $iLimitCount = 0, $iLimitStart = 0, $bGetCount = false) { // Check the order by specification, and prefix with the class alias // and make sure that the ordering columns are going to be selected // $sClass = $this->GetClass(); $sClassAlias = $this->GetClassAlias(); $aOrderSpec = array(); foreach ($aOrderBy as $sFieldAlias => $bAscending) { if (!is_bool($bAscending)) { throw new CoreException("Wrong direction in ORDER BY spec, found '{$bAscending}' and expecting a boolean value"); } $iDotPos = strpos($sFieldAlias, '.'); if ($iDotPos === false) { $sAttClass = $sClass; $sAttClassAlias = $sClassAlias; $sAttCode = $sFieldAlias; } else { $sAttClassAlias = substr($sFieldAlias, 0, $iDotPos); $sAttClass = $this->GetClassName($sAttClassAlias); $sAttCode = substr($sFieldAlias, $iDotPos + 1); } if ($sAttCode != 'id') { MyHelpers::CheckValueInArray('field name in ORDER BY spec', $sAttCode, MetaModel::GetAttributesList($sAttClass)); $oAttDef = MetaModel::GetAttributeDef($sAttClass, $sAttCode); foreach ($oAttDef->GetOrderBySQLExpressions($sAttClassAlias) as $sSQLExpression) { $aOrderSpec[$sSQLExpression] = $bAscending; } } else { $aOrderSpec['`' . $sAttClassAlias . $sAttCode . '`'] = $bAscending; } // Make sure that the columns used for sorting are present in the loaded columns if (!is_null($aAttToLoad) && !isset($aAttToLoad[$sAttClassAlias][$sAttCode])) { $aAttToLoad[$sAttClassAlias][$sAttCode] = MetaModel::GetAttributeDef($sAttClass, $sAttCode); } } $oSQLQuery = $this->GetSQLQuery($aOrderBy, $aArgs, $aAttToLoad, $aExtendedDataSpec, $iLimitCount, $iLimitStart, $bGetCount); $aScalarArgs = array_merge(MetaModel::PrepareQueryArguments($aArgs), $this->GetInternalParams()); try { $bBeautifulSQL = self::$m_bTraceQueries || self::$m_bDebugQuery || self::$m_bIndentQueries; $sRes = $oSQLQuery->RenderSelect($aOrderSpec, $aScalarArgs, $iLimitCount, $iLimitStart, $bGetCount, $bBeautifulSQL); if ($sClassAlias == '_itop_') { IssueLog::Info('SQL Query (_itop_): ' . $sRes); } } catch (MissingQueryArgument $e) { // Add some information... $e->addInfo('OQL', $this->ToOQL()); throw $e; } $this->AddQueryTraceSelect($aOrderBy, $aArgs, $aAttToLoad, $aExtendedDataSpec, $iLimitCount, $iLimitStart, $bGetCount, $sRes); return $sRes; }
/** * Helper function to build the mapping drop-down list for a field * Spec: Possible choices are "writable" fields in this class plus external fields that are listed as reconciliation keys * for any class pointed to by an external key in the current class. * If not in advanced mode, all "id" fields (id and external keys) must be mapped to ":none:" (i.e -- ignore this field --) * External fields that do not correspond to a reconciliation key must be mapped to ":none:" * Otherwise, if a field equals either the 'code' or the 'label' (translated) of a field, then it's mapped automatically * @param string $sClassName Name of the class used for the mapping * @param string $sFieldName Name of the field, as it comes from the data file (header line) * @param integer $iFieldIndex Number of the field in the sequence * @param bool $bAdvancedMode Whether or not advanced mode was chosen * @param string $sDefaultChoice If set, this will be the item selected by default * @return string The HTML code corresponding to the drop-down list for this field */ function GetMappingForField($sClassName, $sFieldName, $iFieldIndex, $bAdvancedMode, $sDefaultChoice) { $aChoices = array('' => Dict::S('UI:CSVImport:MappingSelectOne')); $aChoices[':none:'] = Dict::S('UI:CSVImport:MappingNotApplicable'); $sFieldCode = ''; // Code of the attribute, if there is a match $aMatches = array(); if (preg_match('/^(.+)\\*$/', $sFieldName, $aMatches)) { // Remove any trailing "star" character. // A star character at the end can be used to indicate a mandatory field $sFieldName = $aMatches[1]; } else { if (preg_match('/^(.+)\\*->(.+)$/', $sFieldName, $aMatches)) { // Remove any trailing "star" character before the arrow (->) // A star character at the end can be used to indicate a mandatory field $sFieldName = $aMatches[1] . '->' . $aMatches[2]; } } if ($sFieldName == 'id') { $sFieldCode = 'id'; } if ($bAdvancedMode) { $aChoices['id'] = Dict::S('UI:CSVImport:idField'); } foreach (MetaModel::ListAttributeDefs($sClassName) as $sAttCode => $oAttDef) { $sStar = ''; if ($oAttDef->IsExternalKey()) { if ($sFieldName == $oAttDef->GetLabel() || $sFieldName == $sAttCode) { $sFieldCode = $sAttCode; } if ($bAdvancedMode) { $aChoices[$sAttCode] = $oAttDef->GetLabel(); } $oExtKeyAttDef = MetaModel::GetAttributeDef($sClassName, $oAttDef->GetKeyAttCode()); if (!$oExtKeyAttDef->IsNullAllowed()) { $sStar = '*'; } // Get fields of the external class that are considered as reconciliation keys $sTargetClass = $oAttDef->GetTargetClass(); foreach (MetaModel::ListAttributeDefs($sTargetClass) as $sTargetAttCode => $oTargetAttDef) { if (MetaModel::IsReconcKey($sTargetClass, $sTargetAttCode)) { $bExtKey = $oTargetAttDef->IsExternalKey(); $sSuffix = ''; if ($bExtKey) { $sSuffix = '->id'; } if ($bAdvancedMode || !$bExtKey) { // When not in advanced mode do not allow to use reconciliation keys (on external keys) if they are themselves external keys ! $aChoices[$sAttCode . '->' . $sTargetAttCode] = MetaModel::GetLabel($sClassName, $sAttCode . '->' . $sTargetAttCode, true); if (strcasecmp($sFieldName, $oAttDef->GetLabel() . '->' . $oTargetAttDef->GetLabel() . $sSuffix) == 0 || strcasecmp($sFieldName, $sAttCode . '->' . $sTargetAttCode . $sSuffix) == 0) { $sFieldCode = $sAttCode . '->' . $sTargetAttCode; } } } } } else { if ($oAttDef->IsWritable() && (!$oAttDef->IsLinkset() || $bAdvancedMode && $oAttDef->IsIndirect())) { $aChoices[$sAttCode] = MetaModel::GetLabel($sClassName, $sAttCode, true); if ($sFieldName == $oAttDef->GetLabel() || $sFieldName == $sAttCode) { $sFieldCode = $sAttCode; } } } } asort($aChoices); $sHtml = "<select id=\"mapping_{$iFieldIndex}\" name=\"field[{$iFieldIndex}]\">\n"; $bIsIdField = IsIdField($sClassName, $sFieldCode); foreach ($aChoices as $sAttCode => $sLabel) { $sSelected = ''; if ($bIsIdField && !$bAdvancedMode) { if ($sAttCode == ':none:') { $sSelected = ' selected'; } } else { if (empty($sFieldCode) && strpos($sFieldName, '->') !== false) { if ($sAttCode == ':none:') { $sSelected = ' selected'; } } else { if (is_null($sDefaultChoice) && $sFieldCode == $sAttCode) { $sSelected = ' selected'; } else { if (!is_null($sDefaultChoice) && $sDefaultChoice == $sAttCode) { $sSelected = ' selected'; } } } } $sHtml .= "<option value=\"{$sAttCode}\"{$sSelected}>{$sLabel}</option>\n"; } $sHtml .= "</select>\n"; return $sHtml; }
public function GetHeader() { $sData = ''; $oSet = new DBObjectSet($this->oSearch); $this->aStatusInfo['status'] = 'running'; $this->aStatusInfo['position'] = 0; $this->aStatusInfo['total'] = $oSet->Count(); $aSelectedClasses = $this->oSearch->GetSelectedClasses(); foreach ($aSelectedClasses as $sAlias => $sClassName) { if (UserRights::IsActionAllowed($sClassName, UR_ACTION_BULK_READ, $oSet) && (UR_ALLOWED_YES || UR_ALLOWED_DEPENDS)) { $aAuthorizedClasses[$sAlias] = $sClassName; } } $aAliases = array_keys($aAuthorizedClasses); $aData = array(); foreach ($this->aStatusInfo['fields'] as $sExtendedAttCode) { if (preg_match('/^([^\\.]+)\\.(.+)$/', $sExtendedAttCode, $aMatches)) { $sAlias = $aMatches[1]; $sAttCode = $aMatches[2]; } else { $sAlias = reset($aAliases); $sAttCode = $sExtendedAttCode; } if (!in_array($sAlias, $aAliases)) { throw new Exception("Invalid alias '{$sAlias}' for the column '{$sExtendedAttCode}'. Availables aliases: '" . implode("', '", $aAliases) . "'"); } $sClass = $aSelectedClasses[$sAlias]; switch ($sAttCode) { case 'id': if (count($aSelectedClasses) > 1) { $aData[] = $sAlias . '.id'; //@@@ } else { $aData[] = 'id'; //@@@ } break; default: $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); if (count($aSelectedClasses) > 1) { $aData[] = $sAlias . '.' . $oAttDef->GetLabel(); } else { $aData[] = $oAttDef->GetLabel(); } } } $sData .= "<table class=\"listResults\">\n"; $sData .= "<thead>\n"; $sData .= "<tr>\n"; foreach ($aData as $sLabel) { $sData .= "<th>" . $sLabel . "</th>\n"; } $sData .= "</tr>\n"; $sData .= "</thead>\n"; $sData .= "<tbody>\n"; return $sData; }