public function GetNextChunk(&$aStatus) { $sRetCode = 'run'; $iPercentage = 0; $oSet = new DBObjectSet($this->oSearch); $oSet->SetLimit($this->iChunkSize, $this->aStatusInfo['position']); $this->OptimizeColumnLoad($oSet); $iCount = 0; $sData = ''; $iPreviousTimeLimit = ini_get('max_execution_time'); $iLoopTimeLimit = MetaModel::GetConfig()->Get('max_execution_time_per_loop'); while ($aRow = $oSet->FetchAssoc()) { set_time_limit($iLoopTimeLimit); $aData = array(); foreach ($this->aStatusInfo['fields'] as $iCol => $aFieldSpec) { $sAlias = $aFieldSpec['sAlias']; $sAttCode = $aFieldSpec['sAttCode']; $sField = ''; $oObj = $aRow[$sAlias]; if ($oObj != null) { switch ($sAttCode) { case 'id': $sField = $oObj->GetKey(); break; default: $sField = $oObj->GetAsCSV($sAttCode, $this->aStatusInfo['separator'], $this->aStatusInfo['text_qualifier'], $this->bLocalizeOutput); } } if ($this->aStatusInfo['charset'] != 'UTF-8') { // Note: due to bugs in the glibc library it's safer to call iconv on the smallest possible string // and thus to convert field by field and not the whole row or file at once (see ticket #991) $aData[] = iconv('UTF-8', $this->aStatusInfo['charset'] . '//IGNORE//TRANSLIT', $sField); } else { $aData[] = $sField; } } $sData .= implode($this->aStatusInfo['separator'], $aData) . "\n"; $iCount++; } set_time_limit($iPreviousTimeLimit); $this->aStatusInfo['position'] += $this->iChunkSize; if ($this->aStatusInfo['total'] == 0) { $iPercentage = 100; } else { $iPercentage = floor(min(100.0, 100.0 * $this->aStatusInfo['position'] / $this->aStatusInfo['total'])); } if ($iCount < $this->iChunkSize) { $sRetCode = 'done'; } $aStatus = array('code' => $sRetCode, 'message' => Dict::S('Core:BulkExport:RetrievingData'), 'percentage' => $iPercentage); return $sData; }
public function GetNextChunk(&$aStatus) { $sRetCode = 'run'; $iPercentage = 0; $oSet = new DBObjectSet($this->oSearch); $aSelectedClasses = $this->oSearch->GetSelectedClasses(); $aAliases = array_keys($aSelectedClasses); $oSet->SetLimit($this->iChunkSize, $this->aStatusInfo['position']); $aAliasByField = array(); $aColumnsToLoad = array(); // Prepare the list of aliases / columns to load foreach ($this->aStatusInfo['fields'] as $sExtendedAttCode) { if (preg_match('/^([^\\.]+)\\.(.+)$/', $sExtendedAttCode, $aMatches)) { $sAlias = $aMatches[1]; $sAttCode = $aMatches[2]; } else { $sAlias = reset($aAliases); $sAttCode = $sExtendedAttCode; } if (!in_array($sAlias, $aAliases)) { throw new Exception("Invalid alias '{$sAlias}' for the column '{$sExtendedAttCode}'. Availables aliases: '" . implode("', '", $aAliases) . "'"); } if (!array_key_exists($sAlias, $aColumnsToLoad)) { $aColumnsToLoad[$sAlias] = array(); } if ($sAttCode != 'id') { // id is not a real attribute code and, moreover, is always loaded $aColumnsToLoad[$sAlias][] = $sAttCode; } $aAliasByField[$sExtendedAttCode] = array('alias' => $sAlias, 'attcode' => $sAttCode); } $iCount = 0; $sData = ''; $oSet->OptimizeColumnLoad($aColumnsToLoad); $iPreviousTimeLimit = ini_get('max_execution_time'); $iLoopTimeLimit = MetaModel::GetConfig()->Get('max_execution_time_per_loop'); while ($aRow = $oSet->FetchAssoc()) { set_time_limit($iLoopTimeLimit); $sFirstAlias = reset($aAliases); $sHilightClass = $aRow[$sFirstAlias]->GetHilightClass(); if ($sHilightClass != '') { $sData .= "<tr class=\"{$sHilightClass}\">"; } else { $sData .= "<tr>"; } foreach ($aAliasByField as $aAttCode) { $sField = ''; switch ($aAttCode['attcode']) { case 'id': $sField = $aRow[$aAttCode['alias']]->GetHyperlink(); break; default: $sField = $aRow[$aAttCode['alias']]->GetAsHtml($aAttCode['attcode']); } $sValue = $sField === '' ? ' ' : $sField; $sData .= "<td>{$sValue}</td>"; } $sData .= "</tr>"; $iCount++; } set_time_limit($iPreviousTimeLimit); $this->aStatusInfo['position'] += $this->iChunkSize; if ($this->aStatusInfo['total'] == 0) { $iPercentage = 100; } else { $iPercentage = floor(min(100.0, 100.0 * $this->aStatusInfo['position'] / $this->aStatusInfo['total'])); } if ($iCount < $this->iChunkSize) { $sRetCode = 'done'; } $aStatus = array('code' => $sRetCode, 'message' => Dict::S('Core:BulkExport:RetrievingData'), 'percentage' => $iPercentage); return $sData; }
/** * Do the synchronization job #3: Delete replica depending on the obsolescence scheme * @param integer $iMaxReplica Limit the number of replicas to process * @param integer $iCurrPos Current position where to resume the processing * @return true if the process must be continued */ protected function DoJob3($iMaxReplica = null, $iCurrPos = -1) { $sDeletePolicy = $this->m_oDataSource->Get('delete_policy'); if ($sDeletePolicy != 'update_then_delete') { // Job complete! $this->m_oStatLog->Set('status_curr_job', 0); $this->m_oStatLog->Set('status_curr_pos', -1); return false; } $bFirstPass = $iCurrPos == -1; // Get all the replicas that are to be deleted // $oDeletionDate = $this->m_oLastFullLoadStartDate; $iDeleteRetention = $this->m_oDataSource->Get('delete_policy_retention'); // Duration in seconds if ($iDeleteRetention > 0) { $sInterval = "-{$iDeleteRetention} seconds"; $oDeletionDate->Modify($sInterval); } $sDeletionDate = $oDeletionDate->Format('Y-m-d H:i:s'); if ($bFirstPass) { $this->m_oStatLog->AddTrace("Deletion date: {$sDeletionDate}"); } $sSelectToDelete = "SELECT SynchroReplica WHERE id > :curr_pos AND sync_source_id = :source_id AND status IN ('obsolete') AND status_last_seen < :last_import"; $oSetScope = new DBObjectSet(DBObjectSearch::FromOQL($sSelectToDelete), array(), array('source_id' => $this->m_oDataSource->GetKey(), 'last_import' => $sDeletionDate, 'curr_pos' => $iCurrPos)); $iCountScope = $oSetScope->Count(); if ($iMaxReplica) { // Consider a given subset, starting from replica iCurrPos, limited to the count of iMaxReplica // The replica have to be ordered by id $oSetToProcess = new DBObjectSet(DBObjectSearch::FromOQL($sSelectToDelete), array('id' => true), array('source_id' => $this->m_oDataSource->GetKey(), 'last_import' => $sDeletionDate, 'curr_pos' => $iCurrPos)); $oSetToProcess->SetLimit($iMaxReplica); } else { $oSetToProcess = $oSetScope; } $iLastReplicaProcessed = -1; while ($oReplica = $oSetToProcess->Fetch()) { $iLastReplicaProcessed = $oReplica->GetKey(); $this->m_oStatLog->AddTrace("Destination object to be DELETED", $oReplica); $oReplica->DeleteDestObject($this->m_oChange, $this->m_oStatLog); } if ($iMaxReplica) { if ($iMaxReplica < $iCountScope) { // Continue with this job! $this->m_oStatLog->Set('status_curr_pos', $iLastReplicaProcessed); return true; } } // Job complete! $this->m_oStatLog->Set('status_curr_job', 0); $this->m_oStatLog->Set('status_curr_pos', -1); return false; }
protected function GetInteractiveFieldsWidget(WebPage $oP, $sWidgetId) { $oSet = new DBObjectSet($this->oSearch); $aSelectedClasses = $this->oSearch->GetSelectedClasses(); $aAuthorizedClasses = array(); foreach ($aSelectedClasses as $sAlias => $sClassName) { if (UserRights::IsActionAllowed($sClassName, UR_ACTION_BULK_READ, $oSet) && (UR_ALLOWED_YES || UR_ALLOWED_DEPENDS)) { $aAuthorizedClasses[$sAlias] = $sClassName; } } $aAllFieldsByAlias = array(); $aAllAttCodes = array(); foreach ($aAuthorizedClasses as $sAlias => $sClass) { $aAllFields = array(); if (count($aAuthorizedClasses) > 1) { $sShortAlias = $sAlias . '.'; } else { $sShortAlias = ''; } if ($this->IsExportableField($sClass, 'id')) { $sFriendlyNameAttCode = MetaModel::GetFriendlyNameAttributeCode($sClass); if (is_null($sFriendlyNameAttCode)) { // The friendly name is made of several attribute $aSubAttr = array(array('attcodeex' => 'id', 'code' => $sShortAlias . 'id', 'unique_label' => $sShortAlias . Dict::S('UI:CSVImport:idField'), 'label' => $sShortAlias . 'id'), array('attcodeex' => 'friendlyname', 'code' => $sShortAlias . 'friendlyname', 'unique_label' => $sShortAlias . Dict::S('Core:FriendlyName-Label'), 'label' => $sShortAlias . Dict::S('Core:FriendlyName-Label'))); } else { // The friendly name has no added value $aSubAttr = array(); } $aAllFields[] = array('attcodeex' => 'id', 'code' => $sShortAlias . 'id', 'unique_label' => $sShortAlias . Dict::S('UI:CSVImport:idField'), 'label' => Dict::S('UI:CSVImport:idField'), 'subattr' => $aSubAttr); } foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) { if ($this->IsSubAttribute($sClass, $sAttCode, $oAttDef)) { continue; } if ($this->IsExportableField($sClass, $sAttCode, $oAttDef)) { $sShortLabel = $oAttDef->GetLabel(); $sLabel = $sShortAlias . $oAttDef->GetLabel(); $aSubAttr = $this->GetSubAttributes($sClass, $sAttCode, $oAttDef); $aValidSubAttr = array(); foreach ($aSubAttr as $aSubAttDef) { $aValidSubAttr[] = array('attcodeex' => $aSubAttDef['code'], 'code' => $sShortAlias . $aSubAttDef['code'], 'label' => $aSubAttDef['label'], 'unique_label' => $sShortAlias . $aSubAttDef['unique_label']); } $aAllFields[] = array('attcodeex' => $sAttCode, 'code' => $sShortAlias . $sAttCode, 'label' => $sShortLabel, 'unique_label' => $sLabel, 'subattr' => $aValidSubAttr); } } usort($aAllFields, array(get_class($this), 'SortOnLabel')); if (count($aAuthorizedClasses) > 1) { $sKey = MetaModel::GetName($sClass) . ' (' . $sAlias . ')'; } else { $sKey = MetaModel::GetName($sClass); } $aAllFieldsByAlias[$sKey] = $aAllFields; foreach ($aAllFields as $aFieldSpec) { $sAttCode = $aFieldSpec['attcodeex']; if (count($aFieldSpec['subattr']) > 0) { foreach ($aFieldSpec['subattr'] as $aSubFieldSpec) { $aAllAttCodes[$sAlias][] = $aSubFieldSpec['attcodeex']; } } else { $aAllAttCodes[$sAlias][] = $sAttCode; } } } $oP->add('<div id="' . $sWidgetId . '"></div>'); $JSAllFields = json_encode($aAllFieldsByAlias); // First, fetch only the ids - the rest will be fetched by an object reload $oSet = new DBObjectSet($this->oSearch); $iCount = $oSet->Count(); foreach ($this->oSearch->GetSelectedClasses() as $sAlias => $sClass) { $aColumns[$sAlias] = array(); } $oSet->OptimizeColumnLoad($aColumns); $iPreviewLimit = 3; $oSet->SetLimit($iPreviewLimit); $aSampleData = array(); while ($aRow = $oSet->FetchAssoc()) { $aSampleRow = array(); foreach ($aAuthorizedClasses as $sAlias => $sClass) { if (count($aAuthorizedClasses) > 1) { $sShortAlias = $sAlias . '.'; } else { $sShortAlias = ''; } foreach ($aAllAttCodes[$sAlias] as $sAttCodeEx) { $oObj = $aRow[$sAlias]; $aSampleRow[$sShortAlias . $sAttCodeEx] = $oObj ? $this->GetSampleData($oObj, $sAttCodeEx) : ''; } } $aSampleData[] = $aSampleRow; } $sJSSampleData = json_encode($aSampleData); $aLabels = array('preview_header' => Dict::S('Core:BulkExport:DragAndDropHelp'), 'empty_preview' => Dict::S('Core:BulkExport:EmptyPreview'), 'columns_order' => Dict::S('Core:BulkExport:ColumnsOrder'), 'columns_selection' => Dict::S('Core:BulkExport:AvailableColumnsFrom_Class'), 'check_all' => Dict::S('Core:BulkExport:CheckAll'), 'uncheck_all' => Dict::S('Core:BulkExport:UncheckAll'), 'no_field_selected' => Dict::S('Core:BulkExport:NoFieldSelected')); $sJSLabels = json_encode($aLabels); $oP->add_ready_script(<<<EOF \$('#{$sWidgetId}').tabularfieldsselector({fields: {$JSAllFields}, value_holder: '#tabular_fields', advanced_holder: '#tabular_advanced', sample_data: {$sJSSampleData}, total_count: {$iCount}, preview_limit: {$iPreviewLimit}, labels: {$sJSLabels} }); EOF ); }
protected function GetInteractiveFieldsWidget(WebPage $oP, $sWidgetId) { $oSet = new DBObjectSet($this->oSearch); $aSelectedClasses = $this->oSearch->GetSelectedClasses(); $aAuthorizedClasses = array(); foreach ($aSelectedClasses as $sAlias => $sClassName) { if (UserRights::IsActionAllowed($sClassName, UR_ACTION_BULK_READ, $oSet) && (UR_ALLOWED_YES || UR_ALLOWED_DEPENDS)) { $aAuthorizedClasses[$sAlias] = $sClassName; } } $aAllFieldsByAlias = array(); foreach ($aAuthorizedClasses as $sAlias => $sClass) { $aAllFields = array(); if (count($aAuthorizedClasses) > 1) { $sShortAlias = $sAlias . '.'; } else { $sShortAlias = ''; } if ($this->IsValidField($sClass, 'id')) { $aAllFields[] = array('code' => $sShortAlias . 'id', 'unique_label' => $sShortAlias . Dict::S('Core:BulkExport:Identifier'), 'label' => $sShortAlias . 'id', 'subattr' => array(array('code' => $sShortAlias . 'id', 'unique_label' => $sShortAlias . Dict::S('Core:BulkExport:Identifier'), 'label' => $sShortAlias . 'id'), array('code' => $sShortAlias . 'friendlyname', 'unique_label' => $sShortAlias . Dict::S('Core:BulkExport:Friendlyname'), 'label' => $sShortAlias . Dict::S('Core:BulkExport:Friendlyname')))); } foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) { if ($this->IsSubAttribute($sClass, $sAttCode, $oAttDef)) { continue; } if ($this->IsValidField($sClass, $sAttCode, $oAttDef)) { $sShortLabel = $oAttDef->GetLabel(); $sLabel = $sShortAlias . $oAttDef->GetLabel(); $aSubAttr = $this->GetSubAttributes($sClass, $sAttCode, $oAttDef); $aValidSubAttr = array(); foreach ($aSubAttr as $aSubAttDef) { if ($this->IsValidField($sClass, $aSubAttDef['code'], $aSubAttDef['attdef'])) { $aValidSubAttr[] = array('code' => $sShortAlias . $aSubAttDef['code'], 'label' => $aSubAttDef['label'], 'unique_label' => $aSubAttDef['unique_label']); } } $aAllFields[] = array('code' => $sShortAlias . $sAttCode, 'label' => $sShortLabel, 'unique_label' => $sLabel, 'subattr' => $aValidSubAttr); } } usort($aAllFields, array(get_class($this), 'SortOnLabel')); if (count($aAuthorizedClasses) > 1) { $sKey = MetaModel::GetName($sClass) . ' (' . $sAlias . ')'; } else { $sKey = MetaModel::GetName($sClass); } $aAllFieldsByAlias[$sKey] = $aAllFields; } $oP->add('<div id="' . $sWidgetId . '"></div>'); $JSAllFields = json_encode($aAllFieldsByAlias); $oSet = new DBObjectSet($this->oSearch); $iCount = $oSet->Count(); $iPreviewLimit = 3; $oSet->SetLimit($iPreviewLimit); $aSampleData = array(); while ($aRow = $oSet->FetchAssoc()) { $aSampleRow = array(); foreach ($aAuthorizedClasses as $sAlias => $sClass) { if (count($aAuthorizedClasses) > 1) { $sShortAlias = $sAlias . '.'; } else { $sShortAlias = ''; } if ($this->IsValidField($sClass, 'id')) { $aSampleRow[$sShortAlias . 'id'] = $this->GetSampleKey($aRow[$sAlias]); } foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) { if ($this->IsValidField($sClass, $sAttCode, $oAttDef)) { $aSampleRow[$sShortAlias . $sAttCode] = $this->GetSampleData($aRow[$sAlias], $sAttCode); } } } $aSampleData[] = $aSampleRow; } $sJSSampleData = json_encode($aSampleData); $aLabels = array('preview_header' => Dict::S('Core:BulkExport:DragAndDropHelp'), 'empty_preview' => Dict::S('Core:BulkExport:EmptyPreview'), 'columns_order' => Dict::S('Core:BulkExport:ColumnsOrder'), 'columns_selection' => Dict::S('Core:BulkExport:AvailableColumnsFrom_Class'), 'check_all' => Dict::S('Core:BulkExport:CheckAll'), 'uncheck_all' => Dict::S('Core:BulkExport:UncheckAll'), 'no_field_selected' => Dict::S('Core:BulkExport:NoFieldSelected')); $sJSLabels = json_encode($aLabels); $oP->add_ready_script(<<<EOF \$('#{$sWidgetId}').tabularfieldsselector({fields: {$JSAllFields}, value_holder: '#tabular_fields', advanced_holder: '#tabular_advanced', sample_data: {$sJSSampleData}, total_count: {$iCount}, preview_limit: {$iPreviewLimit}, labels: {$sJSLabels} }); EOF ); }
public function GetNextChunk(&$aStatus) { $sRetCode = 'run'; $iPercentage = 0; $oSet = new DBObjectSet($this->oSearch); $oSet->SetLimit($this->iChunkSize, $this->aStatusInfo['position']); $this->OptimizeColumnLoad($oSet); $iCount = 0; $sData = ''; $iPreviousTimeLimit = ini_get('max_execution_time'); $iLoopTimeLimit = MetaModel::GetConfig()->Get('max_execution_time_per_loop'); while ($aRow = $oSet->FetchAssoc()) { set_time_limit($iLoopTimeLimit); $sData .= "<tr>"; foreach ($this->aStatusInfo['fields'] as $iCol => $aFieldSpec) { $sAlias = $aFieldSpec['sAlias']; $sAttCode = $aFieldSpec['sAttCode']; $sField = ''; $oObj = $aRow[$sAlias]; if ($oObj == null) { $sData .= "<td x:str></td>"; continue; } switch ($sAttCode) { case 'id': $sField = $oObj->GetKey(); $sData .= "<td>{$sField}</td>"; break; default: $oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode); $oFinalAttDef = $oAttDef->GetFinalAttDef(); if (get_class($oFinalAttDef) == 'AttributeDateTime') { $iDate = AttributeDateTime::GetAsUnixSeconds($oObj->Get($sAttCode)); $sData .= '<td>' . date('Y-m-d', $iDate) . '</td>'; // Add the first column directly $sField = date('H:i:s', $iDate); // Will add the second column below $sData .= "<td>{$sField}</td>"; } else { if ($oAttDef instanceof AttributeCaseLog) { $rawValue = $oObj->Get($sAttCode); $sField = str_replace("\n", "<br/>", htmlentities($rawValue->__toString(), ENT_QUOTES, 'UTF-8')); // Trick for Excel: treat the content as text even if it begins with an equal sign $sData .= "<td x:str>{$sField}</td>"; } else { if ($oAttDef instanceof AttributeString) { $sField = $oObj->GetAsHTML($sAttCode, $this->bLocalizeOutput); $sData .= "<td x:str>{$sField}</td>"; } else { $rawValue = $oObj->Get($sAttCode); if ($this->bLocalizeOutput) { $sField = htmlentities($oFinalAttDef->GetEditValue($rawValue), ENT_QUOTES, 'UTF-8'); } else { $sField = htmlentities($rawValue, ENT_QUOTES, 'UTF-8'); } $sData .= "<td>{$sField}</td>"; } } } } } $sData .= "</tr>"; $iCount++; } set_time_limit($iPreviousTimeLimit); $this->aStatusInfo['position'] += $this->iChunkSize; if ($this->aStatusInfo['total'] == 0) { $iPercentage = 100; } else { $iPercentage = floor(min(100.0, 100.0 * $this->aStatusInfo['position'] / $this->aStatusInfo['total'])); } if ($iCount < $this->iChunkSize) { $sRetCode = 'done'; } $aStatus = array('code' => $sRetCode, 'message' => Dict::S('Core:BulkExport:RetrievingData'), 'percentage' => $iPercentage); return $sData; }
public function GetNextChunk(&$aStatus) { $sRetCode = 'run'; $iPercentage = 0; $hFile = fopen($this->aStatusInfo['tmp_file'], 'ab'); $oSet = new DBObjectSet($this->oSearch); $oSet->SetLimit($this->iChunkSize, $this->aStatusInfo['position']); $this->OptimizeColumnLoad($oSet); $iCount = 0; $iPreviousTimeLimit = ini_get('max_execution_time'); $iLoopTimeLimit = MetaModel::GetConfig()->Get('max_execution_time_per_loop'); while ($aRow = $oSet->FetchAssoc()) { set_time_limit($iLoopTimeLimit); $aData = array(); foreach ($this->aStatusInfo['fields'] as $iCol => $aFieldSpec) { $sAlias = $aFieldSpec['sAlias']; $sAttCode = $aFieldSpec['sAttCode']; $oObj = $aRow[$sAlias]; $sField = ''; if ($oObj) { $sField = $this->GetValue($oObj, $sAttCode); } $aData[] = $sField; } fwrite($hFile, json_encode($aData) . "\n"); $iCount++; } set_time_limit($iPreviousTimeLimit); $this->aStatusInfo['position'] += $this->iChunkSize; if ($this->aStatusInfo['total'] == 0) { $iPercentage = 100; $sRetCode = 'done'; // Next phase (GetFooter) will be to build the xlsx file } else { $iPercentage = floor(min(100.0, 100.0 * $this->aStatusInfo['position'] / $this->aStatusInfo['total'])); } if ($iCount < $this->iChunkSize) { $sRetCode = 'done'; } $aStatus = array('code' => $sRetCode, 'message' => Dict::S('Core:BulkExport:RetrievingData'), 'percentage' => $iPercentage); return ''; // The actual XLSX file is built in GetFooter(); }
public function GetNextChunk(&$aStatus) { $sRetCode = 'run'; $iPercentage = 0; $oSet = new DBObjectSet($this->oSearch); $oSet->SetLimit($this->iChunkSize, $this->aStatusInfo['position']); $this->OptimizeColumnLoad($oSet); $sFirstAlias = $this->oSearch->GetClassAlias(); $iCount = 0; $sData = ''; $iPreviousTimeLimit = ini_get('max_execution_time'); $iLoopTimeLimit = MetaModel::GetConfig()->Get('max_execution_time_per_loop'); while ($aRow = $oSet->FetchAssoc()) { set_time_limit($iLoopTimeLimit); $oMainObj = $aRow[$sFirstAlias]; $sHilightClass = ''; if ($oMainObj) { $sHilightClass = $aRow[$sFirstAlias]->GetHilightClass(); } if ($sHilightClass != '') { $sData .= "<tr class=\"{$sHilightClass}\">"; } else { $sData .= "<tr>"; } foreach ($this->aStatusInfo['fields'] as $iCol => $aFieldSpec) { $sAlias = $aFieldSpec['sAlias']; $sAttCode = $aFieldSpec['sAttCode']; $oObj = $aRow[$sAlias]; $sField = ''; if ($oObj) { $sField = $this->GetValue($oObj, $sAttCode); } $sValue = $sField === '' ? ' ' : $sField; $sData .= "<td>{$sValue}</td>"; } $sData .= "</tr>"; $iCount++; } set_time_limit($iPreviousTimeLimit); $this->aStatusInfo['position'] += $this->iChunkSize; if ($this->aStatusInfo['total'] == 0) { $iPercentage = 100; } else { $iPercentage = floor(min(100.0, 100.0 * $this->aStatusInfo['position'] / $this->aStatusInfo['total'])); } if ($iCount < $this->iChunkSize) { $sRetCode = 'done'; } $aStatus = array('code' => $sRetCode, 'message' => Dict::S('Core:BulkExport:RetrievingData'), 'percentage' => $iPercentage); return $sData; }
public function GetNextChunk(&$aStatus) { $sRetCode = 'run'; $iPercentage = 0; $oSet = new DBObjectSet($this->oSearch); $aSelectedClasses = $this->oSearch->GetSelectedClasses(); $oSet->SetLimit($this->iChunkSize, $this->aStatusInfo['position']); $aAliasByField = array(); $aColumnsToLoad = array(); // Prepare the list of aliases / columns to load foreach ($this->aStatusInfo['fields'] as $sExtendedAttCode) { if (preg_match('/^([^\\.]+)\\.(.+)$/', $sExtendedAttCode, $aMatches)) { $sAlias = $aMatches[1]; $sAttCode = $aMatches[2]; } else { $sAlias = reset($aSelectedClasses); $sAttCode = $sExtendedAttCode; } if (!array_key_exists($sAlias, $aSelectedClasses)) { throw new Exception("Invalid alias '{$sAlias}' for the column '{$sExtendedAttCode}'. Availables aliases: '" . implode("', '", array_keys($aSelectedClasses)) . "'"); } if (!array_key_exists($sAlias, $aColumnsToLoad)) { $aColumnsToLoad[$sAlias] = array(); } if ($sAttCode != 'id') { // id is not a real attribute code and, moreover, is always loaded $aColumnsToLoad[$sAlias][] = $sAttCode; } $aAliasByField[$sExtendedAttCode] = array('alias' => $sAlias, 'attcode' => $sAttCode); } $iCount = 0; $sData = ''; $oSet->OptimizeColumnLoad($aColumnsToLoad); $iPreviousTimeLimit = ini_get('max_execution_time'); $iLoopTimeLimit = MetaModel::GetConfig()->Get('max_execution_time_per_loop'); while ($aRow = $oSet->FetchAssoc()) { set_time_limit($iLoopTimeLimit); $sData .= "<tr>"; foreach ($aAliasByField as $aAttCode) { $sField = ''; $oObj = $aRow[$aAttCode['alias']]; if ($oObj == null) { $sData .= "<td x:str>{$sField}</td>"; continue; } switch ($aAttCode['attcode']) { case 'id': $sField = $oObj->GetName(); $sData .= "<td>{$sField}</td>"; break; default: $oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $aAttCode['attcode']); $oFinalAttDef = $oAttDef->GetFinalAttDef(); if (get_class($oFinalAttDef) == 'AttributeDateTime') { $iDate = AttributeDateTime::GetAsUnixSeconds($oObj->Get($aAttCode['attcode'])); $sData .= '<td>' . date('Y-m-d', $iDate) . '</td>'; // Add the first column directly $sField = date('H:i:s', $iDate); // Will add the second column below $sData .= "<td>{$sField}</td>"; } else { if ($oAttDef instanceof AttributeCaseLog) { $rawValue = $oObj->Get($aAttCode['attcode']); $sField = str_replace("\n", "<br/>", htmlentities($rawValue->__toString(), ENT_QUOTES, 'UTF-8')); // Trick for Excel: treat the content as text even if it begins with an equal sign $sData .= "<td x:str>{$sField}</td>"; } else { $rawValue = $oObj->Get($aAttCode['attcode']); // Due to custom formatting rules, empty friendlynames may be rendered as non-empty strings // let's fix this and make sure we render an empty string if the key == 0 if ($oAttDef instanceof AttributeFriendlyName) { $sKeyAttCode = $oAttDef->GetKeyAttCode(); if ($sKeyAttCode != 'id') { if ($oObj->Get($sKeyAttCode) == 0) { $sValue = ''; } } } if ($this->aStatusInfo['localize']) { $sField = htmlentities($oFinalAttDef->GetEditValue($rawValue), ENT_QUOTES, 'UTF-8'); } else { $sField = htmlentities($rawValue, ENT_QUOTES, 'UTF-8'); } $sData .= "<td>{$sField}</td>"; } } } } $sData .= "</tr>"; $iCount++; } set_time_limit($iPreviousTimeLimit); $this->aStatusInfo['position'] += $this->iChunkSize; if ($this->aStatusInfo['total'] == 0) { $iPercentage = 100; } else { $iPercentage = floor(min(100.0, 100.0 * $this->aStatusInfo['position'] / $this->aStatusInfo['total'])); } if ($iCount < $this->iChunkSize) { $sRetCode = 'done'; } $aStatus = array('code' => $sRetCode, 'message' => Dict::S('Core:BulkExport:RetrievingData'), 'percentage' => $iPercentage); return $sData; }
public function GetNextChunk(&$aStatus) { $sRetCode = 'run'; $iPercentage = 0; $hFile = fopen($this->aStatusInfo['tmp_file'], 'ab'); $oSet = new DBObjectSet($this->oSearch); $aSelectedClasses = $this->oSearch->GetSelectedClasses(); $aAliases = array_keys($aSelectedClasses); $oSet->SetLimit($this->iChunkSize, $this->aStatusInfo['position']); $aAliasByField = array(); $aColumnsToLoad = array(); // Prepare the list of aliases / columns to load foreach ($this->aStatusInfo['fields'] as $sExtendedAttCode) { if (preg_match('/^([^\\.]+)\\.(.+)$/', $sExtendedAttCode, $aMatches)) { $sAlias = $aMatches[1]; $sAttCode = $aMatches[2]; } else { $sAlias = reset($aAliases); $sAttCode = $sExtendedAttCode; } if (!in_array($sAlias, $aAliases)) { throw new Exception("Invalid alias '{$sAlias}' for the column '{$sExtendedAttCode}'. Availables aliases: '" . implode("', '", $aAliases) . "'"); } if (!array_key_exists($sAlias, $aColumnsToLoad)) { $aColumnsToLoad[$sAlias] = array(); } if ($sAttCode != 'id') { // id is not a real attribute code and, moreover, is always loaded $aColumnsToLoad[$sAlias][] = $sAttCode; } $aAliasByField[$sExtendedAttCode] = array('alias' => $sAlias, 'attcode' => $sAttCode); } $iCount = 0; $oSet->OptimizeColumnLoad($aColumnsToLoad); $iPreviousTimeLimit = ini_get('max_execution_time'); $iLoopTimeLimit = MetaModel::GetConfig()->Get('max_execution_time_per_loop'); while ($aRow = $oSet->FetchAssoc()) { set_time_limit($iLoopTimeLimit); $aData = array(); foreach ($aAliasByField as $aAttCode) { $sField = ''; switch ($aAttCode['attcode']) { case 'id': $sField = $aRow[$aAttCode['alias']]->GetKey(); break; default: $value = $aRow[$aAttCode['alias']]->Get($aAttCode['attcode']); if ($value instanceof ormCaseLog) { // Extract the case log as text and remove the "===" which make Excel think that the cell contains a formula the next time you edit it! $sField = trim(preg_replace('/========== ([^=]+) ============/', '********** $1 ************', $value->GetText())); } else { if ($value instanceof DBObjectSet) { $oAttDef = MetaModel::GetAttributeDef(get_class($aRow[$aAttCode['alias']]), $aAttCode['attcode']); $sField = $oAttDef->GetAsCSV($value, '', '', $aRow[$aAttCode['alias']]); } else { $oAttDef = MetaModel::GetAttributeDef(get_class($aRow[$aAttCode['alias']]), $aAttCode['attcode']); $sField = $oAttDef->GetEditValue($value, $aRow[$aAttCode['alias']]); } } } $aData[] = $sField; } fwrite($hFile, json_encode($aData) . "\n"); $iCount++; } set_time_limit($iPreviousTimeLimit); $this->aStatusInfo['position'] += $this->iChunkSize; if ($this->aStatusInfo['total'] == 0) { $iPercentage = 100; $sRetCode = 'done'; // Next phase (GetFooter) will be to build the xlsx file } else { $iPercentage = floor(min(100.0, 100.0 * $this->aStatusInfo['position'] / $this->aStatusInfo['total'])); } if ($iCount < $this->iChunkSize) { $sRetCode = 'done'; } $aStatus = array('code' => $sRetCode, 'message' => Dict::S('Core:BulkExport:RetrievingData'), 'percentage' => $iPercentage); return ''; // The actual XLSX file is built in GetFooter(); }
/** * Display the history of bulk imports */ static function DisplayImportHistory(WebPage $oPage, $bFromAjax = false, $bShowAll = false) { $sAjaxDivId = "CSVImportHistory"; if (!$bFromAjax) { $oPage->add('<div id="' . $sAjaxDivId . '">'); } $oPage->p(Dict::S('UI:History:BulkImports+') . ' <span id="csv_history_reload"></span>'); $oBulkChangeSearch = DBObjectSearch::FromOQL("SELECT CMDBChange WHERE origin IN ('csv-interactive', 'csv-import.php')"); $iQueryLimit = $bShowAll ? 0 : appUserPreferences::GetPref('default_page_size', MetaModel::GetConfig()->GetMinDisplayLimit()); $oBulkChanges = new DBObjectSet($oBulkChangeSearch, array('date' => false), array(), null, $iQueryLimit); $oAppContext = new ApplicationContext(); $bLimitExceeded = false; if ($oBulkChanges->Count() > appUserPreferences::GetPref('default_page_size', MetaModel::GetConfig()->GetMinDisplayLimit())) { $bLimitExceeded = true; if (!$bShowAll) { $iMaxObjects = appUserPreferences::GetPref('default_page_size', MetaModel::GetConfig()->GetMinDisplayLimit()); $oBulkChanges->SetLimit($iMaxObjects); } } $oBulkChanges->Seek(0); $aDetails = array(); while ($oChange = $oBulkChanges->Fetch()) { $sDate = '<a href="csvimport.php?step=10&changeid=' . $oChange->GetKey() . '&' . $oAppContext->GetForLink() . '">' . $oChange->Get('date') . '</a>'; $sUser = $oChange->GetUserName(); if (preg_match('/^(.*)\\(CSV\\)$/i', $oChange->Get('userinfo'), $aMatches)) { $sUser = $aMatches[1]; } else { $sUser = $oChange->Get('userinfo'); } $oOpSearch = DBObjectSearch::FromOQL("SELECT CMDBChangeOpCreate WHERE change = :change_id"); $oOpSet = new DBObjectSet($oOpSearch, array(), array('change_id' => $oChange->GetKey())); $iCreated = $oOpSet->Count(); // Get the class from the first item found (assumption: a CSV load is done for a single class) if ($oCreateOp = $oOpSet->Fetch()) { $sClass = $oCreateOp->Get('objclass'); } $oOpSearch = DBObjectSearch::FromOQL("SELECT CMDBChangeOpSetAttribute WHERE change = :change_id"); $oOpSet = new DBObjectSet($oOpSearch, array(), array('change_id' => $oChange->GetKey())); $aModified = array(); $aAttList = array(); while ($oModified = $oOpSet->Fetch()) { // Get the class (if not done earlier on object creation) $sClass = $oModified->Get('objclass'); $iKey = $oModified->Get('objkey'); $sAttCode = $oModified->Get('attcode'); $aAttList[$sClass][$sAttCode] = true; $aModified["{$sClass}::{$iKey}"] = true; } $iModified = count($aModified); // Assumption: there is only one class of objects being loaded // Then the last class found gives us the class for every object if ($iModified > 0 || $iCreated > 0) { $aDetails[] = array('date' => $sDate, 'user' => $sUser, 'class' => $sClass, 'created' => $iCreated, 'modified' => $iModified); } } $aConfig = array('date' => array('label' => Dict::S('UI:History:Date'), 'description' => Dict::S('UI:History:Date+')), 'user' => array('label' => Dict::S('UI:History:User'), 'description' => Dict::S('UI:History:User+')), 'class' => array('label' => Dict::S('Core:AttributeClass'), 'description' => Dict::S('Core:AttributeClass+')), 'created' => array('label' => Dict::S('UI:History:StatsCreations'), 'description' => Dict::S('UI:History:StatsCreations+')), 'modified' => array('label' => Dict::S('UI:History:StatsModifs'), 'description' => Dict::S('UI:History:StatsModifs+'))); if ($bLimitExceeded) { if ($bShowAll) { // Collapsible list $oPage->add('<p>' . Dict::Format('UI:CountOfResults', $oBulkChanges->Count()) . ' <a class="truncated" onclick="OnTruncatedHistoryToggle(false);">' . Dict::S('UI:CollapseList') . '</a></p>'); } else { // Truncated list $iMinDisplayLimit = appUserPreferences::GetPref('default_page_size', MetaModel::GetConfig()->GetMinDisplayLimit()); $sCollapsedLabel = Dict::Format('UI:TruncatedResults', $iMinDisplayLimit, $oBulkChanges->Count()); $sLinkLabel = Dict::S('UI:DisplayAll'); $oPage->add('<p>' . $sCollapsedLabel . ' <a class="truncated" onclick="OnTruncatedHistoryToggle(true);">' . $sLinkLabel . '</p>'); $oPage->add_ready_script(<<<EOF \t\$('#{$sAjaxDivId} table.listResults').addClass('truncated'); \t\$('#{$sAjaxDivId} table.listResults tr:last td').addClass('truncated'); EOF ); $sAppContext = $oAppContext->GetForLink(); $oPage->add_script(<<<EOF \tfunction OnTruncatedHistoryToggle(bShowAll) \t{ \t\t\$('#csv_history_reload').html('<img src="../images/indicator.gif"/>'); \t\t\$.get(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php?{$sAppContext}', {operation: 'displayCSVHistory', showall: bShowAll}, function(data) \t\t\t{ \t\t\t\t\$('#{$sAjaxDivId}').html(data); \t\t\t\tvar table = \$('#{$sAjaxDivId} .listResults'); \t\t\t\ttable.tableHover(); // hover tables \t\t\t\ttable.tablesorter( { widgets: ['myZebra', 'truncatedList']} ); // sortable and zebra tables \t\t\t} \t\t); \t} EOF ); } } else { // Normal display - full list without any decoration } $oPage->table($aConfig, $aDetails); if (!$bFromAjax) { $oPage->add('</div>'); } }
public function GetNextChunk(&$aStatus) { $sRetCode = 'run'; $iPercentage = 0; $iCount = 0; $sData = ''; $oSet = new DBObjectSet($this->oSearch); $oSet->SetLimit($this->iChunkSize, $this->aStatusInfo['position']); $bLocalize = $this->aStatusInfo['localize']; $aClasses = $this->oSearch->GetSelectedClasses(); $aAuthorizedClasses = array(); foreach ($aClasses as $sAlias => $sClassName) { if (UserRights::IsActionAllowed($sClassName, UR_ACTION_BULK_READ, $oSet) && (UR_ALLOWED_YES || UR_ALLOWED_DEPENDS)) { $aAuthorizedClasses[$sAlias] = $sClassName; } } $aAttribs = array(); $aList = array(); $aList[$sAlias] = MetaModel::GetZListItems($sClassName, 'details'); $iPreviousTimeLimit = ini_get('max_execution_time'); $iLoopTimeLimit = MetaModel::GetConfig()->Get('max_execution_time_per_loop'); while ($aObjects = $oSet->FetchAssoc()) { set_time_limit($iLoopTimeLimit); if (count($aAuthorizedClasses) > 1) { $sData .= "<Row>\n"; } foreach ($aAuthorizedClasses as $sAlias => $sClassName) { $oObj = $aObjects[$sAlias]; if (is_null($oObj)) { $sData .= "<{$sClassName} alias=\"{$sAlias}\" id=\"null\">\n"; } else { $sClassName = get_class($oObj); $sData .= "<{$sClassName} alias=\"{$sAlias}\" id=\"" . $oObj->GetKey() . "\">\n"; } foreach (MetaModel::ListAttributeDefs($sClassName) as $sAttCode => $oAttDef) { if (is_null($oObj)) { $sData .= "<{$sAttCode}>null</{$sAttCode}>\n"; } else { if ($oAttDef->IsWritable()) { $sValue = $oObj->GetAsXML($sAttCode, $bLocalize); $sData .= "<{$sAttCode}>{$sValue}</{$sAttCode}>\n"; } } } $sData .= "</{$sClassName}>\n"; } if (count($aAuthorizedClasses) > 1) { $sData .= "</Row>\n"; } $iCount++; } set_time_limit($iPreviousTimeLimit); $this->aStatusInfo['position'] += $this->iChunkSize; if ($this->aStatusInfo['total'] == 0) { $iPercentage = 100; } else { $iPercentage = floor(min(100.0, 100.0 * $this->aStatusInfo['position'] / $this->aStatusInfo['total'])); } if ($iCount < $this->iChunkSize) { $sRetCode = 'done'; } $aStatus = array('code' => $sRetCode, 'message' => Dict::S('Core:BulkExport:RetrievingData'), 'percentage' => $iPercentage); return $sData; }