* @author Romain Quetiez * @author Denis Flaven * @license http://www.opensource.org/licenses/gpl-3.0.html LGPL */ define('OBJECT_PROPERTIES_TAB', 'ObjectProperties'); define('HILIGHT_CLASS_CRITICAL', 'red'); define('HILIGHT_CLASS_WARNING', 'orange'); define('HILIGHT_CLASS_OK', 'green'); define('HILIGHT_CLASS_NONE', ''); require_once('../core/cmdbobject.class.inc.php'); require_once('../application/utils.inc.php'); require_once('../application/applicationcontext.class.inc.php'); require_once('../application/ui.linkswidget.class.inc.php'); abstract class cmdbAbstractObject extends CMDBObject { protected $m_iFormId; // The ID of the form used to edit the object (when in edition mode !) public static function GetUIPage() { return '../pages/UI.php'; } public static function ComputeUIPage($sClass) { static $aUIPagesCache = array(); // Cache to store the php page used to display each class of object if (!isset($aUIPagesCache[$sClass])) { $UIPage = false; if (is_callable("$sClass::GetUIPage")) { $UIPage = eval("return $sClass::GetUIPage();"); // May return false in case of error } $aUIPagesCache[$sClass] = $UIPage === false ? './UI.php' : $UIPage; } $sPage = $aUIPagesCache[$sClass]; return $sPage; } protected static function MakeHyperLink($sObjClass, $sObjKey, $aAvailableFields) { if ($sObjKey <= 0) return ''.Dict::S('UI:UndefinedObject').''; // Objects built in memory have negative IDs $oAppContext = new ApplicationContext(); $sExtClassNameAtt = MetaModel::GetNameAttributeCode($sObjClass); $sPage = self::ComputeUIPage($sObjClass); $sAbsoluteUrl = utils::GetAbsoluteUrl(false); // False => Don't get the query string $sAbsoluteUrl = substr($sAbsoluteUrl, 0, 1+strrpos($sAbsoluteUrl, '/')); // remove the current page, keep just the path, up to the last / // Use the "name" of the target class as the label of the hyperlink // unless it's not available in the external attributes... if (isset($aAvailableFields[$sExtClassNameAtt])) { $sLabel = $aAvailableFields[$sExtClassNameAtt]; } else { $sLabel = implode(' / ', $aAvailableFields); } // Safety belt // if (empty($sLabel)) { // Developer's note: // This is doing the job for you, but that is just there in case // the external fields associated to the external key are blanks // The ultimate solution will be to query the name automatically // and independantly from the data model (automatic external field) // AND make the name be a mandatory field // $sObject = MetaModel::GetObject($sObjClass, $sObjKey); $sLabel = $sObject->GetName(); } // Safety net // if (empty($sLabel)) { $sLabel = MetaModel::GetName($sObjClass)." #$sObjKey"; } $sHint = MetaModel::GetName($sObjClass)."::$sObjKey"; return "GetForLink()."\" title=\"$sHint\">$sLabel"; } function DisplayBareHeader(WebPage $oPage, $bEditMode = false) { // Standard Header with name, actions menu and history block // // action menu $oSingletonFilter = new DBObjectSearch(get_class($this)); $oSingletonFilter->AddCondition('id', $this->GetKey(), '='); $oBlock = new MenuBlock($oSingletonFilter, 'popup', false); $oBlock->Display($oPage, -1); $oPage->add("

".$this->GetIcon()." \n"); $oPage->add(MetaModel::GetName(get_class($this)).": ".$this->GetName()."

