diff --git a/modules/Vtiger/actions/ExportData.php b/modules/Vtiger/actions/ExportData.php index bfe0583c3..f6f916de3 100644 --- a/modules/Vtiger/actions/ExportData.php +++ b/modules/Vtiger/actions/ExportData.php @@ -31,6 +31,7 @@ function process(Vtiger_Request $request) { private $moduleInstance; private $focus; + private $exportBatchLimit = 10_000; // 1回のクエリで取得するデータ数上限 /** * Function exports the data based on the mode @@ -44,9 +45,6 @@ function ExportData(Vtiger_Request $request) { $this->moduleFieldInstances = $this->moduleFieldInstances($moduleName); $this->focus = CRMEntity::getInstance($moduleName); - $query = $this->getExportQuery($request); - $result = $db->pquery($query, array()); - $redirectedModules = array('Users', 'Calendar'); if($request->getModule() != $moduleName && in_array($moduleName, $redirectedModules) && !$this->moduleCall){ $handlerClass = Vtiger_Loader::getComponentClassName('Action', 'ExportData', $moduleName); @@ -54,37 +52,51 @@ function ExportData(Vtiger_Request $request) { $handler->ExportData($request); return; } - $translatedHeaders = $this->getHeaders(); - $entries = array(); - for ($j = 0; $j < $db->num_rows($result); $j++) { - $entries[] = $this->sanitizeValues($db->fetchByAssoc($result, $j)); - } - //エクスポート時の選択肢項目の翻訳処理 - for ($i = 0; $i < $j; $i++){ - $moduleModel = Vtiger_Module_Model::getInstance($moduleName); - $moduleFields = $moduleModel->getFields(); - foreach ($entries[$i] as $columnName => $fieldValue) { - $fieldModel = $moduleFields[$columnName]; - if(empty($fieldModel)){ - foreach($moduleFields as $key => $fieldinfo){ - if($fieldinfo->column == $columnName){ - $fieldName = $fieldinfo->name; + $batchoffset = 0; + while(true){ // 取得するデータが無い場合に終了 + $request->set('batchoffset', $batchoffset); + $query = $this->getExportQuery($request); + $result = $db->pquery($query, array()); + $entries = array(); + for ($j = 0; $j < $db->num_rows($result); $j++) { + $entries[] = $this->sanitizeValues($db->fetchByAssoc($result, $j)); + } + if(empty($entries)){ + break; + } + + //エクスポート時の選択肢項目の翻訳処理 + for ($i = 0; $i < $j; $i++){ + $moduleModel = Vtiger_Module_Model::getInstance($moduleName); + $moduleFields = $moduleModel->getFields(); + foreach ($entries[$i] as $columnName => $fieldValue) { + $fieldModel = $moduleFields[$columnName]; + if(empty($fieldModel)){ + foreach($moduleFields as $key => $fieldinfo){ + if($fieldinfo->column == $columnName){ + $fieldName = $fieldinfo->name; + } } + $fieldModel = $moduleFields[$fieldName]; } - $fieldModel = $moduleFields[$fieldName]; - } - $fieldDataType = ($fieldModel) ? $fieldModel->getFieldDataType() : ''; + $fieldDataType = ($fieldModel) ? $fieldModel->getFieldDataType() : ''; - if ($fieldDataType == 'picklist') { - $entries[$i][$columnName] = vtranslate($fieldValue,$moduleName); + if ($fieldDataType == 'picklist') { + $entries[$i][$columnName] = vtranslate($fieldValue,$moduleName); + } } } + if($batchoffset == 0){ + $translatedHeaders = $this->getHeaders(); + $this->output($request, $translatedHeaders, $entries); + }else{ + $this->output($request, '', $entries); + } + $batchoffset = $batchoffset + $this->exportBatchLimit; // オフセットの更新 } - - $this->output($request, $translatedHeaders, $entries); } public function getHeaders() { @@ -205,6 +217,10 @@ function getExportQuery(Vtiger_Request $request) { case 'ExportAllData' : if ($orderBy && $orderByFieldModel) { $query .= ' ORDER BY '.$queryGenerator->getOrderByColumn($orderBy).' '.$sortOrder; } + $batchOffset = $request->get('batchoffset'); + if(isset($batchOffset)){ + $query .= ' LIMIT '.$this->exportBatchLimit.' OFFSET '.$batchOffset; + } break; case 'ExportCurrentPage' : $pagingModel = new Vtiger_Paging_Model(); @@ -239,6 +255,10 @@ function getExportQuery(Vtiger_Request $request) { if ($orderBy && $orderByFieldModel) { $query .= ' ORDER BY '.$queryGenerator->getOrderByColumn($orderBy).' '.$sortOrder; } + $batchOffset = $request->get('batchoffset'); + if(isset($batchOffset)){ + $query .= ' LIMIT '.$this->exportBatchLimit.' OFFSET '.$batchOffset; + } break; @@ -272,16 +292,18 @@ function output($request, $headers, $entries) { $fileName = str_replace(',', '_', $fileName); $exportType = $this->getExportContentType($request); - header("Content-Disposition:attachment;filename=$fileName.csv"); - header("Content-Type:$exportType;charset=UTF-8"); - header("Expires: Mon, 31 Dec 2000 00:00:00 GMT" ); - header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT" ); - header("Cache-Control: post-check=0, pre-check=0", false ); - - $header = implode("\",\"", $headers); - $header = "\"" .$header; - $header .= "\"\r\n"; - echo chr(0xEF).chr(0xBB).chr(0xBF).$header; + if(!empty($headers)){ // 最初のバッチ処理で実行 + header("Content-Disposition:attachment;filename=$fileName.csv"); + header("Content-Type:$exportType;charset=UTF-8"); + header("Expires: Mon, 31 Dec 2000 00:00:00 GMT" ); + header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT" ); + header("Cache-Control: post-check=0, pre-check=0", false ); + + $header = implode("\",\"", $headers); + $header = "\"" .$header; + $header .= "\"\r\n"; + echo chr(0xEF).chr(0xBB).chr(0xBF).$header; + } $cnt = 0; foreach($entries as $row) {