@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
at upstream/main 168 lines 4.6 kB view raw
1<?php 2 3final class PhabricatorExportEngine 4 extends Phobject { 5 6 private $viewer; 7 private $searchEngine; 8 private $savedQuery; 9 private $exportFormat; 10 private $filename; 11 private $title; 12 13 public function setViewer(PhabricatorUser $viewer) { 14 $this->viewer = $viewer; 15 return $this; 16 } 17 18 public function getViewer() { 19 return $this->viewer; 20 } 21 22 public function setSearchEngine( 23 PhabricatorApplicationSearchEngine $search_engine) { 24 $this->searchEngine = $search_engine; 25 return $this; 26 } 27 28 public function getSearchEngine() { 29 return $this->searchEngine; 30 } 31 32 public function setSavedQuery(PhabricatorSavedQuery $saved_query) { 33 $this->savedQuery = $saved_query; 34 return $this; 35 } 36 37 public function getSavedQuery() { 38 return $this->savedQuery; 39 } 40 41 public function setExportFormat( 42 PhabricatorExportFormat $export_format) { 43 $this->exportFormat = $export_format; 44 return $this; 45 } 46 47 public function getExportFormat() { 48 return $this->exportFormat; 49 } 50 51 public function setFilename($filename) { 52 $this->filename = $filename; 53 return $this; 54 } 55 56 public function getFilename() { 57 return $this->filename; 58 } 59 60 public function setTitle($title) { 61 $this->title = $title; 62 return $this; 63 } 64 65 public function getTitle() { 66 return $this->title; 67 } 68 69 public function newBulkJob(AphrontRequest $request) { 70 $viewer = $this->getViewer(); 71 $engine = $this->getSearchEngine(); 72 $saved_query = $this->getSavedQuery(); 73 $format = $this->getExportFormat(); 74 75 $params = array( 76 'engineClass' => get_class($engine), 77 'queryKey' => $saved_query->getQueryKey(), 78 'formatKey' => $format->getExportFormatKey(), 79 'title' => $this->getTitle(), 80 'filename' => $this->getFilename(), 81 ); 82 83 $job = PhabricatorWorkerBulkJob::initializeNewJob( 84 $viewer, 85 new PhabricatorExportEngineBulkJobType(), 86 $params); 87 88 // We queue these jobs directly into STATUS_WAITING without requiring 89 // a confirmation from the user. 90 91 $xactions = array(); 92 93 $xactions[] = id(new PhabricatorWorkerBulkJobTransaction()) 94 ->setTransactionType(PhabricatorWorkerBulkJobTransaction::TYPE_STATUS) 95 ->setNewValue(PhabricatorWorkerBulkJob::STATUS_WAITING); 96 97 $editor = id(new PhabricatorWorkerBulkJobEditor()) 98 ->setActor($viewer) 99 ->setContentSourceFromRequest($request) 100 ->setContinueOnMissingFields(true) 101 ->applyTransactions($job, $xactions); 102 103 return $job; 104 } 105 106 public function exportFile() { 107 $viewer = $this->getViewer(); 108 $engine = $this->getSearchEngine(); 109 $saved_query = $this->getSavedQuery(); 110 $format = $this->getExportFormat(); 111 $title = $this->getTitle(); 112 $filename = $this->getFilename(); 113 114 $query = $engine->buildQueryFromSavedQuery($saved_query); 115 116 $extension = $format->getFileExtension(); 117 $mime_type = $format->getMIMEContentType(); 118 $filename = $filename.'.'.$extension; 119 120 $format = id(clone $format) 121 ->setViewer($viewer) 122 ->setTitle($title); 123 124 $field_list = $engine->newExportFieldList(); 125 $field_list = mpull($field_list, null, 'getKey'); 126 $format->addHeaders($field_list); 127 128 // Iterate over the query results in large pages so we don't have to hold 129 // too much stuff in memory. 130 $page_size = 1000; 131 $page_cursor = null; 132 do { 133 $pager = $engine->newPagerForSavedQuery($saved_query); 134 $pager->setPageSize($page_size); 135 136 if ($page_cursor !== null) { 137 $pager->setAfterID($page_cursor); 138 } 139 140 $objects = $engine->executeQuery($query, $pager); 141 $objects = array_values($objects); 142 $page_cursor = $pager->getNextPageID(); 143 144 $export_data = $engine->newExport($objects); 145 for ($ii = 0; $ii < count($objects); $ii++) { 146 $format->addObject($objects[$ii], $field_list, $export_data[$ii]); 147 } 148 } while ($pager->getHasMoreResults()); 149 150 $export_result = $format->newFileData(); 151 152 // We have all the data in one big string and aren't actually 153 // streaming it, but pretending that we are allows us to actviate 154 // the chunk engine and store large files. 155 $iterator = new ArrayIterator(array($export_result)); 156 157 $source = id(new PhabricatorIteratorFileUploadSource()) 158 ->setName($filename) 159 ->setViewPolicy(PhabricatorPolicies::POLICY_NOONE) 160 ->setMIMEType($mime_type) 161 ->setRelativeTTL(phutil_units('60 minutes in seconds')) 162 ->setAuthorPHID($viewer->getPHID()) 163 ->setIterator($iterator); 164 165 return $source->uploadFile(); 166 } 167 168}