\n"); $oPage->add("
\n"); } function DisplayBareHistory(WebPage $oPage, $bEditMode = false) { // history block (with as a tab) $oHistoryFilter = new DBObjectSearch('CMDBChangeOp'); $oHistoryFilter->AddCondition('objkey', $this->GetKey(), '='); $oHistoryFilter->AddCondition('objclass', get_class($this), '='); $oBlock = new HistoryBlock($oHistoryFilter, 'table', false); $oBlock->Display($oPage, -1); } function DisplayBareProperties(WebPage $oPage, $bEditMode = false) { $oPage->add($this->GetBareProperties($oPage, $bEditMode)); } function DisplayBareRelations(WebPage $oPage, $bEditMode = false) { // Related objects: display all the linkset attributes, each as a separate tab // In the order described by the 'display' ZList $aList = $this->FlattenZList(MetaModel::GetZListItems(get_class($this), 'details')); if (count($aList) == 0) { // Empty ZList defined, display all the linkedset attributes defined $aList = array_keys(MetaModel::ListAttributeDefs(get_class($this))); } foreach($aList as $sAttCode) { $oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode); // Display mode if (!$oAttDef->IsLinkset()) continue; // Process only linkset attributes... $oPage->SetCurrentTab($oAttDef->GetLabel()); if ($bEditMode) { $iFlags = $this->GetAttributeFlags($sAttCode); $sClass = get_class($this); if (get_class($oAttDef) == 'AttributeLinkedSet') { // 1:n links $sTargetClass = $oAttDef->GetLinkedClass(); $oPage->p(" ".$oAttDef->GetDescription()); $oFilter = new DBObjectSearch($sTargetClass); $oFilter->AddCondition($oAttDef->GetExtKeyToMe(), $this->GetKey(),'='); $oBlock = new DisplayBlock($oFilter, 'list', false); $oBlock->Display($oPage, 0); } else // get_class($oAttDef) == 'AttributeLinkedSetIndirect' { // n:n links $sLinkedClass = $oAttDef->GetLinkedClass(); $oLinkingAttDef = MetaModel::GetAttributeDef($sLinkedClass, $oAttDef->GetExtKeyToRemote()); $sTargetClass = $oLinkingAttDef->GetTargetClass(); $oPage->p(MetaModel::GetClassIcon($sTargetClass)." ".$oAttDef->GetDescription()); $sValue = $this->Get($sAttCode); $sDisplayValue = $this->GetEditValue($sAttCode); $aArgs = array('this' => $this); $sInputId = $this->m_iFormId.'_'.$sAttCode; $sHTMLValue = "".self::GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef, $sValue, $sDisplayValue, $sInputId, '', $iFlags, $aArgs).''; $aFieldsMap[$sAttCode] = $sInputId; $oPage->add($sHTMLValue); } } else { // Display mode if (!$oAttDef->IsIndirect()) { // 1:n links $sTargetClass = $oAttDef->GetLinkedClass(); $aParams = array( 'target_attr' => $oAttDef->GetExtKeyToMe(), 'object_id' => $this->GetKey(), 'menu' => true, ); } else { // n:n links $sLinkedClass = $oAttDef->GetLinkedClass(); $oLinkingAttDef = MetaModel::GetAttributeDef($sLinkedClass, $oAttDef->GetExtKeyToRemote()); $sTargetClass = $oLinkingAttDef->GetTargetClass(); $bMenu = ($this->Get($sAttCode)->Count() > 0); // The menu is enabled only if there are already some elements... $aParams = array( 'link_attr' => $oAttDef->GetExtKeyToMe(), 'object_id' => $this->GetKey(), 'target_attr' => $oAttDef->GetExtKeyToRemote(), 'view_link' => false, 'menu' => false, ); } $oPage->p(MetaModel::GetClassIcon($sTargetClass)." ".$oAttDef->GetDescription()); $oBlock = new DisplayBlock($this->Get($sAttCode)->GetFilter(), 'list', false); $oBlock->Display($oPage, 'rel_'.$sAttCode, $aParams); } } $oPage->SetCurrentTab(''); } function GetBareProperties(WebPage $oPage, $bEditMode = false) { $sHtml = ''; $oAppContext = new ApplicationContext(); $sStateAttCode = MetaModel::GetStateAttributeCode(get_class($this)); $aDetails = array(); $sClass = get_class($this); $aDetailsList = MetaModel::GetZListItems($sClass, 'details'); $aDetailsStruct = self::ProcessZlist($aDetailsList, array('UI:PropertiesTab' => array()), 'UI:PropertiesTab', 'col1', ''); // Compute the list of properties to display, first the attributes in the 'details' list, then // all the remaining attributes that are not external fields $sHtml = ''; $aDetails = array(); foreach($aDetailsStruct as $sTab => $aCols ) { $aDetails[$sTab] = array(); ksort($aCols); $oPage->SetCurrentTab(Dict::S($sTab)); $oPage->add(''); foreach($aCols as $sColIndex => $aFieldsets) { $aDetails[$sTab][$sColIndex] = array(); foreach($aFieldsets as $sFieldsetName => $aFields) { //if ($sFieldsetName == '') //{ foreach($aFields as $sAttCode) { $val = $this->GetFieldAsHtml($sClass, $sAttCode, $sStateAttCode); if ($val != null) { // The field is visible, add it to the current column $aDetails[$sTab][$sColIndex][] = $val; } } //} } $oPage->add(''); } $oPage->add('
'); $oPage->Details($aDetails[$sTab][$sColIndex]); $oPage->add('
'); } return $sHtml; } function DisplayDetails(WebPage $oPage, $bEditMode = false) { $sTemplate = Utils::ReadFromFile(MetaModel::GetDisplayTemplate(get_class($this))); if (!empty($sTemplate)) { $oTemplate = new DisplayTemplate($sTemplate); $sNameAttCode = MetaModel::GetNameAttributeCode(get_class($this)); // Note: to preserve backward compatibility with home-made templates, the placeholder '$pkey$' has been preserved // but the preferred method is to use '$id$' $oTemplate->Render($oPage, array('class_name'=> MetaModel::GetName(get_class($this)),'class'=> get_class($this), 'pkey'=> $this->GetKey(), 'id'=> $this->GetKey(), 'name' => $this->Get($sNameAttCode))); } else { // Object's details // template not found display the object using the *old style* $this->DisplayBareHeader($oPage, $bEditMode); $oPage->AddTabContainer(OBJECT_PROPERTIES_TAB); $oPage->SetCurrentTabContainer(OBJECT_PROPERTIES_TAB); $oPage->SetCurrentTab(Dict::S('UI:PropertiesTab')); $this->DisplayBareProperties($oPage, $bEditMode); $this->DisplayBareRelations($oPage, $bEditMode); $oPage->SetCurrentTab(Dict::S('UI:HistoryTab')); $this->DisplayBareHistory($oPage, $bEditMode); } } function DisplayPreview(WebPage $oPage) { $aDetails = array(); $sClass = get_class($this); $aList = MetaModel::GetZListItems($sClass, 'preview'); foreach($aList as $sAttCode) { $aDetails[] = array('label' => MetaModel::GetLabel($sClass, $sAttCode), 'value' =>$this->GetAsHTML($sAttCode)); } $oPage->details($aDetails); } public static function DisplaySet(WebPage $oPage, CMDBObjectSet $oSet, $aExtraParams = array()) { $oPage->add(self::GetDisplaySet($oPage, $oSet, $aExtraParams)); } /** * Get the HTML fragment corresponding to the display of a table representing a set of objects * @param WebPage $oPage The page object is used for out-of-band information (mostly scripts) output * @param CMDBObjectSet The set of objects to display * @param Hash $aExtraParams Some extra configuration parameters to tweak the behavior of the display * @return String The HTML fragment representing the table of objects */ public static function GetDisplaySet(WebPage $oPage, CMDBObjectSet $oSet, $aExtraParams = array()) { static $iListId = 0; $iListId++; // Initialize and check the parameters $bViewLink = isset($aExtraParams['view_link']) ? $aExtraParams['view_link'] : true; $sLinkageAttribute = isset($aExtraParams['link_attr']) ? $aExtraParams['link_attr'] : ''; $iLinkedObjectId = isset($aExtraParams['object_id']) ? $aExtraParams['object_id'] : 0; $sTargetAttr = isset($aExtraParams['target_attr']) ? $aExtraParams['target_attr'] : ''; if (!empty($sLinkageAttribute)) { if($iLinkedObjectId == 0) { // if 'links' mode is requested the id of the object to link to must be specified throw new ApplicationException(Dict::S('UI:Error:MandatoryTemplateParameter_object_id')); } if($sTargetAttr == '') { // if 'links' mode is requested the d of the object to link to must be specified throw new ApplicationException(Dict::S('UI:Error:MandatoryTemplateParameter_target_attr')); } } $bDisplayMenu = isset($aExtraParams['menu']) ? $aExtraParams['menu'] == true : true; $bSelectMode = isset($aExtraParams['selection_mode']) ? $aExtraParams['selection_mode'] == true : false; $bSingleSelectMode = isset($aExtraParams['selection_type']) ? ($aExtraParams['selection_type'] == 'single') : false; $aExtraFields = isset($aExtraParams['extra_fields']) ? explode(',', trim($aExtraParams['extra_fields'])) : array(); $sHtml = ''; $oAppContext = new ApplicationContext(); $sClassName = $oSet->GetFilter()->GetClass(); $aAttribs = array(); $aList = MetaModel::GetZListItems($sClassName, 'list'); $aList = array_merge($aList, $aExtraFields); if (!empty($sLinkageAttribute)) { // The set to display is in fact a set of links between the object specified in the $sLinkageAttribute // and other objects... // The display will then group all the attributes related to the link itself: // | Link_attr1 | link_attr2 | ... || Object_attr1 | Object_attr2 | Object_attr3 | .. | Object_attr_n | $aAttDefs = MetaModel::ListAttributeDefs($sClassName); assert(isset($aAttDefs[$sLinkageAttribute])); $oAttDef = $aAttDefs[$sLinkageAttribute]; assert($oAttDef->IsExternalKey()); // First display all the attributes specific to the link record foreach($aList as $sLinkAttCode) { $oLinkAttDef = $aAttDefs[$sLinkAttCode]; if ( (!$oLinkAttDef->IsExternalKey()) && (!$oLinkAttDef->IsExternalField()) ) { $aDisplayList[] = $sLinkAttCode; } } // Then display all the attributes neither specific to the link record nor to the 'linkage' object (because the latter are constant) foreach($aList as $sLinkAttCode) { $oLinkAttDef = $aAttDefs[$sLinkAttCode]; if (($oLinkAttDef->IsExternalKey() && ($sLinkAttCode != $sLinkageAttribute)) || ($oLinkAttDef->IsExternalField() && ($oLinkAttDef->GetKeyAttCode()!=$sLinkageAttribute)) ) { $aDisplayList[] = $sLinkAttCode; } } // First display all the attributes specific to the link // Then display all the attributes linked to the other end of the relationship $aList = $aDisplayList; } if ($bSelectMode) { if (!$bSingleSelectMode) { $aAttribs['form::select'] = array('label' => "", 'description' => Dict::S('UI:SelectAllToggle+')); } else { $aAttribs['form::select'] = array('label' => "", 'description' => ''); } } if ($bViewLink) { $aAttribs['key'] = array('label' => MetaModel::GetName($sClassName), 'description' => ''); } foreach($aList as $sAttCode) { $aAttribs[$sAttCode] = array('label' => MetaModel::GetLabel($sClassName, $sAttCode), 'description' => MetaModel::GetDescription($sClassName, $sAttCode)); } $aValues = array(); $oSet->Seek(0); $bDisplayLimit = isset($aExtraParams['display_limit']) ? $aExtraParams['display_limit'] : true; $iMaxObjects = -1; if ($bDisplayLimit) { if ($oSet->Count() > utils::GetConfig()->GetMaxDisplayLimit()) { $iMaxObjects = utils::GetConfig()->GetMinDisplayLimit(); } } while (($oObj = $oSet->Fetch()) && ($iMaxObjects != 0)) { $aRow = array(); $sHilightClass = $oObj->GetHilightClass(); if ($sHilightClass != '') { $aRow['@class'] = $sHilightClass; } if ($bViewLink) { $aRow['key'] = $oObj->GetHyperLink(); } if ($bSelectMode) { if ($bSingleSelectMode) { $aRow['form::select'] = "GetKey()."\">"; } else { $aRow['form::select'] = "GetKey()."\">"; } } foreach($aList as $sAttCode) { $aRow[$sAttCode] = $oObj->GetAsHTML($sAttCode); } $aValues[] = $aRow; $iMaxObjects--; } $sHtml .= ''; $sColspan = ''; if ($bDisplayMenu) { $oMenuBlock = new MenuBlock($oSet->GetFilter()); $sColspan = 'colspan="2"'; $aMenuExtraParams = $aExtraParams; if (!empty($sLinkageAttribute)) { //$aMenuExtraParams['linkage'] = $sLinkageAttribute; $aMenuExtraParams = $aExtraParams; } if ($bDisplayLimit && ($oSet->Count() > utils::GetConfig()->GetMaxDisplayLimit())) { // list truncated $divId = $aExtraParams['block_id']; $sFilter = $oSet->GetFilter()->serialize(); $aExtraParams['display_limit'] = false; // To expand the full list $sExtraParams = addslashes(str_replace('"', "'", json_encode($aExtraParams))); // JSON encode, change the style of the quotes and escape them $sHtml .= ''; } $sHtml .= "'; $sHtml .= '
'.Dict::Format('UI:TruncatedResults', utils::GetConfig()->GetMinDisplayLimit(), $oSet->Count()).'  '.Dict::S('UI:DisplayAll').''; $oPage->add_ready_script("$('#{$divId} table.listResults').addClass('truncated');"); $oPage->add_ready_script("$('#{$divId} table.listResults tr:last td').addClass('truncated');"); } else { // Full list $sHtml .= '
 '.Dict::Format('UI:CountOfResults', $oSet->Count()).''; } $sHtml .= $oMenuBlock->GetRenderContent($oPage, $aMenuExtraParams); $sHtml .= '
