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 === '' ? '&nbsp;' : $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 === '' ? '&nbsp;' : $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()) . '&nbsp;&nbsp;<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 . '&nbsp;&nbsp;<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;
 }