Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401]
1 <?php 2 3 namespace Box\Spout\Writer; 4 5 use Box\Spout\Common\Creator\HelperFactory; 6 use Box\Spout\Common\Entity\Row; 7 use Box\Spout\Common\Entity\Style\Style; 8 use Box\Spout\Common\Exception\InvalidArgumentException; 9 use Box\Spout\Common\Exception\IOException; 10 use Box\Spout\Common\Exception\SpoutException; 11 use Box\Spout\Common\Helper\GlobalFunctionsHelper; 12 use Box\Spout\Common\Manager\OptionsManagerInterface; 13 use Box\Spout\Writer\Common\Entity\Options; 14 use Box\Spout\Writer\Exception\WriterAlreadyOpenedException; 15 use Box\Spout\Writer\Exception\WriterNotOpenedException; 16 17 /** 18 * Class WriterAbstract 19 * 20 * @abstract 21 */ 22 abstract class WriterAbstract implements WriterInterface 23 { 24 /** @var string Path to the output file */ 25 protected $outputFilePath; 26 27 /** @var resource Pointer to the file/stream we will write to */ 28 protected $filePointer; 29 30 /** @var bool Indicates whether the writer has been opened or not */ 31 protected $isWriterOpened = false; 32 33 /** @var GlobalFunctionsHelper Helper to work with global functions */ 34 protected $globalFunctionsHelper; 35 36 /** @var HelperFactory $helperFactory */ 37 protected $helperFactory; 38 39 /** @var OptionsManagerInterface Writer options manager */ 40 protected $optionsManager; 41 42 /** @var string Content-Type value for the header - to be defined by child class */ 43 protected static $headerContentType; 44 45 /** 46 * @param OptionsManagerInterface $optionsManager 47 * @param GlobalFunctionsHelper $globalFunctionsHelper 48 * @param HelperFactory $helperFactory 49 */ 50 public function __construct( 51 OptionsManagerInterface $optionsManager, 52 GlobalFunctionsHelper $globalFunctionsHelper, 53 HelperFactory $helperFactory 54 ) { 55 $this->optionsManager = $optionsManager; 56 $this->globalFunctionsHelper = $globalFunctionsHelper; 57 $this->helperFactory = $helperFactory; 58 } 59 60 /** 61 * Opens the streamer and makes it ready to accept data. 62 * 63 * @throws IOException If the writer cannot be opened 64 * @return void 65 */ 66 abstract protected function openWriter(); 67 68 /** 69 * Adds a row to the currently opened writer. 70 * 71 * @param Row $row The row containing cells and styles 72 * @throws WriterNotOpenedException If the workbook is not created yet 73 * @throws IOException If unable to write data 74 * @return void 75 */ 76 abstract protected function addRowToWriter(Row $row); 77 78 /** 79 * Closes the streamer, preventing any additional writing. 80 * 81 * @return void 82 */ 83 abstract protected function closeWriter(); 84 85 /** 86 * {@inheritdoc} 87 */ 88 public function setDefaultRowStyle(Style $defaultStyle) 89 { 90 $this->optionsManager->setOption(Options::DEFAULT_ROW_STYLE, $defaultStyle); 91 92 return $this; 93 } 94 95 /** 96 * {@inheritdoc} 97 */ 98 public function openToFile($outputFilePath) 99 { 100 $this->outputFilePath = $outputFilePath; 101 102 $this->filePointer = $this->globalFunctionsHelper->fopen($this->outputFilePath, 'wb+'); 103 $this->throwIfFilePointerIsNotAvailable(); 104 105 $this->openWriter(); 106 $this->isWriterOpened = true; 107 108 return $this; 109 } 110 111 /** 112 * @codeCoverageIgnore 113 * {@inheritdoc} 114 */ 115 public function openToBrowser($outputFileName) 116 { 117 $this->outputFilePath = $this->globalFunctionsHelper->basename($outputFileName); 118 119 $this->filePointer = $this->globalFunctionsHelper->fopen('php://output', 'w'); 120 $this->throwIfFilePointerIsNotAvailable(); 121 122 // Clear any previous output (otherwise the generated file will be corrupted) 123 // @see https://github.com/box/spout/issues/241 124 $this->globalFunctionsHelper->ob_end_clean(); 125 126 // Set headers 127 $this->globalFunctionsHelper->header('Content-Type: ' . static::$headerContentType); 128 $this->globalFunctionsHelper->header('Content-Disposition: attachment; filename="' . $this->outputFilePath . '"'); 129 130 /* 131 * When forcing the download of a file over SSL,IE8 and lower browsers fail 132 * if the Cache-Control and Pragma headers are not set. 133 * 134 * @see http://support.microsoft.com/KB/323308 135 * @see https://github.com/liuggio/ExcelBundle/issues/45 136 */ 137 $this->globalFunctionsHelper->header('Cache-Control: max-age=0'); 138 $this->globalFunctionsHelper->header('Pragma: public'); 139 140 $this->openWriter(); 141 $this->isWriterOpened = true; 142 143 return $this; 144 } 145 146 /** 147 * Checks if the pointer to the file/stream to write to is available. 148 * Will throw an exception if not available. 149 * 150 * @throws IOException If the pointer is not available 151 * @return void 152 */ 153 protected function throwIfFilePointerIsNotAvailable() 154 { 155 if (!$this->filePointer) { 156 throw new IOException('File pointer has not be opened'); 157 } 158 } 159 160 /** 161 * Checks if the writer has already been opened, since some actions must be done before it gets opened. 162 * Throws an exception if already opened. 163 * 164 * @param string $message Error message 165 * @throws WriterAlreadyOpenedException If the writer was already opened and must not be. 166 * @return void 167 */ 168 protected function throwIfWriterAlreadyOpened($message) 169 { 170 if ($this->isWriterOpened) { 171 throw new WriterAlreadyOpenedException($message); 172 } 173 } 174 175 /** 176 * {@inheritdoc} 177 */ 178 public function addRow(Row $row) 179 { 180 if ($this->isWriterOpened) { 181 try { 182 $this->addRowToWriter($row); 183 } catch (SpoutException $e) { 184 // if an exception occurs while writing data, 185 // close the writer and remove all files created so far. 186 $this->closeAndAttemptToCleanupAllFiles(); 187 188 // re-throw the exception to alert developers of the error 189 throw $e; 190 } 191 } else { 192 throw new WriterNotOpenedException('The writer needs to be opened before adding row.'); 193 } 194 195 return $this; 196 } 197 198 /** 199 * {@inheritdoc} 200 */ 201 public function addRows(array $rows) 202 { 203 foreach ($rows as $row) { 204 if (!$row instanceof Row) { 205 $this->closeAndAttemptToCleanupAllFiles(); 206 throw new InvalidArgumentException('The input should be an array of Row'); 207 } 208 209 $this->addRow($row); 210 } 211 212 return $this; 213 } 214 215 /** 216 * {@inheritdoc} 217 */ 218 public function close() 219 { 220 if (!$this->isWriterOpened) { 221 return; 222 } 223 224 $this->closeWriter(); 225 226 if (is_resource($this->filePointer)) { 227 $this->globalFunctionsHelper->fclose($this->filePointer); 228 } 229 230 $this->isWriterOpened = false; 231 } 232 233 /** 234 * Closes the writer and attempts to cleanup all files that were 235 * created during the writing process (temp files & final file). 236 * 237 * @return void 238 */ 239 private function closeAndAttemptToCleanupAllFiles() 240 { 241 // close the writer, which should remove all temp files 242 $this->close(); 243 244 // remove output file if it was created 245 if ($this->globalFunctionsHelper->file_exists($this->outputFilePath)) { 246 $outputFolderPath = dirname($this->outputFilePath); 247 $fileSystemHelper = $this->helperFactory->createFileSystemHelper($outputFolderPath); 248 $fileSystemHelper->deleteFile($this->outputFilePath); 249 } 250 } 251 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body