"; $sHtml .= $oPage->GetTable($aAttribs, $aValues); $sHtml .= '
'; return $sHtml; } public static function GetDisplayExtendedSet(WebPage $oPage, CMDBObjectSet $oSet, $aExtraParams = array()) { static $iListId = 0; $iListId++; $aList = array(); // Initialize and check the parameters $bViewLink = isset($aExtraParams['view_link']) ? $aExtraParams['view_link'] : true; $bDisplayMenu = isset($aExtraParams['menu']) ? $aExtraParams['menu'] == true : true; // Check if there is a list of aliases to limit the display to... $aDisplayAliases = isset($aExtraParams['display_aliases']) ? explode(',', $aExtraParams['display_aliases']) : array(); $sHtml = ''; $oAppContext = new ApplicationContext(); $aClasses = $oSet->GetFilter()->GetSelectedClasses(); $aAuthorizedClasses = array(); foreach($aClasses as $sAlias => $sClassName) { if ((UserRights::IsActionAllowed($sClassName, UR_ACTION_READ, $oSet) == UR_ALLOWED_YES) && ( (count($aDisplayAliases) == 0) || (in_array($sAlias, $aDisplayAliases))) ) { $aAuthorizedClasses[$sAlias] = $sClassName; } } $aAttribs = array(); foreach($aAuthorizedClasses as $sAlias => $sClassName) // TO DO: check if the user has enough rights to view the classes of the list... { $aList[$sClassName] = MetaModel::GetZListItems($sClassName, 'list'); if ($bViewLink) { $aAttribs['key_'.$sAlias] = array('label' => MetaModel::GetName($sClassName), 'description' => ''); } foreach($aList[$sClassName] as $sAttCode) { $aAttribs[$sAttCode.'_'.$sAlias] = array('label' => MetaModel::GetLabel($sClassName, $sAttCode), 'description' => MetaModel::GetDescription($sClassName, $sAttCode)); } } $aValues = array(); $oSet->Seek(0); $bDisplayLimit = isset($aExtraParams['display_limit']) ? $aExtraParams['display_limit'] : true; $iMaxObjects = -1; if ($bDisplayLimit) { if ($oSet->Count() > utils::GetConfig()->GetMaxDisplayLimit()) { $iMaxObjects = utils::GetConfig()->GetMinDisplayLimit(); } } while (($aObjects = $oSet->FetchAssoc()) && ($iMaxObjects != 0)) { $aRow = array(); foreach($aAuthorizedClasses as $sAlias => $sClassName) // TO DO: check if the user has enough rights to view the classes of the list... { if ($bViewLink) { $aRow['key_'.$sAlias] = $aObjects[$sAlias]->GetHyperLink(); } foreach($aList[$sClassName] as $sAttCode) { $aRow[$sAttCode.'_'.$sAlias] = $aObjects[$sAlias]->GetAsHTML($sAttCode); } } $aValues[] = $aRow; $iMaxObjects--; } $sHtml .= ''; $sColspan = ''; if ($bDisplayMenu) { $oMenuBlock = new MenuBlock($oSet->GetFilter()); $sColspan = 'colspan="2"'; $aMenuExtraParams = $aExtraParams; if (!empty($sLinkageAttribute)) { $aMenuExtraParams = $aExtraParams; } if ($bDisplayLimit && ($oSet->Count() > utils::GetConfig()->GetMaxDisplayLimit())) { // list truncated $divId = $aExtraParams['block_id']; $sFilter = $oSet->GetFilter()->serialize(); $aExtraParams['display_limit'] = false; // To expand the full list $sExtraParams = addslashes(str_replace('"', "'", json_encode($aExtraParams))); // JSON encode, change the style of the quotes and escape them $sHtml .= ''; } $sHtml .= "'; $sHtml .= '
'.Dict::Format('UI:TruncatedResults', utils::GetConfig()->GetMinDisplayLimit(), $oSet->Count()).'  '.Dict::S('UI:DisplayAll').''; $oPage->add_ready_script("$('#{$divId} table.listResults').addClass('truncated');"); $oPage->add_ready_script("$('#{$divId} table.listResults tr:last td').addClass('truncated');"); } else { // Full list $sHtml .= '
 '.Dict::Format('UI:CountOfResults', $oSet->Count()).''; } $sHtml .= $oMenuBlock->GetRenderContent($oPage, $aMenuExtraParams); $sHtml .= '
