PHP#資料Excel導出的一些政策
導出其實在任何類型的後端系統都比較常見,正規情況下excel導出的資料應該更多的用來做備份、底稿,理想情況下針對業務資料的任何業務操作都不應該依靠從後端業務系統導出資料然後人工進行幹涉處理,但現實很骨感。。。
資料導出這類的功能在有條件的情況下是須要封裝起來的,隻有一個資料出口,在後續的業務規則調整變更時會真正的展現出它的價值。當一個典型的應用系統出現了五花八門的資料導出需求,說明這個應用系統的業務分析做的不夠好或者很差,當使用者隻想用應用系統導出資料來輔助他們的業務流程時,最恐怖的情況就會是使用者和資料庫的距離隻是隔着一個導出按鈕。。。
環境
1.PHP5.5.14 (cli) (built: Sep 9 201419:09:25)
2.PHP Excel 1.7.8 (http://www.codeplex.com/PHPExcel)
處理邏輯
其實這類問題的關鍵點就是如何定義導出規則,定義的這套規則是否能适應業務流程,最基本的辦法就是将資料導出的過程抽象為3個基礎階段,而後每個階段可以再進行逐漸的細化:
1.導出規則的定義
2.業務資料與導出規則的适配
3.導出規則解析構造Excel
示例
該示例實作了基本的導出功能,沒有進行任何封裝,沒有關注性能或其它擴充性問題。
[php] view plain copy print ?
- <?php
- namespace org\ybygjy\comp\excel;
- class ExcelComp {
- public function __construct() {
- require_once 'org/ybygjy/library/excel/PHPExcel.php';
- }
- public function doTest() {
- //構造原始資料
- $dataArray = $this->buildData();
- //導出
- $this->doExportData($dataArray);
- }
- public function doExportData($dataArr) {
- $phpObjExcel = new \PHPExcel();
- $worksSheet = $phpObjExcel->setActiveSheetIndex(0);
- //構造表頭資料_Begin
- $tmpColTitles = [];
- $firstDataEntry = $dataArr[0];
- //配置設定列索引
- $colIndex = 0;
- foreach($firstDataEntry as $key => $val) {
- if (preg_match('/^_/', $key)) {
- continue;
- }
- if (is_array($val)) {
- //取array下的列名稱
- $val = $val[0];
- $rowNums = count($val);
- foreach ($val as $innerKey => $innerValue) {
- $tmpColTitles[] = array(
- 'parentKey' => $key,
- 'key' => $innerKey,
- 'colIndex' => $colIndex
- );
- $colIndex++;
- }
- } else {
- $tmpColTitles[] = array(
- 'key'=>$key,
- 'colIndex'=>$colIndex
- );
- $colIndex++;
- }
- }
- for($i = 0; $i < count($tmpColTitles); $i++) {
- $tmpObj = $tmpColTitles[$i];
- $key = $tmpObj['key'];
- $colIndex = $tmpObj['colIndex'];
- $worksSheet->setCellValueByColumnAndRow($colIndex,1,$key);
- }
- //構造表頭資料_End
- //填充單元格資料
- $currRow = 2;
- foreach ($dataArr as $dataEntry) {
- $mergeRow = $dataEntry['_DIMENSION'];
- foreach ($tmpColTitles as $colEntry) {
- $key = $colEntry['key'];
- $colIndex = $colEntry['colIndex'];
- $parentKey = (isset($colEntry['parentKey']) ? $colEntry['parentKey'] : null);
- if (empty($parentKey)) {
- $value = $dataEntry[$key];
- if ($mergeRow == 1) {
- $worksSheet->setCellValueByColumnAndRow($colIndex, $currRow, $value);
- } else {
- $worksSheet->mergeCellsByColumnAndRow($colIndex, $currRow, $colIndex, ($currRow + $mergeRow - 1))->setCellValueByColumnAndRow($colIndex, $currRow, $value);
- }
- } else {
- $tmpDataArr = $dataEntry[$parentKey];
- $innerRow = $currRow;
- for($index = 0; $index < count($tmpDataArr); $index++) {
- $innerDataEntry = $tmpDataArr[$index];
- $value = $innerDataEntry[$key];
- $worksSheet->setCellValueByColumnAndRow($colIndex, $innerRow, $value);
- $innerRow++;
- }
- }
- }
- $currRow += $mergeRow;
- }
- header('Content-Type: application/vnd.ms-excel');
- header('Content-Type: application/force-download');
- header('Content-Type: application/octet-stream');
- header('Content-Type: application/download');
- header('Content-Disposition: attachment;filename="HelloWord.xls"');
- header('Cache-Control: max-age=0');
- header('Cache-Control: max-age=1');
- header('Cache-Control: no-cache, must-revalidate');
- header('Pragma: public');
- $objWriter = \PHPExcel_IOFactory::createWriter($phpObjExcel, 'Excel5');
- $objWriter->save('php://output');
- }
- private function buildData() {
- $rtnData = array(
- array(
- 'name'=>'YanCheng_01',
- 'age'=>'20',
- 'addr'=>array(
- array(
- 'country'=>'China',
- 'province'=>'ShanDong'
- ),
- array(
- 'country'=>'China',
- 'province'=>'BeiJing'
- )
- ),
- '_DIMENSION'=>2
- ),
- array(
- 'name'=>'YanCheng_02',
- 'age'=>'21',
- 'addr'=>array(
- array(
- 'country'=>'China',
- 'province'=>'LanZhou'
- ),
- array(
- 'country'=>'China',
- 'province'=>'NingXia'
- )
- ),
- '_DIMENSION'=>2
- ),
- array(
- 'name'=>'YanCheng_03',
- 'age'=>'22',
- 'addr'=>array(
- array(
- 'country'=>'China',
- 'province'=>'JiaYuGuan'
- )
- ),
- '_DIMENSION'=>1
- )
- );
- return $rtnData;
- }
- }