/** * Helper to link objects * * @param string sLinkAttCode * @param string sLinkedClass * @param array $aLinkList * @param DBObject oTargetObj * @param WebServiceResult oRes * * @return array List of objects that could not be found */ protected function AddLinkedObjects($sLinkAttCode, $sParamName, $sLinkedClass, $aLinkList, &$oTargetObj, &$oRes) { $oLinkAtt = MetaModel::GetAttributeDef(get_class($oTargetObj), $sLinkAttCode); $sLinkClass = $oLinkAtt->GetLinkedClass(); $sExtKeyToItem = $oLinkAtt->GetExtKeyToRemote(); $aItemsFound = array(); $aItemsNotFound = array(); if (is_null($aLinkList)) { return $aItemsNotFound; } foreach ($aLinkList as $aItemData) { if (!array_key_exists('class', $aItemData)) { $oRes->LogWarning("Parameter {$sParamName}: missing 'class' specification"); continue; // skip } $sTargetClass = $aItemData['class']; if (!MetaModel::IsValidClass($sTargetClass)) { $oRes->LogError("Parameter {$sParamName}: invalid class '{$sTargetClass}'"); continue; // skip } if (!MetaModel::IsParentClass($sLinkedClass, $sTargetClass)) { $oRes->LogError("Parameter {$sParamName}: '{$sTargetClass}' is not a child class of '{$sLinkedClass}'"); continue; // skip } $oReconFilter = new CMDBSearchFilter($sTargetClass); $aCIStringDesc = array(); foreach ($aItemData['search'] as $sAttCode => $value) { if (!MetaModel::IsValidFilterCode($sTargetClass, $sAttCode)) { $aCodes = array_keys(MetaModel::GetClassFilterDefs($sTargetClass)); $oRes->LogError("Parameter {$sParamName}: '{$sAttCode}' is not a valid filter code for class '{$sTargetClass}', expecting a value in {" . implode(', ', $aCodes) . "}"); continue 2; // skip the entire item } $aCIStringDesc[] = "{$sAttCode}: {$value}"; // The attribute is one of our reconciliation key $oReconFilter->AddCondition($sAttCode, $value, '='); } if (count($aCIStringDesc) == 1) { // take the last and unique value to describe the object $sItemDesc = $value; } else { // describe the object by the given keys $sItemDesc = $sTargetClass . '(' . implode('/', $aCIStringDesc) . ')'; } $oExtObjects = new CMDBObjectSet($oReconFilter); switch ($oExtObjects->Count()) { case 0: $oRes->LogWarning("Parameter {$sParamName}: object to link {$sLinkedClass} / {$sItemDesc} could not be found (searched: '" . $oReconFilter->ToOQL(true) . "')"); $aItemsNotFound[] = $sItemDesc; break; case 1: $aItemsFound[] = array('object' => $oExtObjects->Fetch(), 'link_values' => @$aItemData['link_values'], 'desc' => $sItemDesc); break; default: $oRes->LogWarning("Parameter {$sParamName}: Found " . $oExtObjects->Count() . " matches for item '{$sItemDesc}' (searched: '" . $oReconFilter->ToOQL(true) . "')"); $aItemsNotFound[] = $sItemDesc; } } if (count($aItemsFound) > 0) { $aLinks = array(); foreach ($aItemsFound as $aItemData) { $oLink = MetaModel::NewObject($sLinkClass); $oLink->Set($sExtKeyToItem, $aItemData['object']->GetKey()); foreach ($aItemData['link_values'] as $sKey => $value) { if (!MetaModel::IsValidAttCode($sLinkClass, $sKey)) { $oRes->LogWarning("Parameter {$sParamName}: Attaching item '" . $aItemData['desc'] . "', the attribute code '{$sKey}' is not valid ; check the class '{$sLinkClass}'"); } else { $oLink->Set($sKey, $value); } } $aLinks[] = $oLink; } $oImpactedInfraSet = DBObjectSet::FromArray($sLinkClass, $aLinks); $oTargetObj->Set($sLinkAttCode, $oImpactedInfraSet); } return $aItemsNotFound; }
public function IsValidFilterCode($sClass, $sFilterCode) { return MetaModel::IsValidFilterCode($sClass, $sFilterCode); }
$oP->add('<div class="page_header"><h1>' . Dict::S('UI:Audit:InteractiveAudit') . '</h1><img style="margin-top: -20px; margin-right: 10px; float: right;" src="../images/clean.png"/></div>'); $oAuditFilter = new DBObjectSearch('AuditCategory'); $oCategoriesSet = new DBObjectSet($oAuditFilter); $oP->add("<table style=\"margin-top: 1em; padding: 0px; border-top: 3px solid #f6f6f1; border-left: 3px solid #f6f6f1; border-bottom: 3px solid #e6e6e1;\tborder-right: 3px solid #e6e6e1;\">\n"); $oP->add("<tr><td>\n"); $oP->add("<table>\n"); $oP->add("<tr>\n"); $oP->add("<th><img src=\"../images/minus.gif\"></th><th class=\"alignLeft\">" . Dict::S('UI:Audit:HeaderAuditRule') . "</th><th>" . Dict::S('UI:Audit:HeaderNbObjects') . "</th><th>" . Dict::S('UI:Audit:HeaderNbErrors') . "</th><th>" . Dict::S('UI:Audit:PercentageOk') . "</th>\n"); $oP->add("</tr>\n"); while ($oAuditCategory = $oCategoriesSet->fetch()) { try { $oDefinitionFilter = DBObjectSearch::FromOQL($oAuditCategory->Get('definition_set')); FilterByContext($oDefinitionFilter, $oAppContext); $aObjectsWithErrors = array(); if (!empty($currentOrganization)) { if (MetaModel::IsValidFilterCode($oDefinitionFilter->GetClass(), 'org_id')) { $oDefinitionFilter->AddCondition('org_id', $currentOrganization, '='); } } $aResults = array(); $oDefinitionSet = new CMDBObjectSet($oDefinitionFilter); $iCount = $oDefinitionSet->Count(); $oRulesFilter = new DBObjectSearch('AuditRule'); $oRulesFilter->AddCondition('category_id', $oAuditCategory->GetKey(), '='); $oRulesSet = new DBObjectSet($oRulesFilter); while ($oAuditRule = $oRulesSet->fetch()) { $aRow = array(); $aRow['description'] = $oAuditRule->GetName(); if ($iCount == 0) { // nothing to check, really ! $aRow['nb_errors'] = "<a href=\"audit.php?operation=errors&category=" . $oAuditCategory->GetKey() . "&rule=" . $oAuditRule->GetKey() . "\">0</a>";
public function GetRenderContent(WebPage $oPage, $aExtraParams = array(), $sId) { $sHtml = ''; // Add the extra params into the filter if they make sense for such a filter $bDoSearch = utils::ReadParam('dosearch', false); if ($this->m_oSet == null) { $aQueryParams = array(); if (isset($aExtraParams['query_params'])) { $aQueryParams = $aExtraParams['query_params']; } if ($this->m_sStyle != 'links') { $oAppContext = new ApplicationContext(); $sClass = $this->m_oFilter->GetClass(); $aFilterCodes = array_keys(MetaModel::GetClassFilterDefs($sClass)); $aCallSpec = array($sClass, 'MapContextParam'); if (is_callable($aCallSpec)) { foreach ($oAppContext->GetNames() as $sContextParam) { $sParamCode = call_user_func($aCallSpec, $sContextParam); //Map context parameter to the value/filter code depending on the class if (!is_null($sParamCode)) { $sParamValue = $oAppContext->GetCurrentValue($sContextParam, null); if (!is_null($sParamValue)) { $aExtraParams[$sParamCode] = $sParamValue; } } } } foreach ($aFilterCodes as $sFilterCode) { $externalFilterValue = utils::ReadParam($sFilterCode, '', false, 'raw_data'); $condition = null; if (isset($aExtraParams[$sFilterCode])) { $condition = $aExtraParams[$sFilterCode]; } if ($bDoSearch && $externalFilterValue != "") { // Search takes precedence over context params... unset($aExtraParams[$sFilterCode]); if (!is_array($externalFilterValue)) { $condition = trim($externalFilterValue); } else { if (count($externalFilterValue) == 1) { $condition = trim($externalFilterValue[0]); } else { $condition = $externalFilterValue; } } } if (!is_null($condition)) { $sOpCode = null; // default operator if (is_array($condition)) { // Multiple values, add them as AND X IN (v1, v2, v3...) $sOpCode = 'IN'; } $this->AddCondition($sFilterCode, $condition, $sOpCode); } } if ($bDoSearch) { // Keep the table_id identifying this table if we're performing a search $sTableId = utils::ReadParam('_table_id_', null, false, 'raw_data'); if ($sTableId != null) { $aExtraParams['table_id'] = $sTableId; } } } $aOrderBy = array(); if (isset($aExtraParams['order_by'])) { // Convert the string describing the order_by parameter into an array // The syntax is +attCode1,-attCode2 // attCode1 => ascending, attCode2 => descending $aTemp = explode(',', $aExtraParams['order_by']); foreach ($aTemp as $sTemp) { $aMatches = array(); if (preg_match('/^([+-])?(.+)$/', $sTemp, $aMatches)) { $bAscending = true; if ($aMatches[1] == '-') { $bAscending = false; } $aOrderBy[$aMatches[2]] = $bAscending; } } } $this->m_oSet = new CMDBObjectSet($this->m_oFilter, $aOrderBy, $aQueryParams); } switch ($this->m_sStyle) { case 'count': if (isset($aExtraParams['group_by'])) { if (isset($aExtraParams['group_by_label'])) { $oGroupByExp = Expression::FromOQL($aExtraParams['group_by']); $sGroupByLabel = $aExtraParams['group_by_label']; } else { // Backward compatibility: group_by is simply a field id $sAlias = $this->m_oFilter->GetClassAlias(); $oGroupByExp = new FieldExpression($aExtraParams['group_by'], $sAlias); $sGroupByLabel = MetaModel::GetLabel($this->m_oFilter->GetClass(), $aExtraParams['group_by']); } $aGroupBy = array(); $aGroupBy['grouped_by_1'] = $oGroupByExp; $sSql = $this->m_oFilter->MakeGroupByQuery($aQueryParams, $aGroupBy, true); $aRes = CMDBSource::QueryToArray($sSql); $aGroupBy = array(); $aLabels = array(); $aValues = array(); $iTotalCount = 0; foreach ($aRes as $iRow => $aRow) { $sValue = $aRow['grouped_by_1']; $aValues[$iRow] = $sValue; $sHtmlValue = $oGroupByExp->MakeValueLabel($this->m_oFilter, $sValue, $sValue); $aLabels[$iRow] = $sHtmlValue; $aGroupBy[$iRow] = (int) $aRow['_itop_count_']; $iTotalCount += $aRow['_itop_count_']; } $aData = array(); $oAppContext = new ApplicationContext(); $sParams = $oAppContext->GetForLink(); foreach ($aGroupBy as $iRow => $iCount) { // Build the search for this subset $oSubsetSearch = $this->m_oFilter->DeepClone(); $oCondition = new BinaryExpression($oGroupByExp, '=', new ScalarExpression($aValues[$iRow])); $oSubsetSearch->AddConditionExpression($oCondition); $sFilter = urlencode($oSubsetSearch->serialize()); $aData[] = array('group' => $aLabels[$iRow], 'value' => "<a href=\"" . utils::GetAbsoluteUrlAppRoot() . "pages/UI.php?operation=search&dosearch=1&{$sParams}&filter={$sFilter}\">{$iCount}</a>"); // TO DO: add the context information } $aAttribs = array('group' => array('label' => $sGroupByLabel, 'description' => ''), 'value' => array('label' => Dict::S('UI:GroupBy:Count'), 'description' => Dict::S('UI:GroupBy:Count+'))); $sFormat = isset($aExtraParams['format']) ? $aExtraParams['format'] : 'UI:Pagination:HeaderNoSelection'; $sHtml .= $oPage->GetP(Dict::Format($sFormat, $iTotalCount)); $sHtml .= $oPage->GetTable($aAttribs, $aData); } else { // Simply count the number of elements in the set $iCount = $this->m_oSet->Count(); $sFormat = 'UI:CountOfObjects'; if (isset($aExtraParams['format'])) { $sFormat = $aExtraParams['format']; } $sHtml .= $oPage->GetP(Dict::Format($sFormat, $iCount)); } break; case 'join': $aDisplayAliases = isset($aExtraParams['display_aliases']) ? explode(',', $aExtraParams['display_aliases']) : array(); if (!isset($aExtraParams['group_by'])) { $sHtml .= $oPage->GetP(Dict::S('UI:Error:MandatoryTemplateParameter_group_by')); } else { $aGroupByFields = array(); $aGroupBy = explode(',', $aExtraParams['group_by']); foreach ($aGroupBy as $sGroupBy) { $aMatches = array(); if (preg_match('/^(.+)\\.(.+)$/', $sGroupBy, $aMatches) > 0) { $aGroupByFields[] = array('alias' => $aMatches[1], 'att_code' => $aMatches[2]); } } if (count($aGroupByFields) == 0) { $sHtml .= $oPage->GetP(Dict::Format('UI:Error:InvalidGroupByFields', $aExtraParams['group_by'])); } else { $aResults = array(); $aCriteria = array(); while ($aObjects = $this->m_oSet->FetchAssoc()) { $aKeys = array(); foreach ($aGroupByFields as $aField) { $sAlias = $aField['alias']; if (is_null($aObjects[$sAlias])) { $aKeys[$sAlias . '.' . $aField['att_code']] = ''; } else { $aKeys[$sAlias . '.' . $aField['att_code']] = $aObjects[$sAlias]->Get($aField['att_code']); } } $sCategory = implode($aKeys, ' '); $aResults[$sCategory][] = $aObjects; $aCriteria[$sCategory] = $aKeys; } $sHtml .= "<table>\n"; // Construct a new (parametric) query that will return the content of this block $oBlockFilter = $this->m_oFilter->DeepClone(); $aExpressions = array(); $index = 0; foreach ($aGroupByFields as $aField) { $aExpressions[] = '`' . $aField['alias'] . '`.`' . $aField['att_code'] . '` = :param' . $index++; } $sExpression = implode(' AND ', $aExpressions); $oExpression = Expression::FromOQL($sExpression); $oBlockFilter->AddConditionExpression($oExpression); $aExtraParams['menu'] = false; foreach ($aResults as $sCategory => $aObjects) { $sHtml .= "<tr><td><h1>{$sCategory}</h1></td></tr>\n"; if (count($aDisplayAliases) == 1) { $aSimpleArray = array(); foreach ($aObjects as $aRow) { $oObj = $aRow[$aDisplayAliases[0]]; if (!is_null($oObj)) { $aSimpleArray[] = $oObj; } } $oSet = CMDBObjectSet::FromArray($this->m_oFilter->GetClass(), $aSimpleArray); $sHtml .= "<tr><td>" . cmdbAbstractObject::GetDisplaySet($oPage, $oSet, $aExtraParams) . "</td></tr>\n"; } else { $index = 0; $aArgs = array(); foreach ($aGroupByFields as $aField) { $aArgs['param' . $index] = $aCriteria[$sCategory][$aField['alias'] . '.' . $aField['att_code']]; $index++; } $oSet = new CMDBObjectSet($oBlockFilter, array(), $aArgs); $sHtml .= "<tr><td>" . cmdbAbstractObject::GetDisplayExtendedSet($oPage, $oSet, $aExtraParams) . "</td></tr>\n"; } } $sHtml .= "</table>\n"; } } break; case 'list': $aClasses = $this->m_oSet->GetSelectedClasses(); $aAuthorizedClasses = array(); if (count($aClasses) > 1) { // Check the classes that can be read (i.e authorized) by this user... foreach ($aClasses as $sAlias => $sClassName) { if (UserRights::IsActionAllowed($sClassName, UR_ACTION_READ, $this->m_oSet) && (UR_ALLOWED_YES || UR_ALLOWED_DEPENDS)) { $aAuthorizedClasses[$sAlias] = $sClassName; } } if (count($aAuthorizedClasses) > 0) { if ($this->m_oSet->Count() > 0) { $sHtml .= cmdbAbstractObject::GetDisplayExtendedSet($oPage, $this->m_oSet, $aExtraParams); } else { // Empty set $sHtml .= $oPage->GetP(Dict::S('UI:NoObjectToDisplay')); } } else { // Not authorized $sHtml .= $oPage->GetP(Dict::S('UI:NoObjectToDisplay')); } } else { // The list is made of only 1 class of objects, actions on the list are possible if ($this->m_oSet->Count() > 0 && UserRights::IsActionAllowed($this->m_oSet->GetClass(), UR_ACTION_READ, $this->m_oSet) == UR_ALLOWED_YES) { $sHtml .= cmdbAbstractObject::GetDisplaySet($oPage, $this->m_oSet, $aExtraParams); } else { $sHtml .= $oPage->GetP(Dict::S('UI:NoObjectToDisplay')); $sClass = $this->m_oFilter->GetClass(); $bDisplayMenu = isset($aExtraParams['menu']) ? $aExtraParams['menu'] == true : true; if ($bDisplayMenu) { if (UserRights::IsActionAllowed($sClass, UR_ACTION_MODIFY) == UR_ALLOWED_YES) { $sLinkTarget = ''; $oAppContext = new ApplicationContext(); $sParams = $oAppContext->GetForLink(); // 1:n links, populate the target object as a default value when creating a new linked object if (isset($aExtraParams['target_attr'])) { $sLinkTarget = ' target="_blank" '; $aExtraParams['default'][$aExtraParams['target_attr']] = $aExtraParams['object_id']; } $sDefault = ''; if (!empty($aExtraParams['default'])) { foreach ($aExtraParams['default'] as $sKey => $sValue) { $sDefault .= "&default[{$sKey}]={$sValue}"; } } $sHtml .= $oPage->GetP("<a{$sLinkTarget} href=\"" . utils::GetAbsoluteUrlAppRoot() . "pages/UI.php?operation=new&class={$sClass}&{$sParams}{$sDefault}\">" . Dict::Format('UI:ClickToCreateNew', Metamodel::GetName($sClass)) . "</a>\n"); } } } } break; case 'links': //$bDashboardMode = isset($aExtraParams['dashboard']) ? ($aExtraParams['dashboard'] == 'true') : false; //$bSelectMode = isset($aExtraParams['select']) ? ($aExtraParams['select'] == 'true') : false; if ($this->m_oSet->Count() > 0 && UserRights::IsActionAllowed($this->m_oSet->GetClass(), UR_ACTION_READ, $this->m_oSet) == UR_ALLOWED_YES) { //$sLinkage = isset($aExtraParams['linkage']) ? $aExtraParams['linkage'] : ''; $sHtml .= cmdbAbstractObject::GetDisplaySet($oPage, $this->m_oSet, $aExtraParams); } else { $sClass = $this->m_oFilter->GetClass(); $oAttDef = MetaModel::GetAttributeDef($sClass, $this->m_aParams['target_attr']); $sTargetClass = $oAttDef->GetTargetClass(); $sHtml .= $oPage->GetP(Dict::Format('UI:NoObject_Class_ToDisplay', MetaModel::GetName($sTargetClass))); $bDisplayMenu = isset($this->m_aParams['menu']) ? $this->m_aParams['menu'] == true : true; if ($bDisplayMenu) { if (UserRights::IsActionAllowed($sClass, UR_ACTION_MODIFY) == UR_ALLOWED_YES) { $oAppContext = new ApplicationContext(); $sParams = $oAppContext->GetForLink(); $sDefaults = ''; if (isset($this->m_aParams['default'])) { foreach ($this->m_aParams['default'] as $sName => $sValue) { $sDefaults .= '&' . urlencode($sName) . '=' . urlencode($sValue); } } $sHtml .= $oPage->GetP("<a href=\"" . utils::GetAbsoluteUrlAppRoot() . "pages/UI.php?operation=modify_links&class={$sClass}&sParams&link_attr=" . $aExtraParams['link_attr'] . "&id=" . $aExtraParams['object_id'] . "&target_class={$sTargetClass}&addObjects=true{$sDefaults}\">" . Dict::Format('UI:ClickToCreateNew', Metamodel::GetName($sClass)) . "</a>\n"); } } } break; case 'details': while ($oObj = $this->m_oSet->Fetch()) { $sHtml .= $oObj->GetDetails($oPage); // Still used ??? } break; case 'actions': $sClass = $this->m_oFilter->GetClass(); $oAppContext = new ApplicationContext(); $bContextFilter = isset($aExtraParams['context_filter']) ? isset($aExtraParams['context_filter']) != 0 : false; if ($bContextFilter) { $aFilterCodes = array_keys(MetaModel::GetClassFilterDefs($this->m_oFilter->GetClass())); foreach ($oAppContext->GetNames() as $sFilterCode) { $sContextParamValue = $oAppContext->GetCurrentValue($sFilterCode, null); if (!is_null($sContextParamValue) && !empty($sContextParamValue) && MetaModel::IsValidFilterCode($sClass, $sFilterCode)) { $this->AddCondition($sFilterCode, $sContextParamValue); } } $aQueryParams = array(); if (isset($aExtraParams['query_params'])) { $aQueryParams = $aExtraParams['query_params']; } $this->m_oSet = new CMDBObjectSet($this->m_oFilter, array(), $aQueryParams); } $iCount = $this->m_oSet->Count(); $sHyperlink = utils::GetAbsoluteUrlAppRoot() . 'pages/UI.php?operation=search&' . $oAppContext->GetForLink() . '&filter=' . urlencode($this->m_oFilter->serialize()); $sHtml .= '<p><a class="actions" href="' . $sHyperlink . '">'; // Note: border set to 0 due to various browser interpretations (IE9 adding a 2px border) $sHtml .= MetaModel::GetClassIcon($sClass, true, 'float;left;margin-right:10px;border:0;'); $sHtml .= MetaModel::GetName($sClass) . ': ' . $iCount . '</a></p>'; $sParams = $oAppContext->GetForLink(); $sHtml .= '<p>'; if (UserRights::IsActionAllowed($sClass, UR_ACTION_MODIFY)) { $sHtml .= "<a href=\"" . utils::GetAbsoluteUrlAppRoot() . "pages/UI.php?operation=new&class={$sClass}&{$sParams}\">" . Dict::Format('UI:ClickToCreateNew', MetaModel::GetName($sClass)) . "</a><br/>\n"; } $sHtml .= "<a href=\"" . utils::GetAbsoluteUrlAppRoot() . "pages/UI.php?operation=search_form&do_search=0&class={$sClass}&{$sParams}\">" . Dict::Format('UI:SearchFor_Class', MetaModel::GetName($sClass)) . "</a>\n"; $sHtml .= '</p>'; break; case 'summary': $sClass = $this->m_oFilter->GetClass(); $oAppContext = new ApplicationContext(); $sTitle = isset($aExtraParams['title[block]']) ? $aExtraParams['title[block]'] : ''; $sLabel = isset($aExtraParams['label[block]']) ? $aExtraParams['label[block]'] : ''; $sStateAttrCode = isset($aExtraParams['status[block]']) ? $aExtraParams['status[block]'] : 'status'; $sStatesList = isset($aExtraParams['status_codes[block]']) ? $aExtraParams['status_codes[block]'] : ''; $bContextFilter = isset($aExtraParams['context_filter']) ? isset($aExtraParams['context_filter']) != 0 : false; if ($bContextFilter) { $aFilterCodes = array_keys(MetaModel::GetClassFilterDefs($this->m_oFilter->GetClass())); foreach ($oAppContext->GetNames() as $sFilterCode) { $sContextParamValue = $oAppContext->GetCurrentValue($sFilterCode, null); if (!is_null($sContextParamValue) && !empty($sContextParamValue) && MetaModel::IsValidFilterCode($sClass, $sFilterCode)) { $this->AddCondition($sFilterCode, $sContextParamValue); } } $aQueryParams = array(); if (isset($aExtraParams['query_params'])) { $aQueryParams = $aExtraParams['query_params']; } $this->m_oSet = new CMDBObjectSet($this->m_oFilter, array(), $aQueryParams); } // Summary details $aCounts = array(); $aStateLabels = array(); if (!empty($sStateAttrCode) && !empty($sStatesList)) { $aStates = explode(',', $sStatesList); $oAttDef = MetaModel::GetAttributeDef($sClass, $sStateAttrCode); foreach ($aStates as $sStateValue) { $oFilter = $this->m_oFilter->DeepClone(); $oFilter->AddCondition($sStateAttrCode, $sStateValue, '='); $oSet = new DBObjectSet($oFilter); $aCounts[$sStateValue] = $oSet->Count(); $aStateLabels[$sStateValue] = htmlentities($oAttDef->GetValueLabel($sStateValue), ENT_QUOTES, 'UTF-8'); if ($aCounts[$sStateValue] == 0) { $aCounts[$sStateValue] = '-'; } else { $sHyperlink = utils::GetAbsoluteUrlAppRoot() . 'pages/UI.php?operation=search&' . $oAppContext->GetForLink() . '&filter=' . urlencode($oFilter->serialize()); $aCounts[$sStateValue] = "<a href=\"{$sHyperlink}\">{$aCounts[$sStateValue]}</a>"; } } } $sHtml .= '<div class="summary-details"><table><tr><th>' . implode('</th><th>', $aStateLabels) . '</th></tr>'; $sHtml .= '<tr><td>' . implode('</td><td>', $aCounts) . '</td></tr></table></div>'; // Title & summary $iCount = $this->m_oSet->Count(); $sHyperlink = utils::GetAbsoluteUrlAppRoot() . 'pages/UI.php?operation=search&' . $oAppContext->GetForLink() . '&filter=' . urlencode($this->m_oFilter->serialize()); $sHtml .= '<h1>' . Dict::S(str_replace('_', ':', $sTitle)) . '</h1>'; $sHtml .= '<a class="summary" href="' . $sHyperlink . '">' . Dict::Format(str_replace('_', ':', $sLabel), $iCount) . '</a>'; $sHtml .= '<div style="clear:both;"></div>'; break; case 'csv': $bAdvancedMode = utils::ReadParam('advanced', false); $sCsvFile = strtolower($this->m_oFilter->GetClass()) . '.csv'; $sDownloadLink = utils::GetAbsoluteUrlAppRoot() . 'webservices/export.php?expression=' . urlencode($this->m_oFilter->ToOQL(true)) . '&format=csv&filename=' . urlencode($sCsvFile); $sLinkToToggle = utils::GetAbsoluteUrlAppRoot() . 'pages/UI.php?operation=search&' . $oAppContext->GetForLink() . '&filter=' . urlencode($this->m_oFilter->serialize()) . '&format=csv'; if ($bAdvancedMode) { $sDownloadLink .= '&fields_advanced=1'; $sChecked = 'CHECKED'; } else { $sLinkToToggle = $sLinkToToggle . '&advanced=1'; $sChecked = ''; } $sAjaxLink = $sDownloadLink . '&charset=UTF-8'; // Includes &fields_advanced=1 if in advanced mode /* $sCSVData = cmdbAbstractObject::GetSetAsCSV($this->m_oSet, array('fields_advanced' => $bAdvancedMode)); $sCharset = MetaModel::GetConfig()->Get('csv_file_default_charset'); if ($sCharset == 'UTF-8') { $bLostChars = false; } else { $sConverted = @iconv('UTF-8', $sCharset, $sCSVData); $sRestored = @iconv($sCharset, 'UTF-8', $sConverted); $bLostChars = ($sRestored != $sCSVData); } if ($bLostChars) { $sCharsetNotice = " <span id=\"csv_charset_issue\">"; $sCharsetNotice .= '<img src="../images/error.png" style="vertical-align:middle"/>'; $sCharsetNotice .= "</span>"; $sTip = "<p>".htmlentities(Dict::S('UI:CSVExport:LostChars'), ENT_QUOTES, 'UTF-8')."</p>"; $sTip .= "<p>".htmlentities(Dict::Format('UI:CSVExport:LostChars+', $sCharset), ENT_QUOTES, 'UTF-8')."</p>"; $oPage->add_ready_script("$('#csv_charset_issue').qtip( { content: '$sTip', show: 'mouseover', hide: 'mouseout', style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );"); } else { $sCharsetNotice = ''; } */ $sCharsetNotice = false; $sHtml .= "<div>"; $sHtml .= '<table style="width:100%" class="transparent">'; $sHtml .= '<tr>'; $sHtml .= '<td><a href="' . $sDownloadLink . '">' . Dict::Format('UI:Download-CSV', $sCsvFile) . '</a>' . $sCharsetNotice . '</td>'; $sHtml .= '<td style="text-align:right"><input type="checkbox" ' . $sChecked . ' onClick="window.location.href=\'' . $sLinkToToggle . '\'"> ' . Dict::S('UI:CSVExport:AdvancedMode') . '</td>'; $sHtml .= '</tr>'; $sHtml .= '</table>'; if ($bAdvancedMode) { $sHtml .= "<p>"; $sHtml .= htmlentities(Dict::S('UI:CSVExport:AdvancedMode+'), ENT_QUOTES, 'UTF-8'); $sHtml .= "</p>"; } $sHtml .= "</div>"; $sHtml .= "<div id=\"csv_content_loading\"><div style=\"width: 250px; height: 20px; background: url(../setup/orange-progress.gif); border: 1px #999 solid; margin-left:auto; margin-right: auto; text-align: center;\">" . Dict::S('UI:Loading') . "</div></div><textarea id=\"csv_content\" style=\"display:none;\">\n"; //$sHtml .= htmlentities($sCSVData, ENT_QUOTES, 'UTF-8'); $sHtml .= "</textarea>\n"; $oPage->add_ready_script("\$.post('{$sAjaxLink}', {}, function(data) { \$('#csv_content').html(data); \$('#csv_content_loading').hide(); \$('#csv_content').show();} );"); break; case 'modify': if (UserRights::IsActionAllowed($this->m_oSet->GetClass(), UR_ACTION_MODIFY, $this->m_oSet) == UR_ALLOWED_YES) { while ($oObj = $this->m_oSet->Fetch()) { $sHtml .= $oObj->GetModifyForm($oPage); } } break; case 'search': $sStyle = isset($aExtraParams['open']) && $aExtraParams['open'] == 'true' ? 'SearchDrawer' : 'SearchDrawer DrawerClosed'; $sHtml .= "<div id=\"ds_{$sId}\" class=\"{$sStyle}\">\n"; $oPage->add_ready_script(<<<EOF \t\$("#dh_{$sId}").click( function() { \t\t\$("#ds_{$sId}").slideToggle('normal', function() { \$("#ds_{$sId}").parent().resize(); FixSearchFormsDisposition(); } ); \t\t\$("#dh_{$sId}").toggleClass('open'); \t}); EOF ); $aExtraParams['currentId'] = $sId; $sHtml .= cmdbAbstractObject::GetSearchForm($oPage, $this->m_oSet, $aExtraParams); $sHtml .= "</div>\n"; $sHtml .= "<div class=\"HRDrawer\"></div>\n"; $sHtml .= "<div id=\"dh_{$sId}\" class=\"DrawerHandle\">" . Dict::S('UI:SearchToggle') . "</div>\n"; break; case 'open_flash_chart': static $iChartCounter = 0; $oAppContext = new ApplicationContext(); $sContext = $oAppContext->GetForLink(); if (!empty($sContext)) { $sContext = '&' . $sContext; } $sChartType = isset($aExtraParams['chart_type']) ? $aExtraParams['chart_type'] : 'pie'; $sTitle = isset($aExtraParams['chart_title']) ? $aExtraParams['chart_title'] : ''; $sGroupBy = isset($aExtraParams['group_by']) ? $aExtraParams['group_by'] : ''; $sGroupByExpr = isset($aExtraParams['group_by_expr']) ? '¶ms[group_by_expr]=' . $aExtraParams['group_by_expr'] : ''; $sFilter = $this->m_oFilter->serialize(); $sHtml .= "<div id=\"my_chart_{$sId}{$iChartCounter}\">If the chart does not display, <a href=\"http://get.adobe.com/flash/\" target=\"_blank\">install Flash</a></div>\n"; $oPage->add_script("function ofc_resize(left, width, top, height) { /* do nothing special */ }"); if (isset($aExtraParams['group_by_label'])) { $sUrl = urlencode(utils::GetAbsoluteUrlAppRoot() . "pages/ajax.render.php?operation=open_flash_chart¶ms[group_by]={$sGroupBy}{$sGroupByExpr}¶ms[group_by_label]={$aExtraParams['group_by_label']}¶ms[chart_type]={$sChartType}¶ms[chart_title]={$sTitle}¶ms[currentId]={$sId}&id={$sId}&filter=" . urlencode($sFilter)); } else { $sUrl = urlencode(utils::GetAbsoluteUrlAppRoot() . "pages/ajax.render.php?operation=open_flash_chart¶ms[group_by]={$sGroupBy}{$sGroupByExpr}¶ms[chart_type]={$sChartType}¶ms[chart_title]={$sTitle}¶ms[currentId]={$sId}&id={$sId}&filter=" . urlencode($sFilter)); } $oPage->add_ready_script("swfobject.embedSWF(\"../images/open-flash-chart.swf\", \"my_chart_{$sId}{$iChartCounter}\", \"100%\", \"300\",\"9.0.0\", \"expressInstall.swf\",\n\t\t\t\t{\"data-file\":\"" . $sUrl . "\"}, {wmode: 'transparent'} );\n"); $iChartCounter++; if (isset($aExtraParams['group_by'])) { if (isset($aExtraParams['group_by_label'])) { $oGroupByExp = Expression::FromOQL($aExtraParams['group_by']); $sGroupByLabel = $aExtraParams['group_by_label']; } else { // Backward compatibility: group_by is simply a field id $sAlias = $this->m_oFilter->GetClassAlias(); $oGroupByExp = new FieldExpression($aExtraParams['group_by'], $sAlias); $sGroupByLabel = MetaModel::GetLabel($this->m_oFilter->GetClass(), $aExtraParams['group_by']); } $aGroupBy = array(); $aGroupBy['grouped_by_1'] = $oGroupByExp; $sSql = $this->m_oFilter->MakeGroupByQuery($aQueryParams, $aGroupBy, true); $aRes = CMDBSource::QueryToArray($sSql); $aGroupBy = array(); $aLabels = array(); $aValues = array(); $iTotalCount = 0; foreach ($aRes as $iRow => $aRow) { $sValue = $aRow['grouped_by_1']; $aValues[$iRow] = $sValue; $sHtmlValue = $oGroupByExp->MakeValueLabel($this->m_oFilter, $sValue, $sValue); $aLabels[$iRow] = $sHtmlValue; $aGroupBy[$iRow] = (int) $aRow['_itop_count_']; $iTotalCount += $aRow['_itop_count_']; } $aData = array(); $idx = 0; $aURLs = array(); foreach ($aGroupBy as $iRow => $iCount) { // Build the search for this subset $oSubsetSearch = $this->m_oFilter->DeepClone(); $oCondition = new BinaryExpression($oGroupByExp, '=', new ScalarExpression($aValues[$iRow])); $oSubsetSearch->AddConditionExpression($oCondition); $aURLs[$idx] = $oSubsetSearch->serialize(); $idx++; } $sURLList = ''; foreach ($aURLs as $index => $sURL) { $sURLList .= "\taURLs[{$index}] = '" . utils::GetAbsoluteUrlAppRoot() . "pages/UI.php?operation=search&format=html{$sContext}&filter=" . urlencode($sURL) . "';\n"; } $oPage->add_script(<<<EOF function ofc_drill_down_{$sId}(index) { \tvar aURLs = new Array(); {$sURLList} \twindow.location.href=aURLs[index]; } EOF ); } break; case 'open_flash_chart_ajax': require_once APPROOT . '/pages/php-ofc-library/open-flash-chart.php'; $sChartType = isset($aExtraParams['chart_type']) ? $aExtraParams['chart_type'] : 'pie'; $sId = utils::ReadParam('id', ''); $oChart = new open_flash_chart(); switch ($sChartType) { case 'bars': $oChartElement = new bar_glass(); if (isset($aExtraParams['group_by'])) { if (isset($aExtraParams['group_by_label'])) { $oGroupByExp = Expression::FromOQL($aExtraParams['group_by']); $sGroupByLabel = $aExtraParams['group_by_label']; } else { // Backward compatibility: group_by is simply a field id $sAlias = $this->m_oFilter->GetClassAlias(); $oGroupByExp = new FieldExpression($aExtraParams['group_by'], $sAlias); $sGroupByLabel = MetaModel::GetLabel($this->m_oFilter->GetClass(), $aExtraParams['group_by']); } $aGroupBy = array(); $aGroupBy['grouped_by_1'] = $oGroupByExp; $sSql = $this->m_oFilter->MakeGroupByQuery($aQueryParams, $aGroupBy, true); $aRes = CMDBSource::QueryToArray($sSql); $aGroupBy = array(); $aLabels = array(); $iTotalCount = 0; foreach ($aRes as $iRow => $aRow) { $sValue = $aRow['grouped_by_1']; $sHtmlValue = $oGroupByExp->MakeValueLabel($this->m_oFilter, $sValue, $sValue); $aLabels[$iRow] = strip_tags($sHtmlValue); $aGroupBy[$iRow] = (int) $aRow['_itop_count_']; $iTotalCount += $aRow['_itop_count_']; } $aData = array(); $aChartLabels = array(); $maxValue = 0; foreach ($aGroupBy as $iRow => $iCount) { $oBarValue = new bar_value($iCount); $oBarValue->on_click("ofc_drill_down_{$sId}"); $aData[] = $oBarValue; if ($iCount > $maxValue) { $maxValue = $iCount; } $aChartLabels[] = html_entity_decode($aLabels[$iRow], ENT_QUOTES, 'UTF-8'); } $oYAxis = new y_axis(); $aMagicValues = array(1, 2, 5, 10); $iMultiplier = 1; $index = 0; $iTop = $aMagicValues[$index % count($aMagicValues)] * $iMultiplier; while ($maxValue > $iTop) { $index++; $iTop = $aMagicValues[$index % count($aMagicValues)] * $iMultiplier; if ($index % count($aMagicValues) == 0) { $iMultiplier = $iMultiplier * 10; } } //echo "oYAxis->set_range(0, $iTop, $iMultiplier);\n"; $oYAxis->set_range(0, $iTop, $iMultiplier); $oChart->set_y_axis($oYAxis); $oChartElement->set_values($aData); $oXAxis = new x_axis(); $oXLabels = new x_axis_labels(); // set them vertical $oXLabels->set_vertical(); // set the label text $oXLabels->set_labels($aChartLabels); // Add the X Axis Labels to the X Axis $oXAxis->set_labels($oXLabels); $oChart->set_x_axis($oXAxis); } break; case 'pie': default: $oChartElement = new pie(); $oChartElement->set_start_angle(35); $oChartElement->set_animate(true); $oChartElement->set_tooltip('#label# - #val# (#percent#)'); $oChartElement->set_colours(array('#FF8A00', '#909980', '#2C2B33', '#CCC08D', '#596664')); if (isset($aExtraParams['group_by'])) { if (isset($aExtraParams['group_by_label'])) { $oGroupByExp = Expression::FromOQL($aExtraParams['group_by']); $sGroupByLabel = $aExtraParams['group_by_label']; } else { // Backward compatibility: group_by is simply a field id $sAlias = $this->m_oFilter->GetClassAlias(); $oGroupByExp = new FieldExpression($aExtraParams['group_by'], $sAlias); $sGroupByLabel = MetaModel::GetLabel($this->m_oFilter->GetClass(), $aExtraParams['group_by']); } $aGroupBy = array(); $aGroupBy['grouped_by_1'] = $oGroupByExp; $sSql = $this->m_oFilter->MakeGroupByQuery($aQueryParams, $aGroupBy, true); $aRes = CMDBSource::QueryToArray($sSql); $aGroupBy = array(); $aLabels = array(); $iTotalCount = 0; foreach ($aRes as $iRow => $aRow) { $sValue = $aRow['grouped_by_1']; $sHtmlValue = $oGroupByExp->MakeValueLabel($this->m_oFilter, $sValue, $sValue); $aLabels[$iRow] = strip_tags($sHtmlValue); $aGroupBy[$iRow] = (int) $aRow['_itop_count_']; $iTotalCount += $aRow['_itop_count_']; } $aData = array(); foreach ($aGroupBy as $iRow => $iCount) { $sFlashLabel = html_entity_decode($aLabels[$iRow], ENT_QUOTES, 'UTF-8'); $PieValue = new pie_value($iCount, $sFlashLabel); //@@ BUG: not passed via ajax !!! $PieValue->on_click("ofc_drill_down_{$sId}"); $aData[] = $PieValue; } $oChartElement->set_values($aData); $oChart->x_axis = null; } } if (isset($aExtraParams['chart_title'])) { // The title has been given in an url, and urlencoded... // and urlencode transforms utf-8 into something similar to ISO-8859-1 // Example: é (C3A9 becomes %E9) // As a consequence, json_encode (called within open-flash-chart.php) // was returning 'null' and the graph was not displayed at all // To make sure that the graph is displayed AND to get a correct title // (at least for european characters) let's transform back into utf-8 ! $sTitle = iconv("ISO-8859-1", "UTF-8//IGNORE", $aExtraParams['chart_title']); // If the title is a dictionnary entry, fetch it $sTitle = Dict::S($sTitle); $oTitle = new title($sTitle); $oChart->set_title($oTitle); $oTitle->set_style("{font-size: 16px; font-family: Tahoma; font-weight: bold; text-align: center;}"); } $oChart->set_bg_colour('#FFFFFF'); $oChart->add_element($oChartElement); $sHtml = $oChart->toPrettyString(); break; default: // Unsupported style, do nothing. $sHtml .= Dict::format('UI:Error:UnsupportedStyleOfBlock', $this->m_sStyle); } return $sHtml; }
/** * Process the CSV data, for real or as a simulation * @param WebPage $oPage The page used to display the wizard * @param bool $bSimulate Whether or not to simulate the data load * @return array The CSV lines in error that were rejected from the load (with the header line - if any) or null */ function ProcessCSVData(WebPage $oPage, $bSimulate = true) { $aResult = array(); $sCSVData = utils::ReadParam('csvdata', '', false, 'raw_data'); $sCSVDataTruncated = utils::ReadParam('csvdata_truncated', '', false, 'raw_data'); $sSeparator = utils::ReadParam('separator', ',', false, 'raw_data'); $sTextQualifier = utils::ReadParam('text_qualifier', '"', false, 'raw_data'); $bHeaderLine = utils::ReadParam('header_line', '0') == 1; $iSkippedLines = 0; if (utils::ReadParam('box_skiplines', '0') == 1) { $iSkippedLines = utils::ReadParam('nb_skipped_lines', '0'); } $sClassName = utils::ReadParam('class_name', '', false, 'class'); $aFieldsMapping = utils::ReadParam('field', array(), false, 'raw_data'); $aSearchFields = utils::ReadParam('search_field', array(), false, 'field_name'); $iCurrentStep = $bSimulate ? 4 : 5; $bAdvanced = utils::ReadParam('advanced', 0); $sEncoding = utils::ReadParam('encoding', 'UTF-8'); $sSynchroScope = utils::ReadParam('synchro_scope', '', false, 'raw_data'); if (!empty($sSynchroScope)) { $oSearch = DBObjectSearch::FromOQL($sSynchroScope); $sClassName = $oSearch->GetClass(); // If a synchronization scope is set, then the class is fixed ! $oSet = new DBObjectSet($oSearch); $iCount = $oSet->Count(); DisplaySynchroBanner($oPage, $sClassName, $iCount); $sClassesSelect = "<select id=\"select_class_name\" name=\"class_name\"><option value=\"{$sClassName}\" selected>" . MetaModel::GetName($sClassName) . "</option>"; $aSynchroUpdate = utils::ReadParam('synchro_update', array()); } else { $sSynchroScope = ''; $aSynchroUpdate = null; } // Parse the data set $oCSVParser = new CSVParser($sCSVData, $sSeparator, $sTextQualifier); $aData = $oCSVParser->ToArray($iSkippedLines); $iRealSkippedLines = $iSkippedLines; if ($bHeaderLine) { $aResult[] = $sTextQualifier . implode($sTextQualifier . $sSeparator . $sTextQualifier, array_shift($aData)) . $sTextQualifier; // Remove the first line and store it in case of error $iRealSkippedLines++; } // Format for the line numbers $sMaxLen = strlen('' . count($aData)) < 3 ? 3 : strlen('' . count($aData)); // Pad line numbers to the appropriate number of chars, but at least 3 // Compute the list of search/reconciliation criteria $aSearchKeys = array(); foreach ($aSearchFields as $index => $sDummy) { $sSearchField = $aFieldsMapping[$index]; $aMatches = array(); if (preg_match('/(.+)->(.+)/', $sSearchField, $aMatches) > 0) { $sSearchField = $aMatches[1]; $aSearchKeys[$aMatches[1]] = ''; } else { $aSearchKeys[$sSearchField] = ''; } if (!MetaModel::IsValidFilterCode($sClassName, $sSearchField)) { // Remove invalid or unmapped search fields $aSearchFields[$index] = null; unset($aSearchKeys[$sSearchField]); } } // Compute the list of fields and external keys to process $aExtKeys = array(); $aAttributes = array(); $aExternalKeysByColumn = array(); foreach ($aFieldsMapping as $iNumber => $sAttCode) { $iIndex = $iNumber - 1; if (!empty($sAttCode) && $sAttCode != ':none:' && $sAttCode != 'finalclass') { if (preg_match('/(.+)->(.+)/', $sAttCode, $aMatches) > 0) { $sAttribute = $aMatches[1]; $sField = $aMatches[2]; $aExtKeys[$sAttribute][$sField] = $iIndex; $aExternalKeysByColumn[$iIndex] = $sAttribute; } else { if ($sAttCode == 'id') { $aAttributes['id'] = $iIndex; } else { $oAttDef = MetaModel::GetAttributeDef($sClassName, $sAttCode); if ($oAttDef->IsExternalKey()) { $aExtKeys[$sAttCode]['id'] = $iIndex; $aExternalKeysByColumn[$iIndex] = $sAttCode; } else { $aAttributes[$sAttCode] = $iIndex; } } } } } $oMyChange = null; if (!$bSimulate) { // We're doing it for real, let's create a change $sUserString = CMDBChange::GetCurrentUserName() . ' (CSV)'; CMDBObject::SetTrackInfo($sUserString); CMDBObject::SetTrackOrigin('csv-interactive'); $oMyChange = CMDBObject::GetCurrentChange(); } $oBulk = new BulkChange($sClassName, $aData, $aAttributes, $aExtKeys, array_keys($aSearchKeys), empty($sSynchroScope) ? null : $sSynchroScope, $aSynchroUpdate, null, true); $oBulk->SetReportHtml(); $oPage->add('<input type="hidden" name="csvdata_truncated" id="csvdata_truncated" value="' . htmlentities($sCSVDataTruncated, ENT_QUOTES, 'UTF-8') . '"/>'); $aRes = $oBulk->Process($oMyChange); $sHtml = '<table id="bulk_preview" style="border-collapse: collapse;">'; $sHtml .= '<tr><th style="padding:2px;border-right: 2px #fff solid;">Line</th>'; $sHtml .= '<th style="padding:2px;border-right: 2px #fff solid;">Status</th>'; $sHtml .= '<th style="padding:2px;border-right: 2px #fff solid;">Object</th>'; foreach ($aFieldsMapping as $iNumber => $sAttCode) { if (!empty($sAttCode) && $sAttCode != ':none:' && $sAttCode != 'finalclass') { $sHtml .= "<th style=\"padding:2px;border-right: 2px #fff solid;\">" . MetaModel::GetLabel($sClassName, $sAttCode) . "</th>"; } } $sHtml .= '<th>Message</th>'; $sHtml .= '</tr>'; $iErrors = 0; $iCreated = 0; $iModified = 0; $iUnchanged = 0; foreach ($aRes as $iLine => $aResRow) { $oStatus = $aResRow['__STATUS__']; $sUrl = ''; $sMessage = ''; $sCSSRowClass = ''; $sCSSMessageClass = 'cell_ok'; switch (get_class($oStatus)) { case 'RowStatus_NoChange': $iUnchanged++; $sFinalClass = $aResRow['finalclass']; $oObj = MetaModel::GetObject($sFinalClass, $aResRow['id']->GetPureValue()); $sUrl = $oObj->GetHyperlink(); $sStatus = '<img src="../images/unchanged.png" title="' . Dict::S('UI:CSVReport-Icon-Unchanged') . '">'; $sCSSRowClass = 'row_unchanged'; break; case 'RowStatus_Modify': $iModified++; $sFinalClass = $aResRow['finalclass']; $oObj = MetaModel::GetObject($sFinalClass, $aResRow['id']->GetPureValue()); $sUrl = $oObj->GetHyperlink(); $sStatus = '<img src="../images/modified.png" title="' . Dict::S('UI:CSVReport-Icon-Modified') . '">'; $sCSSRowClass = 'row_modified'; break; case 'RowStatus_Disappeared': $iModified++; $sFinalClass = $aResRow['finalclass']; $oObj = MetaModel::GetObject($sFinalClass, $aResRow['id']->GetPureValue()); $sUrl = $oObj->GetHyperlink(); $sStatus = '<img src="../images/delete.png" title="' . Dict::S('UI:CSVReport-Icon-Missing') . '">'; $sCSSRowClass = 'row_modified'; if ($bSimulate) { $sMessage = Dict::S('UI:CSVReport-Object-MissingToUpdate'); } else { $sMessage = Dict::S('UI:CSVReport-Object-MissingUpdated'); } break; case 'RowStatus_NewObj': $iCreated++; $sFinalClass = $aResRow['finalclass']; $sStatus = '<img src="../images/added.png" title="' . Dict::S('UI:CSVReport-Icon-Created') . '">'; $sCSSRowClass = 'row_added'; if ($bSimulate) { $sMessage = Dict::S('UI:CSVReport-Object-ToCreate'); } else { $sFinalClass = $aResRow['finalclass']; $oObj = MetaModel::GetObject($sFinalClass, $aResRow['id']->GetPureValue()); $sUrl = $oObj->GetHyperlink(); $sMessage = Dict::S('UI:CSVReport-Object-Created'); } break; case 'RowStatus_Issue': $iErrors++; $sMessage .= $oPage->GetP($oStatus->GetDescription()); $sStatus = '<img src="../images/error.png" title="' . Dict::S('UI:CSVReport-Icon-Error') . '">'; //translate $sCSSMessageClass = 'cell_error'; $sCSSRowClass = 'row_error'; if (array_key_exists($iLine, $aData)) { $aRow = $aData[$iLine]; $aResult[] = $sTextQualifier . implode($sTextQualifier . $sSeparator . $sTextQualifier, $aRow) . $sTextQualifier; // Remove the first line and store it in case of error } break; } $sHtml .= '<tr class="' . $sCSSRowClass . '">'; $sHtml .= "<td style=\"background-color:#f1f1f1;border-right:2px #fff solid;\">" . sprintf("%0{$sMaxLen}d", 1 + $iLine + $iRealSkippedLines) . "</td>"; $sHtml .= "<td style=\"text-align:center;background-color:#f1f1f1;border-right:2px #fff solid;\">{$sStatus}</td>"; $sHtml .= "<td style=\"text-align:center;background-color:#f1f1f1;\">{$sUrl}</td>"; foreach ($aFieldsMapping as $iNumber => $sAttCode) { if (!empty($sAttCode) && $sAttCode != ':none:' && $sAttCode != 'finalclass') { $oCellStatus = $aResRow[$iNumber - 1]; $sCellMessage = ''; if (isset($aExternalKeysByColumn[$iNumber - 1])) { $sExtKeyName = $aExternalKeysByColumn[$iNumber - 1]; $oExtKeyCellStatus = $aResRow[$sExtKeyName]; switch (get_class($oExtKeyCellStatus)) { case 'CellStatus_Issue': case 'CellStatus_SearchIssue': case 'CellStatus_NullIssue': $sCellMessage .= $oPage->GetP($oExtKeyCellStatus->GetDescription()); break; case 'CellStatus_Ambiguous': $sCellMessage .= $oPage->GetP($oExtKeyCellStatus->GetDescription()); break; default: // Do nothing } } $sHtmlValue = $oCellStatus->GetDisplayableValue(); switch (get_class($oCellStatus)) { case 'CellStatus_Issue': $sCellMessage .= $oPage->GetP($oCellStatus->GetDescription()); $sHtml .= '<td class="cell_error" style="border-right:1px #eee solid;">' . Dict::Format('UI:CSVReport-Object-Error', $sHtmlValue) . $sCellMessage . '</td>'; break; case 'CellStatus_SearchIssue': $sCellMessage .= $oPage->GetP($oCellStatus->GetDescription()); $sHtml .= '<td class="cell_error">ERROR: ' . $sHtmlValue . $sCellMessage . '</td>'; break; case 'CellStatus_Ambiguous': $sCellMessage .= $oPage->GetP($oCellStatus->GetDescription()); $sHtml .= '<td class="cell_error" style="border-right:1px #eee solid;">' . Dict::Format('UI:CSVReport-Object-Ambiguous', $sHtmlValue) . $sCellMessage . '</td>'; break; case 'CellStatus_Modify': $sHtml .= '<td class="cell_modified" style="border-right:1px #eee solid;"><b>' . $sHtmlValue . '</b></td>'; break; default: $sHtml .= '<td class="cell_ok" style="border-right:1px #eee solid;">' . $sHtmlValue . $sCellMessage . '</td>'; } } } $sHtml .= "<td class=\"{$sCSSMessageClass}\" style=\"background-color:#f1f1f1;\">{$sMessage}</td>"; $sHtml .= '</tr>'; } $iUnchanged = count($aRes) - $iErrors - $iModified - $iCreated; $sHtml .= '</table>'; $oPage->add('<div class="wizContainer" style="width:auto;display:inline-block;">'); $oPage->add('<form enctype="multipart/form-data" id="wizForm" method="post">'); $oPage->add('<input type="hidden" name="step" value="' . ($iCurrentStep + 1) . '"/>'); $oPage->add('<input type="hidden" name="separator" value="' . htmlentities($sSeparator, ENT_QUOTES, 'UTF-8') . '"/>'); $oPage->add('<input type="hidden" name="text_qualifier" value="' . htmlentities($sTextQualifier, ENT_QUOTES, 'UTF-8') . '"/>'); $oPage->add('<input type="hidden" name="header_line" value="' . $bHeaderLine . '"/>'); $oPage->add('<input type="hidden" name="nb_skipped_lines" value="' . utils::ReadParam('nb_skipped_lines', '0') . '"/>'); $oPage->add('<input type="hidden" name="box_skiplines" value="' . utils::ReadParam('box_skiplines', '0') . '"/>'); $oPage->add('<input type="hidden" name="csvdata" value="' . htmlentities($sCSVData, ENT_QUOTES, 'UTF-8') . '"/>'); $oPage->add('<input type="hidden" name="csvdata_truncated" value="' . htmlentities($sCSVDataTruncated, ENT_QUOTES, 'UTF-8') . '"/>'); $oPage->add('<input type="hidden" name="class_name" value="' . $sClassName . '"/>'); $oPage->add('<input type="hidden" name="advanced" value="' . $bAdvanced . '"/>'); $oPage->add('<input type="hidden" name="encoding" value="' . $sEncoding . '"/>'); $oPage->add('<input type="hidden" name="synchro_scope" value="' . $sSynchroScope . '"/>'); if (!empty($sSynchroScope)) { foreach ($aSynchroUpdate as $sKey => $value) { $oPage->add('<input type="hidden" name="synchro_update[' . $sKey . ']" value="' . $value . '"/>'); } } foreach ($aFieldsMapping as $iNumber => $sAttCode) { $oPage->add('<input type="hidden" name="field[' . $iNumber . ']" value="' . $sAttCode . '"/>'); } foreach ($aSearchFields as $index => $sDummy) { $oPage->add('<input type="hidden" name="search_field[' . $index . ']" value="1"/>'); } $aDisplayFilters = array(); if ($bSimulate) { $aDisplayFilters['unchanged'] = Dict::S('UI:CSVImport:ObjectsWillStayUnchanged'); $aDisplayFilters['modified'] = Dict::S('UI:CSVImport:ObjectsWillBeModified'); $aDisplayFilters['added'] = Dict::S('UI:CSVImport:ObjectsWillBeAdded'); $aDisplayFilters['errors'] = Dict::S('UI:CSVImport:ObjectsWillHaveErrors'); } else { $aDisplayFilters['unchanged'] = Dict::S('UI:CSVImport:ObjectsRemainedUnchanged'); $aDisplayFilters['modified'] = Dict::S('UI:CSVImport:ObjectsWereModified'); $aDisplayFilters['added'] = Dict::S('UI:CSVImport:ObjectsWereAdded'); $aDisplayFilters['errors'] = Dict::S('UI:CSVImport:ObjectsHadErrors'); } $oPage->add('<p><input type="checkbox" checked id="show_unchanged" onClick="ToggleRows(\'row_unchanged\')"/> <img src="../images/unchanged.png"> ' . sprintf($aDisplayFilters['unchanged'], $iUnchanged) . '  '); $oPage->add('<input type="checkbox" checked id="show_modified" onClick="ToggleRows(\'row_modified\')"/> <img src="../images/modified.png"> ' . sprintf($aDisplayFilters['modified'], $iModified) . '  '); $oPage->add('<input type="checkbox" checked id="show_created" onClick="ToggleRows(\'row_added\')"/> <img src="../images/added.png"> ' . sprintf($aDisplayFilters['added'], $iCreated) . '  '); $oPage->add('<input type="checkbox" checked id="show_errors" onClick="ToggleRows(\'row_error\')"/> <img src="../images/error.png"> ' . sprintf($aDisplayFilters['errors'], $iErrors) . '</p>'); $oPage->add('<div class="white" style="display:inline-block">'); $oPage->add($sHtml); $oPage->add('</div> <!-- end of preview -->'); $oPage->add('<p>'); if ($bSimulate) { $oPage->add('<input type="button" value="' . Dict::S('UI:Button:Restart') . '" onClick="CSVRestart()"/> '); } $oPage->add('<input type="button" value="' . Dict::S('UI:Button:Back') . '" onClick="CSVGoBack()"/> '); $bShouldConfirm = false; if ($bSimulate) { // if there are *too many* changes, we should ask the user for a confirmation if (count($aRes) >= MetaModel::GetConfig()->Get('csv_import_min_object_confirmation')) { $fErrorsPercentage = 100.0 * $iErrors / count($aRes); if ($fErrorsPercentage >= MetaModel::GetConfig()->Get('csv_import_errors_percentage')) { $sMessage = Dict::Format('UI:CSVReport-Stats-Errors', $fErrorsPercentage); $bShouldConfirm = true; } $fCreatedPercentage = 100.0 * $iCreated / count($aRes); if ($fCreatedPercentage >= MetaModel::GetConfig()->Get('csv_import_creations_percentage')) { $sMessage = Dict::Format('UI:CSVReport-Stats-Created', $fCreatedPercentage); $bShouldConfirm = true; } $fModifiedPercentage = 100.0 * $iModified / count($aRes); if ($fModifiedPercentage >= MetaModel::GetConfig()->Get('csv_import_modifications_percentage')) { $sMessage = Dict::Format('UI:CSVReport-Stats-Modified', $fModifiedPercentage); $bShouldConfirm = true; } } $iCount = count($aRes); //$oPage->add('<input type="submit" value="'.Dict::S('UI:Button:DoImport').'" onClick="$(\'#wizForm\').block();"/></p>'); $sConfirm = $bShouldConfirm ? 'true' : 'false'; $oPage->add('<input type="button" value="' . Dict::S('UI:Button:DoImport') . "\" onClick=\"return DoSubmit({$sConfirm});\"/></p>"); } else { $oPage->add('<input type="submit" value="' . Dict::S('UI:Button:Done') . '"/></p>'); } $oPage->add('</form>'); $oPage->add('</div> <!-- end of wizForm -->'); if ($bShouldConfirm) { $sYesButton = Dict::S('UI:Button:Ok'); $sNoButton = Dict::S('UI:Button:Cancel'); $oPage->add('<div id="dlg_confirmation" title="' . htmlentities(Dict::S('UI:CSVImportConfirmTitle'), ENT_QUOTES, 'UTF-8') . '">'); $oPage->add('<p style="text-align:center"><b>' . $sMessage . '</b></p>'); $oPage->add('<p style="text-align:center">' . htmlentities(Dict::S('UI:CSVImportConfirmMessage'), ENT_QUOTES, 'UTF-8') . '</p>'); $oPage->add('<div id="confirmation_chart"></div>'); $oPage->add('</div> <!-- end of dlg_confirmation -->'); $oPage->add_ready_script(<<<EOF \t\$('#dlg_confirmation').dialog( \t\t{ \t\t\theight: 'auto', \t\t\twidth: 500, \t\t\tmodal:true, \t\t\tautoOpen: false, \t\t\tbuttons: \t\t\t{ \t\t\t\t'{$sYesButton}': RunImport, \t\t\t\t'{$sNoButton}': CancelImport \t\t\t} \t\t}); \t\tswfobject.embedSWF(\t"../images/open-flash-chart.swf", \t\t\t\t\t\t\t"confirmation_chart", \t\t\t\t\t\t\t"100%", "300","9.0.0", \t\t\t\t\t\t\t"expressInstall.swf", \t\t\t\t\t\t\t{}, \t\t\t\t\t\t\t{'wmode': 'transparent'} \t\t\t\t\t\t); EOF ); } $sErrors = addslashes(Dict::Format('UI:CSVImportError_items', $iErrors)); $sCreated = addslashes(Dict::Format('UI:CSVImportCreated_items', $iCreated)); $sModified = addslashes(Dict::Format('UI:CSVImportModified_items', $iModified)); $sUnchanged = addslashes(Dict::Format('UI:CSVImportUnchanged_items', $iUnchanged)); $oPage->add_script(<<<EOF function CSVGoBack() { \t\$('input[name=step]').val({$iCurrentStep}-1); \t\$('#wizForm').submit(); \t } function CSVRestart() { \t\$('input[name=step]').val(1); \t\$('#wizForm').submit(); \t } function ToggleRows(sCSSClass) { \t\$('.'+sCSSClass).toggle(); } function DoSubmit(bConfirm) { \tif (bConfirm) //Ask for a confirmation \t{ \t\t\$('#dlg_confirmation').dialog('open'); \t} \telse \t{ \t\t// Submit the form \t\t\$('#wizForm').block(); \t\t\$('#wizForm').submit(); \t} \treturn false; } function CancelImport() { \t\$('#dlg_confirmation').dialog('close'); } function RunImport() { \t\$('#dlg_confirmation').dialog('close'); \t// Submit the form \t\$('#wizForm').block(); \t\$('#wizForm').submit(); } function open_flash_chart_data() { \tvar iErrors = {$iErrors}; \tvar iModified = {$iModified}; \tvar iCreated = {$iCreated}; \tvar iUnchanged = {$iUnchanged}; \tvar fAlpha = 0.9; \t \tvar oResult = { \t\t"elements": [ \t\t\t{ \t\t\t\t"type": "pie", \t\t\t\t"tip": "#label# (#percent#)", \t\t\t\t"gradient-fill": true, \t\t\t\t"font-size": 14, \t\t\t\t"colours":[], \t\t\t\t"values": [], \t\t\t\t"animate":[ \t\t\t { \t\t\t "type": "fade" \t\t\t } \t\t ] \t\t\t} \t\t], \t\t"x_axis": null, \t\t"font-size": 14, \t\t"bg_colour": "#EEEEEE" \t}; \tif (iErrors > 0) \t{ \t\tvar oErrors = \t\t{ \t\t\t"value": iErrors, \t\t\t"label": "{$sErrors}", \t\t\t"alpha": fAlpha, \t\t\t"label-colour": "#CC3333", \t\t}; \t\toResult.elements[0].values.push(oErrors); \t\toResult.elements[0].colours.push('#FF6666'); \t} \tif (iModified > 0) \t{ \t\tvar oModified = \t\t{ \t\t\t"value": iModified, \t\t\t"label": "{$sModified}", \t\t\t"alpha": fAlpha, \t\t\t"label-colour": "#3333CC", \t\t}; \t\toResult.elements[0].values.push(oModified); \t\toResult.elements[0].colours.push('#6666FF'); \t} \tif (iCreated > 0) \t{ \t\tvar oCreated = \t\t{ \t\t\t"value": iCreated, \t\t\t"label": "{$sCreated}", \t\t\t"alpha": fAlpha, \t\t\t"label-colour": "#33CC33", \t\t\t \t\t}; \t\toResult.elements[0].values.push(oCreated); \t\toResult.elements[0].colours.push('#66FF66'); \t} \tif (iUnchanged > 0) \t{ \t\tvar oUnchanged = \t\t{ \t\t\t"value": iUnchanged, \t\t\t"label": "{$sUnchanged}", \t\t\t"alpha": fAlpha, \t\t\t"label-colour": "#333333", \t\t\t \t\t}; \t\toResult.elements[0].values.push(oUnchanged); \t\toResult.elements[0].colours.push('#666666'); \t} \treturn JSON.stringify(oResult); } EOF ); if ($iErrors > 0) { return $aResult; } else { return null; } }