"; $sHtml .= $oPage->GetTable($aAttribs, $aValues); $sHtml .= '
'; return $sHtml; } static function DisplaySetAsCSV(WebPage $oPage, CMDBObjectSet $oSet, $aParams = array()) { $oPage->add(self::GetSetAsCSV($oSet, $aParams)); } static function GetSetAsCSV(DBObjectSet $oSet, $aParams = array()) { $sSeparator = isset($aParams['separator']) ? $aParams['separator'] : ','; // default separator is comma $sTextQualifier = isset($aParams['text_qualifier']) ? $aParams['text_qualifier'] : '"'; // default text qualifier is double quote $aList = array(); $oAppContext = new ApplicationContext(); $aClasses = $oSet->GetFilter()->GetSelectedClasses(); $aAuthorizedClasses = array(); foreach($aClasses as $sAlias => $sClassName) { if (UserRights::IsActionAllowed($sClassName, UR_ACTION_READ, $oSet) == UR_ALLOWED_YES) { $aAuthorizedClasses[$sAlias] = $sClassName; } } $aAttribs = array(); $aHeader = array(); foreach($aAuthorizedClasses as $sAlias => $sClassName) { foreach(MetaModel::ListAttributeDefs($sClassName) as $sAttCode => $oAttDef) { if ((($oAttDef->IsExternalField()) || ($oAttDef->IsWritable())) && $oAttDef->IsScalar()) { $aList[$sClassName][$sAttCode] = $oAttDef; } } $aHeader[] = 'id'; foreach($aList[$sClassName] as $sAttCode => $oAttDef) { if ($oAttDef->IsExternalField()) { $sExtKeyLabel = MetaModel::GetLabel($sClassName, $oAttDef->GetKeyAttCode()); $sRemoteAttLabel = MetaModel::GetLabel($oAttDef->GetTargetClass(), $oAttDef->GetExtAttCode()); $aHeader[] = $sExtKeyLabel.'->'.$sRemoteAttLabel; } else { $aHeader[] = MetaModel::GetLabel($sClassName, $sAttCode); } } } $sHtml = implode($sSeparator, $aHeader)."\n"; $oSet->Seek(0); while ($aObjects = $oSet->FetchAssoc()) { $aRow = array(); foreach($aAuthorizedClasses as $sAlias => $sClassName) { $oObj = $aObjects[$sAlias]; $aRow[] = $oObj->GetKey(); foreach($aList[$sClassName] as $sAttCode => $oAttDef) { $aRow[] = $oObj->GetAsCSV($sAttCode, $sSeparator, '\\'); } } $sHtml .= implode($sSeparator, $aRow)."\n"; } return $sHtml; } static function DisplaySetAsXML(WebPage $oPage, CMDBObjectSet $oSet, $aParams = array()) { $oAppContext = new ApplicationContext(); $aClasses = $oSet->GetFilter()->GetSelectedClasses(); $aAuthorizedClasses = array(); foreach($aClasses as $sAlias => $sClassName) { if (UserRights::IsActionAllowed($sClassName, UR_ACTION_READ, $oSet) == UR_ALLOWED_YES) { $aAuthorizedClasses[$sAlias] = $sClassName; } } $aAttribs = array(); $aList = array(); $aList[$sClassName] = MetaModel::GetZListItems($sClassName, 'details'); $oPage->add("\n"); $oSet->Seek(0); while ($aObjects = $oSet->FetchAssoc()) { if (count($aAuthorizedClasses) > 1) { $oPage->add("\n"); } foreach($aAuthorizedClasses as $sAlias => $sClassName) { $oObj = $aObjects[$sAlias]; $sClassName = get_class($oObj); $oPage->add("<$sClassName alias=\"$sAlias\" id=\"".$oObj->GetKey()."\">\n"); foreach(MetaModel::ListAttributeDefs($sClassName) as $sAttCode=>$oAttDef) { if (($oAttDef->IsWritable()) && ($oAttDef->IsScalar())) { $sValue = $oObj->GetAsXML($sAttCode); $oPage->add("<$sAttCode>$sValue\n"); } } $oPage->add("\n"); } if (count($aAuthorizedClasses) > 1) { $oPage->add("\n"); } } $oPage->add("\n"); } // By rom function DisplayChangesLog(WebPage $oPage) { $oFltChangeOps = new CMDBSearchFilter('CMDBChangeOpSetAttribute'); $oFltChangeOps->AddCondition('objkey', $this->GetKey(), '='); $oFltChangeOps->AddCondition('objclass', get_class($this), '='); $oSet = new CMDBObjectSet($oFltChangeOps, array('date' => false)); // order by date descending (i.e. false) $count = $oSet->Count(); if ($count > 0) { $oPage->p(Dict::Format('UI:ChangesLogTitle', $count)); self::DisplaySet($oPage, $oSet); } else { $oPage->p(Dict::S('UI:EmptyChangesLogTitle')); } } public static function DisplaySearchForm(WebPage $oPage, CMDBObjectSet $oSet, $aExtraParams = array()) { $oPage->add(self::GetSearchForm($oPage, $oSet, $aExtraParams)); } public static function GetSearchForm(WebPage $oPage, CMDBObjectSet $oSet, $aExtraParams = array()) { static $iSearchFormId = 0; $oAppContext = new ApplicationContext(); $sHtml = ''; $numCols=4; $sClassName = $oSet->GetFilter()->GetClass(); // Romain: temporarily removed the tab "OQL query" because it was not finalized // (especially when used to add a link) /* $sHtml .= "\n"; */ // Simple search form if (isset($aExtraParams['currentId'])) { $sSearchFormId = $aExtraParams['currentId']; $iSearchFormId++; } else { $iSearchFormId++; $sSearchFormId = 'SimpleSearchForm'.$iSearchFormId; $sHtml .= "
\n"; } // Check if the current class has some sub-classes if (isset($aExtraParams['baseClass'])) { $sRootClass = $aExtraParams['baseClass']; } else { $sRootClass = $sClassName; } $aSubClasses = MetaModel::GetSubclasses($sRootClass); if (count($aSubClasses) > 0) { $aOptions = array(); $aOptions[MetaModel::GetName($sRootClass)] = "
\n"; } // OQL query builder $sHtml .= "
\n"; $sHtml .= "

