@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Support Excel as a data export format

Summary:
Depends on D18954. Ref T13049. This brings over the existing Maniphest Excel export pipeline in a generic way.

The `<Type>ExportField` classes know directly that `PHPExcel` exists, which is a little sketchy, but writing an Excel indirection layer sounds like a lot of work and I don't anticipate us changing Excel backends anytime soon, so trying to abstract this feels YAGNI.

This doesn't bring over the install instructions for PHPExcel or the detection of whether or not it exists. I'll bring that over in a future change.

Test Plan: Exported users as Excel, opened them up, got a sensible-looking Excel sheet.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13049

Differential Revision: https://secure.phabricator.com/D18955

+223 -3
+2
src/__phutil_library_map__.php
··· 2847 2847 'PhabricatorEventListener' => 'infrastructure/events/PhabricatorEventListener.php', 2848 2848 'PhabricatorEventType' => 'infrastructure/events/constant/PhabricatorEventType.php', 2849 2849 'PhabricatorExampleEventListener' => 'infrastructure/events/PhabricatorExampleEventListener.php', 2850 + 'PhabricatorExcelExportFormat' => 'infrastructure/export/PhabricatorExcelExportFormat.php', 2850 2851 'PhabricatorExecFutureFileUploadSource' => 'applications/files/uploadsource/PhabricatorExecFutureFileUploadSource.php', 2851 2852 'PhabricatorExportEngineExtension' => 'infrastructure/export/PhabricatorExportEngineExtension.php', 2852 2853 'PhabricatorExportField' => 'infrastructure/export/PhabricatorExportField.php', ··· 8282 8283 'PhabricatorEventListener' => 'PhutilEventListener', 8283 8284 'PhabricatorEventType' => 'PhutilEventType', 8284 8285 'PhabricatorExampleEventListener' => 'PhabricatorEventListener', 8286 + 'PhabricatorExcelExportFormat' => 'PhabricatorExportFormat', 8285 8287 'PhabricatorExecFutureFileUploadSource' => 'PhabricatorFileUploadSource', 8286 8288 'PhabricatorExportEngineExtension' => 'Phobject', 8287 8289 'PhabricatorExportField' => 'Phobject',
+5 -2
src/applications/search/controller/PhabricatorApplicationSearchController.php
··· 410 410 411 411 if ($named_query) { 412 412 $filename = $named_query->getQueryName(); 413 + $sheet_title = $named_query->getQueryName(); 413 414 } else { 414 415 $filename = $engine->getResultTypeDescription(); 416 + $sheet_title = $engine->getResultTypeDescription(); 415 417 } 416 418 $filename = phutil_utf8_strtolower($filename); 417 419 $filename = PhabricatorFile::normalizeFileName($filename); ··· 445 447 $mime_type = $format->getMIMEContentType(); 446 448 $filename = $filename.'.'.$extension; 447 449 448 - $format = clone $format; 449 - $format->setViewer($viewer); 450 + $format = id(clone $format) 451 + ->setViewer($viewer) 452 + ->setTitle($sheet_title); 450 453 451 454 $export_data = $engine->newExport($objects); 452 455 $objects = array_values($objects);
+20
src/infrastructure/export/PhabricatorEpochExportField.php
··· 24 24 return (int)$value; 25 25 } 26 26 27 + public function getPHPExcelValue($value) { 28 + $epoch = $this->getNaturalValue($value); 29 + 30 + $seconds_per_day = phutil_units('1 day in seconds'); 31 + $offset = ($seconds_per_day * 25569); 32 + 33 + return ($epoch + $offset) / $seconds_per_day; 34 + } 35 + 36 + /** 37 + * @phutil-external-symbol class PHPExcel_Style_NumberFormat 38 + */ 39 + public function formatPHPExcelCell($cell, $style) { 40 + $code = PHPExcel_Style_NumberFormat::FORMAT_DATE_YYYYMMDD2; 41 + 42 + $style 43 + ->getNumberFormat() 44 + ->setFormatCode($code); 45 + } 46 + 27 47 }
+145
src/infrastructure/export/PhabricatorExcelExportFormat.php
··· 1 + <?php 2 + 3 + final class PhabricatorExcelExportFormat 4 + extends PhabricatorExportFormat { 5 + 6 + const EXPORTKEY = 'excel'; 7 + 8 + private $workbook; 9 + private $sheet; 10 + private $rowCursor; 11 + 12 + public function getExportFormatName() { 13 + return pht('Excel (.xlsx)'); 14 + } 15 + 16 + public function isExportFormatEnabled() { 17 + return true; 18 + } 19 + 20 + public function getFileExtension() { 21 + return 'xlsx'; 22 + } 23 + 24 + public function getMIMEContentType() { 25 + return 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'; 26 + } 27 + 28 + /** 29 + * @phutil-external-symbol class PHPExcel_Cell_DataType 30 + */ 31 + public function addHeaders(array $fields) { 32 + $sheet = $this->getSheet(); 33 + 34 + $header_format = array( 35 + 'font' => array( 36 + 'bold' => true, 37 + ), 38 + ); 39 + 40 + $row = 1; 41 + $col = 0; 42 + foreach ($fields as $field) { 43 + $cell_value = $field->getLabel(); 44 + 45 + $cell_name = $this->getCellName($col, $row); 46 + 47 + $cell = $sheet->setCellValue( 48 + $cell_name, 49 + $cell_value, 50 + $return_cell = true); 51 + 52 + $sheet->getStyle($cell_name)->applyFromArray($header_format); 53 + $cell->setDataType(PHPExcel_Cell_DataType::TYPE_STRING); 54 + 55 + $width = $field->getCharacterWidth(); 56 + if ($width !== null) { 57 + $col_name = $this->getCellName($col); 58 + $sheet->getColumnDimension($col_name) 59 + ->setWidth($width); 60 + } 61 + 62 + $col++; 63 + } 64 + } 65 + 66 + public function addObject($object, array $fields, array $map) { 67 + $sheet = $this->getSheet(); 68 + 69 + $col = 0; 70 + foreach ($fields as $key => $field) { 71 + $cell_value = $map[$key]; 72 + $cell_value = $field->getPHPExcelValue($cell_value); 73 + 74 + $cell_name = $this->getCellName($col, $this->rowCursor); 75 + 76 + $cell = $sheet->setCellValue( 77 + $cell_name, 78 + $cell_value, 79 + $return_cell = true); 80 + 81 + $style = $sheet->getStyle($cell_name); 82 + $field->formatPHPExcelCell($cell, $style); 83 + 84 + $col++; 85 + } 86 + 87 + $this->rowCursor++; 88 + } 89 + 90 + /** 91 + * @phutil-external-symbol class PHPExcel_IOFactory 92 + */ 93 + public function newFileData() { 94 + $workbook = $this->getWorkbook(); 95 + $writer = PHPExcel_IOFactory::createWriter($workbook, 'Excel2007'); 96 + 97 + ob_start(); 98 + $writer->save('php://output'); 99 + $data = ob_get_clean(); 100 + 101 + return $data; 102 + } 103 + 104 + private function getWorkbook() { 105 + if (!$this->workbook) { 106 + $this->workbook = $this->newWorkbook(); 107 + } 108 + return $this->workbook; 109 + } 110 + 111 + /** 112 + * @phutil-external-symbol class PHPExcel 113 + */ 114 + private function newWorkbook() { 115 + include_once 'PHPExcel.php'; 116 + return new PHPExcel(); 117 + } 118 + 119 + private function getSheet() { 120 + if (!$this->sheet) { 121 + $workbook = $this->getWorkbook(); 122 + 123 + $sheet = $workbook->setActiveSheetIndex(0); 124 + $sheet->setTitle($this->getTitle()); 125 + 126 + $this->sheet = $sheet; 127 + 128 + // The row cursor starts on the second row, after the header row. 129 + $this->rowCursor = 2; 130 + } 131 + 132 + return $this->sheet; 133 + } 134 + 135 + private function getCellName($col, $row = null) { 136 + $col_name = chr(ord('A') + $col); 137 + 138 + if ($row === null) { 139 + return $col_name; 140 + } 141 + 142 + return $col_name.$row; 143 + } 144 + 145 + }
+15
src/infrastructure/export/PhabricatorExportField.php
··· 32 32 return $value; 33 33 } 34 34 35 + public function getPHPExcelValue($value) { 36 + return $this->getTextValue($value); 37 + } 38 + 39 + /** 40 + * @phutil-external-symbol class PHPExcel_Cell_DataType 41 + */ 42 + public function formatPHPExcelCell($cell, $style) { 43 + $cell->setDataType(PHPExcel_Cell_DataType::TYPE_STRING); 44 + } 45 + 46 + public function getCharacterWidth() { 47 + return 24; 48 + } 49 + 35 50 }
+10
src/infrastructure/export/PhabricatorExportFormat.php
··· 4 4 extends Phobject { 5 5 6 6 private $viewer; 7 + private $title; 7 8 8 9 final public function getExportFormatKey() { 9 10 return $this->getPhobjectClassConstant('EXPORTKEY'); ··· 16 17 17 18 final public function getViewer() { 18 19 return $this->viewer; 20 + } 21 + 22 + final public function setTitle($title) { 23 + $this->title = $title; 24 + return $this; 25 + } 26 + 27 + final public function getTitle() { 28 + return $this->title; 19 29 } 20 30 21 31 abstract public function getExportFormatName();
+4
src/infrastructure/export/PhabricatorIDExportField.php
··· 7 7 return (int)$value; 8 8 } 9 9 10 + public function getCharacterWidth() { 11 + return 12; 12 + } 13 + 10 14 }
+15
src/infrastructure/export/PhabricatorIntExportField.php
··· 4 4 extends PhabricatorExportField { 5 5 6 6 public function getNaturalValue($value) { 7 + if ($value === null) { 8 + return $value; 9 + } 10 + 7 11 return (int)$value; 12 + } 13 + 14 + /** 15 + * @phutil-external-symbol class PHPExcel_Cell_DataType 16 + */ 17 + public function formatPHPExcelCell($cell, $style) { 18 + $cell->setDataType(PHPExcel_Cell_DataType::TYPE_NUMERIC); 19 + } 20 + 21 + public function getCharacterWidth() { 22 + return 8; 8 23 } 9 24 10 25 }
+7 -1
src/infrastructure/export/PhabricatorPHIDExportField.php
··· 1 1 <?php 2 2 3 3 final class PhabricatorPHIDExportField 4 - extends PhabricatorExportField {} 4 + extends PhabricatorExportField { 5 + 6 + public function getCharacterWidth() { 7 + return 32; 8 + } 9 + 10 + }