".Dict::S('UI:OQLQueryBuilderTitle')."

\n"; $sHtml .= "
\n"; $sHtml .= "\n"; $sHtml .= "\n"; $sHtml .= "\n"; foreach($aExtraParams as $sName => $sValue) { $sHtml .= "\n"; } $sHtml .= "\n"; $sHtml .= $oAppContext->GetForForm(); $sHtml .= "
 \n"; $sHtml .= "
\n"; $sHtml .= "
\n"; return $sHtml; } public static function GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef, $value = '', $sDisplayValue = '', $iId = '', $sNameSuffix = '', $iFlags = 0, $aArgs = array()) { static $iInputId = 0; $sFieldPrefix = ''; if (isset($aArgs['prefix'])) { $sFieldPrefix = $aArgs['prefix']; } if (isset($aArgs[$sAttCode]) && empty($value)) { // default value passed by the context (either the app context of the operation) $value = $aArgs[$sAttCode]; } if (!empty($iId)) { $iInputId = $iId; } else { $iInputId++; $iId = $iInputId; } if (!$oAttDef->IsExternalField()) { $aCSSClasses = array(); $bMandatory = 0; if ( (!$oAttDef->IsNullAllowed()) || ($iFlags & OPT_ATT_MANDATORY)) { $aCSSClasses[] = 'mandatory'; $bMandatory = 1; } $sCSSClasses = self::GetCSSClasses($aCSSClasses); $sValidationField = ""; $sHelpText = $oAttDef->GetHelpOnEdition(); $aEventsList = array('validate'); switch($oAttDef->GetEditClass()) { case 'Date': case 'DateTime': $aEventsList[] ='keyup'; $aEventsList[] ='change'; $sHTMLValue = " {$sValidationField}"; break; case 'Password': $aEventsList[] ='keyup'; $aEventsList[] ='change'; $sHTMLValue = " {$sValidationField}"; break; case 'Text': $aEventsList[] ='keypress'; $aEventsList[] ='change'; $sHTMLValue = " {$sValidationField}"; break; case 'LinkedSet': $aEventsList[] ='change'; $oWidget = new UILinksWidget($sClass, $sAttCode, $iId, $sNameSuffix); $sHTMLValue = $oWidget->Display($oPage, $value); break; case 'Document': $aEventsList[] ='change'; $oDocument = $value; // Value is an ormDocument object $sFileName = ''; if (is_object($oDocument)) { $sFileName = $oDocument->GetFileName(); } $iMaxFileSize = utils::ConvertToBytes(ini_get('upload_max_filesize')); $sHTMLValue = "\n"; $sHTMLValue .= "\n"; $sHTMLValue .= "$sFileName
\n"; $sHTMLValue .= " {$sValidationField}\n"; break; case 'List': // Not editable for now... $sHTMLValue = ''; break; case 'String': default: // #@# todo - add context information (depending on dimensions) $aAllowedValues = MetaModel::GetAllowedValues_att($sClass, $sAttCode, $aArgs); if ($aAllowedValues !== null) { //Enum field or external key, display a combo //if (count($aAllowedValues) == 0) //{ // $sHTMLValue = ""; //} //else if (count($aAllowedValues) > 50) if (count($aAllowedValues) > 50) { // too many choices, use an autocomplete // The input for the auto complete $sHTMLValue = " {$sValidationField}"; // another hidden input to store & pass the object's Id $sHTMLValue .= "\n"; $oPage->add_ready_script("\$('#label_$iId').autocomplete('./ajax.render.php', { scroll:true, minChars:3, onItemSelect:selectItem, onFindValue:findValue, formatItem:formatItem, autoFill:true, keyHolder:'#$iId', extraParams:{operation:'autocomplete', sclass:'$sClass',attCode:'".$sAttCode."'}});"); $oPage->add_ready_script("\$('#label_$iId').result( function(event, data, formatted) { if (data) { $('#{$iId}').val(data[1]); } } );"); $aEventsList[] ='change'; } else { // Few choices, use a normal 'select' // In case there are no valid values, the select will be empty, thus blocking the user from validating the form $sHTMLValue = " {$sValidationField}\n"; $aEventsList[] ='change'; } } else { $sHTMLValue = " {$sValidationField}"; $aEventsList[] ='keyup'; $aEventsList[] ='change'; } break; } $sPattern = addslashes($oAttDef->GetValidationPattern()); //'^([0-9]+)$'; $oPage->add_ready_script("$('#$iId').bind('".implode(' ', $aEventsList)."', function(evt, sFormId) { return ValidateField('$iId', '$sPattern', $bMandatory, sFormId) } );"); // Bind to a custom event: validate $aDependencies = MetaModel::GetDependentAttributes($sClass, $sAttCode); // List of attributes that depend on the current one if (count($aDependencies) > 0) { $oPage->add_ready_script("$('#$iId').bind('change', function(evt, sFormId) { return UpdateDependentFields(['".implode("','", $aDependencies)."']) } );"); // Bind to a custom event: validate } } return "
{$sHTMLValue}
"; } public function DisplayModifyForm(WebPage $oPage, $aExtraParams = array()) { static $iGlobalFormId = 0; $iGlobalFormId++; $this->m_iFormId = $iGlobalFormId; $sClass = get_class($this); $oAppContext = new ApplicationContext(); $sStateAttCode = MetaModel::GetStateAttributeCode($sClass); $iKey = $this->GetKey(); $aDetails = array(); $aFieldsMap = array(); $oPage->add("
m_iFormId}\" enctype=\"multipart/form-data\" method=\"post\" onSubmit=\"return CheckFields('form_{$this->m_iFormId}', true)\">\n"); $oPage->AddTabContainer(OBJECT_PROPERTIES_TAB); $oPage->SetCurrentTabContainer(OBJECT_PROPERTIES_TAB); $oPage->SetCurrentTab(Dict::S('UI:PropertiesTab')); $aDetailsList = $this->FLattenZList(MetaModel::GetZListItems($sClass, 'details')); //$aFullList = MetaModel::ListAttributeDefs($sClass); $aList = array(); // Compute the list of properties to display, first the attributes in the 'details' list, then // all the remaining attributes that are not external fields foreach($aDetailsList as $sAttCode) { $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); if (!$oAttDef->IsExternalField()) { $aList[] = $sAttCode; } } foreach($aList as $sAttCode) { $iFlags = $this->GetAttributeFlags($sAttCode); $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); if ( (!$oAttDef->IsLinkSet()) && (($iFlags & OPT_ATT_HIDDEN) == 0) ) { if ($oAttDef->IsWritable()) { if ($sStateAttCode == $sAttCode) { // State attribute is always read-only from the UI $sHTMLValue = $this->GetStateLabel(); $aDetails[] = array('label' => $oAttDef->GetLabel(), 'value' => $sHTMLValue); } else { $iFlags = $this->GetAttributeFlags($sAttCode); if ($iFlags & OPT_ATT_HIDDEN) { // Attribute is hidden, do nothing } else { if ($iFlags & OPT_ATT_READONLY) { // Attribute is read-only $sHTMLValue = $this->GetAsHTML($sAttCode); } else { $sValue = $this->Get($sAttCode); $sDisplayValue = $this->GetEditValue($sAttCode); $aArgs = array('this' => $this); $sInputId = $this->m_iFormId.'_'.$sAttCode; $sHTMLValue = "".self::GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef, $sValue, $sDisplayValue, $sInputId, '', $iFlags, $aArgs).''; $aFieldsMap[$sAttCode] = $sInputId; } $aDetails[] = array('label' => ''.$oAttDef->GetLabel().'', 'value' => $sHTMLValue); } } } else { $aDetails[] = array('label' => ''.$oAttDef->GetLabel().'', 'value' => $this->GetAsHTML($sAttCode)); } } } $oPage->details($aDetails); // Now display the relations, one tab per relation $this->DisplayBareRelations($oPage, true); // Edit mode $oPage->SetCurrentTab(''); $oPage->add("\n"); $oPage->add("\n"); $oPage->add("\n"); $oPage->add("\n"); foreach($aExtraParams as $sName => $value) { $oPage->add("\n"); } $oPage->add($oAppContext->GetForForm()); $oPage->add("    \n"); $oPage->add("\n"); $oPage->add("
\n"); $iFieldsCount = count($aFieldsMap); $sJsonFieldsMap = json_encode($aFieldsMap); $oPage->add_script( <<add_ready_script( <<m_iFormId}', false); EOF ); } public static function DisplayCreationForm(WebPage $oPage, $sClass, $oObjectToClone = null, $aArgs = array(), $aExtraParams = array()) { static $iCreationFormId = 0; $iCreationFormId++; $iFieldIndex = 0; $oAppContext = new ApplicationContext(); $aDetails = array(); $aFieldsMap = array(); $sOperation = ($oObjectToClone == null) ? 'apply_new' : 'apply_clone'; $sClass = ($oObjectToClone == null) ? $sClass : get_class($oObjectToClone); $sStateAttCode = MetaModel::GetStateAttributeCode($sClass); $oPage->add("
\n"); $aStates = MetaModel::EnumStates($sClass); $oPage->AddTabContainer(OBJECT_PROPERTIES_TAB); $oPage->SetCurrentTabContainer(OBJECT_PROPERTIES_TAB); $oPage->SetCurrentTab(Dict::S('UI:PropertiesTab')); $oObj = MetaModel::NewObject($sClass); if (isset($aArgs['default'])) { // Pre-populated default values $aDefaultValues = $aArgs['default']; foreach($aDefaultValues as $sAttCode => $value) { if (MetaModel::IsValidAttCode($sClass, $sAttCode)) { $oObj->Set($sAttCode, $value); } } } $aArgs['this'] = $oObj; if ($oObjectToClone == null) { $sTargetState = MetaModel::GetDefaultState($sClass); } else { $sTargetState = $oObjectToClone->GetState(); } $aDetailsList = self::FlattenZList(MetaModel::GetZListItems($sClass, 'details')); //$aFullList = MetaModel::ListAttributeDefs($sClass); $aList = array(); // Compute the list of properties to display, first the attributes in the 'details' list, then // all the remaining attributes that are not external fields foreach($aDetailsList as $sAttCode) { $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); if (!$oAttDef->IsExternalField()) { $aList[] = $sAttCode; } } foreach($aList as $sAttCode) { $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); $iFlags = isset($aStates[$sTargetState]['attribute_list'][$sAttCode]) ? $aStates[$sTargetState]['attribute_list'][$sAttCode] : 0; if ( (!$oAttDef->IsLinkSet()) && (($iFlags & OPT_ATT_HIDDEN) == 0) ) { if ($oAttDef->IsWritable()) { if ($oObjectToClone != null) { $sValue = $oObjectToClone->GetEditValue($sAttCode); $aArgs['this'] = $oObjectToClone; } else { if(isset($aArgs['default'][$sAttCode])) { $sValue = $aArgs['default'][$sAttCode]; } else { $sValue = $oAttDef->GetDefaultValue(); } } // Prepopulate with a default value -- but no display value... $sDisplayValue = ''; if (!empty($sValue)) { $aAllowedValues = MetaModel::GetAllowedValues_att($sClass, $sAttCode, $aArgs, ''); switch (count($aAllowedValues)) { case 1: case 0: $sDisplayValue = $sValue; break; default: $sDisplayValue = $sValue; foreach($aAllowedValues as $key => $display) { if ($key == $sValue) { $sDisplayValue = $display; break; } } } } if ($sStateAttCode == $sAttCode) { // State attribute is always read-only from the UI $sHTMLValue = MetaModel::GetStateLabel($sClass, $sTargetState); $aDetails[] = array('label' => $oAttDef->GetLabel(), 'value' => $sHTMLValue); } else { if ($iFlags & OPT_ATT_HIDDEN) { // Attribute is hidden, do nothing } else { if ($iFlags & OPT_ATT_READONLY) { // Attribute is read-only $sHTMLValue = ($oObjectToClone == null) ? $sDisplayValue : $oObjectToClone->GetAsHTML($sAttCode); } else { $sFieldId = 'att_'.$iFieldIndex; $sHTMLValue = "
".self::GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef, $sValue, $sDisplayValue, $sFieldId, '', $iFlags, $aArgs)."
"; $aFieldsMap[$sFieldId] = $sAttCode; $aDetails[] = array('label' => $oAttDef->GetLabel(), 'value' => $sHTMLValue); $iFieldIndex++; } } } } } } $oPage->details($aDetails); // Now display the relations, one tab per relation if ($oObjectToClone != null) { $oObj = $oObjectToClone; // Hmm, likely to fail... } else { $oObj = new $sClass; } $oObj->m_iFormId = $iCreationFormId; $oObj->DisplayBareRelations($oPage, true); /* foreach($aList as $sAttCode) { $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); if ($oAttDef->IsLinkset()) { $oPage->SetCurrentTab($oAttDef->GetLabel()); $oPage->p($oAttDef->GetDescription()); $iFlags = isset($aStates[$sTargetState]['attribute_list'][$sAttCode]) ? $aStates[$sTargetState]['attribute_list'][$sAttCode] : 0; $sFieldId = 'att_'.$iFieldIndex; $sValue = ($oObjectToClone == null) ? '' : $oObjectToClone->Get($sAttCode); $sDisplayValue = ($oObjectToClone == null) ? '' : $oObjectToClone->GetEditValue($sAttCode); $iFlags = isset($aStates[$sTargetState]['attribute_list'][$sAttCode]) ? $aStates[$sTargetState]['attribute_list'][$sAttCode] : 0; $sHTMLValue = "
".self::GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef, $sValue, $sDisplayValue, $sFieldId, '', $iFlags, $aArgs)."
"; $aFieldsMap[$sFieldId] = $sAttCode; $aDetails[] = array('label' => $oAttDef->GetLabel(), 'value' => $sHTMLValue); $iFieldIndex++; $oPage->add($sHTMLValue); } } $oPage->SetCurrentTab(''); */ if ($oObjectToClone != null) { $oPage->add("GetKey()."\">\n"); } $oPage->add("\n"); $oPage->add("\n"); $oPage->add("\n"); $oPage->add($oAppContext->GetForForm()); foreach($aExtraParams as $sName => $value) { $oPage->add("\n"); } $oPage->add("    \n"); $oPage->add("\n"); $oPage->add("
\n"); $aNewFieldsMap = array(); foreach($aFieldsMap as $id => $sFieldCode) { $aNewFieldsMap[$sFieldCode] = $id; } $iFieldsCount = count($aFieldsMap); $sJsonFieldsMap = json_encode($aNewFieldsMap); $oPage->add_script(" // Initializes the object once at the beginning of the page... var oWizardHelper = new WizardHelper('$sClass'); oWizardHelper.SetFieldsMap($sJsonFieldsMap); oWizardHelper.SetFieldsCount($iFieldsCount);"); $oPage->add_ready_script("CheckFields('creation_form_{$iCreationFormId}', false);"); } protected static function GetCSSClasses($aCSSClasses) { $sCSSClasses = ''; if (!empty($aCSSClasses)) { $sCSSClasses = ' class="'.implode(' ', $aCSSClasses).'" '; } return $sCSSClasses; } protected static function ProcessZlist($aList, $aDetails, $sCurrentTab, $sCurrentCol, $sCurrentSet) { //echo "
ZList: ";
		//print_r($aList);
		//echo "
\n"; foreach($aList as $sKey => $value) { if (is_array($value)) { if (preg_match('/^(.*):(.*)$/U', $sKey, $aMatches)) { $sCode = $aMatches[1]; $sName = $aMatches[2]; switch($sCode) { case 'tab': //echo "

Found a tab: $sName ($sKey)

\n"; if(!isset($aDetails[$sName])) { $aDetails[$sName] = array('col1' => array('' => array())); } $aDetails = self::ProcessZlist($value, $aDetails, $sName, 'col1', ''); break; case 'fieldset': //echo "

Found a fieldset: $sName ($sKey)

\n"; if(!isset($aDetailsStruct[$sCurrentTab][$sCurrentCol][$sName])) { $aDetails[$sCurrentTab][$sCurrentCol][$sName] = array(); } $aDetails = self::ProcessZlist($value, $aDetails, $sCurrentTab, $sCurrentCol, $sName); break; default: case 'col': //echo "

Found a column: $sName ($sKey)

\n"; if(!isset($aDetails[$sCurrentTab][$sName])) { $aDetails[$sCurrentTab][$sName] = array('' => array()); } $aDetails = self::ProcessZlist($value, $aDetails, $sCurrentTab, $sName, ''); break; } } } else { //echo "

Scalar value: $value, in [$sCurrentTab][$sCurrentCol][$sCurrentSet][]

\n"; $aDetails[$sCurrentTab][$sCurrentCol][$sCurrentSet][] = $value; } } return $aDetails; } protected static function FlattenZList($aList) { $aResult = array(); foreach($aList as $value) { if (!is_array($value)) { $aResult[] = $value; } else { $aResult = array_merge($aResult, $this->FlattenZList($value)); } } return $aResult; } protected function GetFieldAsHtml($sClass, $sAttCode, $sStateAttCode) { $retVal = null; $iFlags = $this->GetAttributeFlags($sAttCode); $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); if ( (!$oAttDef->IsLinkSet()) && (($iFlags & OPT_ATT_HIDDEN) == 0) ) { // The field is visible in the current state of the object if ($sStateAttCode == $sAttCode) { // Special display for the 'state' attribute itself $sDisplayValue = $this->GetStateLabel(); } else if ($oAttDef->GetEditClass() == 'Document') { $oDocument = $this->Get($sAttCode); $sDisplayValue = $this->GetAsHTML($sAttCode); $sDisplayValue .= "
".Dict::Format('UI:OpenDocumentInNewWindow_', $oDocument->GetDisplayLink(get_class($this), $this->GetKey(), $sAttCode)).", \n"; $sDisplayValue .= "
".Dict::Format('UI:DownloadDocument_', $oDocument->GetDisplayLink(get_class($this), $this->GetKey(), $sAttCode)).", \n"; } else { $sDisplayValue = $this->GetAsHTML($sAttCode); } $retVal = array('label' => ''.MetaModel::GetLabel($sClass, $sAttCode).'', 'value' => $sDisplayValue); } return $retVal; } /** * Displays a blob document *inline* (if possible, depending on the type of the document) * @return string */ public function DisplayDocumentInline(WebPage $oPage, $sAttCode) { $oDoc = $this->Get($sAttCode); $sClass = get_class($this); $Id = $this->GetKey(); switch ($oDoc->GetMainMimeType()) { case 'text': case 'html': $data = $oDoc->GetData(); switch($oDoc->GetMimeType()) { case 'text/html': case 'text/xml': $oPage->add("\n"); break; default: $oPage->add("
".htmlentities(MyHelpers::beautifulstr($data, 1000, true))."
\n"); } break; case 'application': switch($oDoc->GetMimeType()) { case 'application/pdf': $oPage->add("\n"); break; default: $oPage->add(Dict::S('UI:Document:NoPreview')); } break; case 'image': $oPage->add("\n"); break; default: $oPage->add(Dict::S('UI:Document:NoPreview')); } } /** * This function returns a 'hilight' CSS class, used to hilight a given row in a table * There are currently (i.e defined in the CSS) 4 possible values HILIGHT_CLASS_CRITICAL, * HILIGHT_CLASS_WARNING, HILIGHT_CLASS_OK, HILIGHT_CLASS_NONE * To Be overridden by derived classes * @param void * @return String The desired higlight class for the object/row */ public function GetHilightClass() { // Possible return values are: // HILIGHT_CLASS_CRITICAL, HILIGHT_CLASS_WARNING, HILIGHT_CLASS_OK, HILIGHT_CLASS_NONE return HILIGHT_CLASS_NONE; // Not hilighted by default } } ?>