From cfea79f03a4e2cd1e95361cd2cb7c71e10d25749 Mon Sep 17 00:00:00 2001 From: Adrien Loison Date: Mon, 29 May 2017 21:34:33 +0200 Subject: [PATCH] Refactor writers for better DI This commit is a big refactor that improves the code organization. It focuses on how dependencies are injected into the different classes. This is now done via some factories. Also, the code is now built around entities (data model that only exposes getters and setters), managers (used to manage an entity) and helpers (used by the managers to perform some specific tasks). The refactoring is not fully complete, as some dependencies are still hidden... --- src/Spout/Common/Helper/FileSystemHelper.php | 2 +- .../Helper/FileSystemHelperInterface.php | 53 +++ .../Writer/AbstractMultiSheetsWriter.php | 117 ------- src/Spout/Writer/CSV/Writer.php | 4 +- ...ileSystemWithRootFolderHelperInterface.php | 28 ++ ...tyleHelper.php => StyleHelperAbstract.php} | 4 +- .../Common/Helper/StyleHelperInterface.php | 30 ++ .../Common/Internal/AbstractWorkbook.php | 193 ----------- .../Common/Internal/WorkbookInterface.php | 74 ---- .../Common/Internal/WorksheetInterface.php | 40 --- src/Spout/Writer/Entity/Workbook.php | 50 +++ src/Spout/Writer/Entity/Worksheet.php | 117 +++++++ src/Spout/Writer/Factory/EntityFactory.php | 34 ++ .../Factory/InternalFactoryInterface.php | 20 ++ .../Manager/WorkbookManagerAbstract.php | 316 ++++++++++++++++++ .../Manager/WorkbookManagerInterface.php | 80 +++++ .../Manager/WorksheetManagerInterface.php | 45 +++ .../Writer/ODS/Factory/InternalFactory.php | 101 ++++++ .../Writer/ODS/Helper/FileSystemHelper.php | 13 +- src/Spout/Writer/ODS/Helper/StyleHelper.php | 4 +- src/Spout/Writer/ODS/Internal/Workbook.php | 121 ------- .../Writer/ODS/Manager/WorkbookManager.php | 71 ++++ .../WorksheetManager.php} | 151 ++++----- src/Spout/Writer/ODS/Writer.php | 59 +--- ...{AbstractWriter.php => WriterAbstract.php} | 22 +- src/Spout/Writer/WriterFactory.php | 7 +- .../Writer/WriterMultiSheetsAbstract.php | 177 ++++++++++ .../Writer/XLSX/Factory/InternalFactory.php | 123 +++++++ .../Writer/XLSX/Helper/FileSystemHelper.php | 35 +- src/Spout/Writer/XLSX/Helper/StyleHelper.php | 4 +- src/Spout/Writer/XLSX/Internal/Workbook.php | 135 -------- .../Writer/XLSX/Manager/WorkbookManager.php | 78 +++++ .../WorksheetManager.php} | 174 +++++----- src/Spout/Writer/XLSX/Writer.php | 61 +--- tests/Spout/Writer/ODS/SheetTest.php | 2 + tests/Spout/Writer/ODS/WriterTest.php | 7 +- tests/Spout/Writer/XLSX/WriterTest.php | 8 +- 37 files changed, 1529 insertions(+), 1031 deletions(-) create mode 100644 src/Spout/Common/Helper/FileSystemHelperInterface.php delete mode 100644 src/Spout/Writer/AbstractMultiSheetsWriter.php create mode 100644 src/Spout/Writer/Common/Helper/FileSystemWithRootFolderHelperInterface.php rename src/Spout/Writer/Common/Helper/{AbstractStyleHelper.php => StyleHelperAbstract.php} (97%) create mode 100644 src/Spout/Writer/Common/Helper/StyleHelperInterface.php delete mode 100644 src/Spout/Writer/Common/Internal/AbstractWorkbook.php delete mode 100644 src/Spout/Writer/Common/Internal/WorkbookInterface.php delete mode 100644 src/Spout/Writer/Common/Internal/WorksheetInterface.php create mode 100644 src/Spout/Writer/Entity/Workbook.php create mode 100644 src/Spout/Writer/Entity/Worksheet.php create mode 100644 src/Spout/Writer/Factory/EntityFactory.php create mode 100644 src/Spout/Writer/Factory/InternalFactoryInterface.php create mode 100644 src/Spout/Writer/Manager/WorkbookManagerAbstract.php create mode 100644 src/Spout/Writer/Manager/WorkbookManagerInterface.php create mode 100644 src/Spout/Writer/Manager/WorksheetManagerInterface.php create mode 100644 src/Spout/Writer/ODS/Factory/InternalFactory.php delete mode 100644 src/Spout/Writer/ODS/Internal/Workbook.php create mode 100644 src/Spout/Writer/ODS/Manager/WorkbookManager.php rename src/Spout/Writer/ODS/{Internal/Worksheet.php => Manager/WorksheetManager.php} (52%) rename src/Spout/Writer/{AbstractWriter.php => WriterAbstract.php} (97%) create mode 100644 src/Spout/Writer/WriterMultiSheetsAbstract.php create mode 100644 src/Spout/Writer/XLSX/Factory/InternalFactory.php delete mode 100644 src/Spout/Writer/XLSX/Internal/Workbook.php create mode 100644 src/Spout/Writer/XLSX/Manager/WorkbookManager.php rename src/Spout/Writer/XLSX/{Internal/Worksheet.php => Manager/WorksheetManager.php} (59%) diff --git a/src/Spout/Common/Helper/FileSystemHelper.php b/src/Spout/Common/Helper/FileSystemHelper.php index 3145be7..11428ab 100644 --- a/src/Spout/Common/Helper/FileSystemHelper.php +++ b/src/Spout/Common/Helper/FileSystemHelper.php @@ -11,7 +11,7 @@ use Box\Spout\Common\Exception\IOException; * * @package Box\Spout\Common\Helper */ -class FileSystemHelper +class FileSystemHelper implements FileSystemHelperInterface { /** @var string Real path of the base folder where all the I/O can occur */ protected $baseFolderRealPath; diff --git a/src/Spout/Common/Helper/FileSystemHelperInterface.php b/src/Spout/Common/Helper/FileSystemHelperInterface.php new file mode 100644 index 0000000..7036a05 --- /dev/null +++ b/src/Spout/Common/Helper/FileSystemHelperInterface.php @@ -0,0 +1,53 @@ +throwIfWriterAlreadyOpened('Writer must be configured before opening it.'); - - $this->optionsManager->setOption(Options::SHOULD_CREATE_NEW_SHEETS_AUTOMATICALLY, $shouldCreateNewSheetsAutomatically); - return $this; - } - - /** - * Returns all the workbook's sheets - * - * @api - * @return Common\Sheet[] All the workbook's sheets - * @throws \Box\Spout\Writer\Exception\WriterNotOpenedException If the writer has not been opened yet - */ - public function getSheets() - { - $this->throwIfBookIsNotAvailable(); - - $externalSheets = []; - $worksheets = $this->getWorkbook()->getWorksheets(); - - /** @var Common\Internal\WorksheetInterface $worksheet */ - foreach ($worksheets as $worksheet) { - $externalSheets[] = $worksheet->getExternalSheet(); - } - - return $externalSheets; - } - - /** - * Creates a new sheet and make it the current sheet. The data will now be written to this sheet. - * - * @api - * @return Common\Sheet The created sheet - * @throws \Box\Spout\Writer\Exception\WriterNotOpenedException If the writer has not been opened yet - */ - public function addNewSheetAndMakeItCurrent() - { - $this->throwIfBookIsNotAvailable(); - $worksheet = $this->getWorkbook()->addNewSheetAndMakeItCurrent(); - - return $worksheet->getExternalSheet(); - } - - /** - * Returns the current sheet - * - * @api - * @return Common\Sheet The current sheet - * @throws \Box\Spout\Writer\Exception\WriterNotOpenedException If the writer has not been opened yet - */ - public function getCurrentSheet() - { - $this->throwIfBookIsNotAvailable(); - return $this->getWorkbook()->getCurrentWorksheet()->getExternalSheet(); - } - - /** - * Sets the given sheet as the current one. New data will be written to this sheet. - * The writing will resume where it stopped (i.e. data won't be truncated). - * - * @api - * @param Common\Sheet $sheet The sheet to set as current - * @return void - * @throws \Box\Spout\Writer\Exception\WriterNotOpenedException If the writer has not been opened yet - * @throws \Box\Spout\Writer\Exception\SheetNotFoundException If the given sheet does not exist in the workbook - */ - public function setCurrentSheet($sheet) - { - $this->throwIfBookIsNotAvailable(); - $this->getWorkbook()->setCurrentSheet($sheet); - } - - /** - * Checks if the book has been created. Throws an exception if not created yet. - * - * @return void - * @throws \Box\Spout\Writer\Exception\WriterNotOpenedException If the book is not created yet - */ - protected function throwIfBookIsNotAvailable() - { - if (!$this->getWorkbook()) { - throw new WriterNotOpenedException('The writer must be opened before performing this action.'); - } - } -} - diff --git a/src/Spout/Writer/CSV/Writer.php b/src/Spout/Writer/CSV/Writer.php index 1c8b7a0..d94aa05 100644 --- a/src/Spout/Writer/CSV/Writer.php +++ b/src/Spout/Writer/CSV/Writer.php @@ -2,7 +2,7 @@ namespace Box\Spout\Writer\CSV; -use Box\Spout\Writer\AbstractWriter; +use Box\Spout\Writer\WriterAbstract; use Box\Spout\Common\Exception\IOException; use Box\Spout\Common\Helper\EncodingHelper; use Box\Spout\Writer\Common\Options; @@ -13,7 +13,7 @@ use Box\Spout\Writer\Common\Options; * * @package Box\Spout\Writer\CSV */ -class Writer extends AbstractWriter +class Writer extends WriterAbstract { /** Number of rows to write before flushing */ const FLUSH_THRESHOLD = 500; diff --git a/src/Spout/Writer/Common/Helper/FileSystemWithRootFolderHelperInterface.php b/src/Spout/Writer/Common/Helper/FileSystemWithRootFolderHelperInterface.php new file mode 100644 index 0000000..8e7a7a5 --- /dev/null +++ b/src/Spout/Writer/Common/Helper/FileSystemWithRootFolderHelperInterface.php @@ -0,0 +1,28 @@ + [STYLE_ID] mapping table, keeping track of the registered styles */ protected $serializedStyleToStyleIdMappingTable = []; diff --git a/src/Spout/Writer/Common/Helper/StyleHelperInterface.php b/src/Spout/Writer/Common/Helper/StyleHelperInterface.php new file mode 100644 index 0000000..a73d1cb --- /dev/null +++ b/src/Spout/Writer/Common/Helper/StyleHelperInterface.php @@ -0,0 +1,30 @@ +optionManager = $optionsManager; - $this->internalId = uniqid(); - } - - /** - * @return \Box\Spout\Writer\Common\Helper\AbstractStyleHelper The specific style helper - */ - abstract protected function getStyleHelper(); - - /** - * @return int Maximum number of rows/columns a sheet can contain - */ - abstract protected function getMaxRowsPerWorksheet(); - - /** - * Creates a new sheet in the workbook. The current sheet remains unchanged. - * - * @return WorksheetInterface The created sheet - * @throws \Box\Spout\Common\Exception\IOException If unable to open the sheet for writing - */ - abstract public function addNewSheet(); - - /** - * Creates a new sheet in the workbook and make it the current sheet. - * The writing will resume where it stopped (i.e. data won't be truncated). - * - * @return WorksheetInterface The created sheet - * @throws \Box\Spout\Common\Exception\IOException If unable to open the sheet for writing - */ - public function addNewSheetAndMakeItCurrent() - { - $worksheet = $this->addNewSheet(); - $this->setCurrentWorksheet($worksheet); - - return $worksheet; - } - - /** - * @return WorksheetInterface[] All the workbook's sheets - */ - public function getWorksheets() - { - return $this->worksheets; - } - - /** - * Returns the current sheet - * - * @return WorksheetInterface The current sheet - */ - public function getCurrentWorksheet() - { - return $this->currentWorksheet; - } - - /** - * Sets the given sheet as the current one. New data will be written to this sheet. - * The writing will resume where it stopped (i.e. data won't be truncated). - * - * @param \Box\Spout\Writer\Common\Sheet $sheet The "external" sheet to set as current - * @return void - * @throws \Box\Spout\Writer\Exception\SheetNotFoundException If the given sheet does not exist in the workbook - */ - public function setCurrentSheet($sheet) - { - $worksheet = $this->getWorksheetFromExternalSheet($sheet); - if ($worksheet !== null) { - $this->currentWorksheet = $worksheet; - } else { - throw new SheetNotFoundException('The given sheet does not exist in the workbook.'); - } - } - - /** - * @param WorksheetInterface $worksheet - * @return void - */ - protected function setCurrentWorksheet($worksheet) - { - $this->currentWorksheet = $worksheet; - } - - /** - * Returns the worksheet associated to the given external sheet. - * - * @param \Box\Spout\Writer\Common\Sheet $sheet - * @return WorksheetInterface|null The worksheet associated to the given external sheet or null if not found. - */ - protected function getWorksheetFromExternalSheet($sheet) - { - $worksheetFound = null; - - foreach ($this->worksheets as $worksheet) { - if ($worksheet->getExternalSheet() === $sheet) { - $worksheetFound = $worksheet; - break; - } - } - - return $worksheetFound; - } - - /** - * Adds data to the current sheet. - * If shouldCreateNewSheetsAutomatically option is set to true, it will handle pagination - * with the creation of new worksheets if one worksheet has reached its maximum capicity. - * - * @param array $dataRow Array containing data to be written. Cannot be empty. - * Example $dataRow = ['data1', 1234, null, '', 'data5']; - * @param \Box\Spout\Writer\Style\Style $style Style to be applied to the row. - * @return void - * @throws \Box\Spout\Common\Exception\IOException If trying to create a new sheet and unable to open the sheet for writing - * @throws \Box\Spout\Writer\Exception\WriterException If unable to write data - */ - public function addRowToCurrentWorksheet($dataRow, $style) - { - $currentWorksheet = $this->getCurrentWorksheet(); - $hasReachedMaxRows = $this->hasCurrentWorkseetReachedMaxRows(); - $styleHelper = $this->getStyleHelper(); - - // if we reached the maximum number of rows for the current sheet... - if ($hasReachedMaxRows) { - // ... continue writing in a new sheet if option set - if ($this->optionManager->getOption(Options::SHOULD_CREATE_NEW_SHEETS_AUTOMATICALLY)) { - $currentWorksheet = $this->addNewSheetAndMakeItCurrent(); - - $updatedStyle = $styleHelper->applyExtraStylesIfNeeded($style, $dataRow); - $registeredStyle = $styleHelper->registerStyle($updatedStyle); - $currentWorksheet->addRow($dataRow, $registeredStyle); - } else { - // otherwise, do nothing as the data won't be read anyways - } - } else { - $updatedStyle = $styleHelper->applyExtraStylesIfNeeded($style, $dataRow); - $registeredStyle = $styleHelper->registerStyle($updatedStyle); - $currentWorksheet->addRow($dataRow, $registeredStyle); - } - } - - /** - * @return bool Whether the current worksheet has reached the maximum number of rows per sheet. - */ - protected function hasCurrentWorkseetReachedMaxRows() - { - $currentWorksheet = $this->getCurrentWorksheet(); - return ($currentWorksheet->getLastWrittenRowIndex() >= $this->getMaxRowsPerWorksheet()); - } - - /** - * Closes the workbook and all its associated sheets. - * All the necessary files are written to disk and zipped together to create the ODS file. - * All the temporary files are then deleted. - * - * @param resource $finalFilePointer Pointer to the ODS that will be created - * @return void - */ - abstract public function close($finalFilePointer); -} diff --git a/src/Spout/Writer/Common/Internal/WorkbookInterface.php b/src/Spout/Writer/Common/Internal/WorkbookInterface.php deleted file mode 100644 index fda0793..0000000 --- a/src/Spout/Writer/Common/Internal/WorkbookInterface.php +++ /dev/null @@ -1,74 +0,0 @@ -internalId = uniqid(); + } + + /** + * @return Worksheet[] + */ + public function getWorksheets() + { + return $this->worksheets; + } + + /** + * @param Worksheet[] $worksheets + */ + public function setWorksheets($worksheets) + { + $this->worksheets = $worksheets; + } + + /** + * @return string + */ + public function getInternalId() + { + return $this->internalId; + } +} \ No newline at end of file diff --git a/src/Spout/Writer/Entity/Worksheet.php b/src/Spout/Writer/Entity/Worksheet.php new file mode 100644 index 0000000..58de5a5 --- /dev/null +++ b/src/Spout/Writer/Entity/Worksheet.php @@ -0,0 +1,117 @@ +filePath = $worksheetFilePath; + $this->filePointer = null; + $this->externalSheet = $externalSheet; + $this->maxNumColumns = 0; + $this->lastWrittenRowIndex = 0; + } + + /** + * @return string + */ + public function getFilePath() + { + return $this->filePath; + } + + /** + * @return Resource + */ + public function getFilePointer() + { + return $this->filePointer; + } + + /** + * @param Resource $filePointer + */ + public function setFilePointer($filePointer) + { + $this->filePointer = $filePointer; + } + + /** + * @return Sheet + */ + public function getExternalSheet() + { + return $this->externalSheet; + } + + /** + * @return int + */ + public function getMaxNumColumns() + { + return $this->maxNumColumns; + } + + /** + * @param int $maxNumColumns + */ + public function setMaxNumColumns($maxNumColumns) + { + $this->maxNumColumns = $maxNumColumns; + } + + /** + * @return int + */ + public function getLastWrittenRowIndex() + { + return $this->lastWrittenRowIndex; + } + + /** + * @param int $lastWrittenRowIndex + */ + public function setLastWrittenRowIndex($lastWrittenRowIndex) + { + $this->lastWrittenRowIndex = $lastWrittenRowIndex; + } + + /** + * @return int The ID of the worksheet + */ + public function getId() + { + // sheet index is zero-based, while ID is 1-based + return $this->externalSheet->getIndex() + 1; + } +} \ No newline at end of file diff --git a/src/Spout/Writer/Factory/EntityFactory.php b/src/Spout/Writer/Factory/EntityFactory.php new file mode 100644 index 0000000..8ecbcd0 --- /dev/null +++ b/src/Spout/Writer/Factory/EntityFactory.php @@ -0,0 +1,34 @@ +workbook = $workbook; + $this->optionManager = $optionsManager; + $this->worksheetManager = $worksheetManager; + $this->styleHelper = $styleHelper; + $this->fileSystemHelper = $fileSystemHelper; + $this->entityFactory = $entityFactory; + } + + /** + * @return int Maximum number of rows/columns a sheet can contain + */ + abstract protected function getMaxRowsPerWorksheet(); + + /** + * @param Sheet $sheet + * @return string The file path where the data for the given sheet will be stored + */ + abstract protected function getWorksheetFilePath(Sheet $sheet); + + /** + * @return Workbook + */ + public function getWorkbook() + { + return $this->workbook; + } + + /** + * Creates a new sheet in the workbook and make it the current sheet. + * The writing will resume where it stopped (i.e. data won't be truncated). + * + * @return Worksheet The created sheet + * @throws IOException If unable to open the sheet for writing + */ + public function addNewSheetAndMakeItCurrent() + { + $worksheet = $this->addNewSheet(); + $this->setCurrentWorksheet($worksheet); + + return $worksheet; + } + + /** + * Creates a new sheet in the workbook. The current sheet remains unchanged. + * + * @return Worksheet The created sheet + * @throws \Box\Spout\Common\Exception\IOException If unable to open the sheet for writing + */ + private function addNewSheet() + { + $worksheets = $this->getWorksheets(); + + $newSheetIndex = count($worksheets); + $sheet = new Sheet($newSheetIndex, $this->workbook->getInternalId()); + + $worksheetFilePath = $this->getWorksheetFilePath($sheet); + $worksheet = $this->entityFactory->createWorksheet($worksheetFilePath, $sheet); + + $this->worksheetManager->startSheet($worksheet); + + $worksheets[] = $worksheet; + $this->workbook->setWorksheets($worksheets); + + return $worksheet; + } + + /** + * @return Worksheet[] All the workbook's sheets + */ + public function getWorksheets() + { + return $this->workbook->getWorksheets(); + } + + /** + * Returns the current sheet + * + * @return Worksheet The current sheet + */ + public function getCurrentWorksheet() + { + return $this->currentWorksheet; + } + + /** + * Sets the given sheet as the current one. New data will be written to this sheet. + * The writing will resume where it stopped (i.e. data won't be truncated). + * + * @param Sheet $sheet The "external" sheet to set as current + * @return void + * @throws SheetNotFoundException If the given sheet does not exist in the workbook + */ + public function setCurrentSheet(Sheet $sheet) + { + $worksheet = $this->getWorksheetFromExternalSheet($sheet); + if ($worksheet !== null) { + $this->currentWorksheet = $worksheet; + } else { + throw new SheetNotFoundException('The given sheet does not exist in the workbook.'); + } + } + + /** + * @param Worksheet $worksheet + * @return void + */ + private function setCurrentWorksheet($worksheet) + { + $this->currentWorksheet = $worksheet; + } + + /** + * Returns the worksheet associated to the given external sheet. + * + * @param Sheet $sheet + * @return Worksheet|null The worksheet associated to the given external sheet or null if not found. + */ + private function getWorksheetFromExternalSheet($sheet) + { + $worksheetFound = null; + + foreach ($this->getWorksheets() as $worksheet) { + if ($worksheet->getExternalSheet() === $sheet) { + $worksheetFound = $worksheet; + break; + } + } + + return $worksheetFound; + } + + /** + * Adds data to the current sheet. + * If shouldCreateNewSheetsAutomatically option is set to true, it will handle pagination + * with the creation of new worksheets if one worksheet has reached its maximum capicity. + * + * @param array $dataRow Array containing data to be written. Cannot be empty. + * Example $dataRow = ['data1', 1234, null, '', 'data5']; + * @param Style $style Style to be applied to the row. + * @return void + * @throws IOException If trying to create a new sheet and unable to open the sheet for writing + * @throws WriterException If unable to write data + */ + public function addRowToCurrentWorksheet($dataRow, Style $style) + { + $currentWorksheet = $this->getCurrentWorksheet(); + $hasReachedMaxRows = $this->hasCurrentWorkseetReachedMaxRows(); + + // if we reached the maximum number of rows for the current sheet... + if ($hasReachedMaxRows) { + // ... continue writing in a new sheet if option set + if ($this->optionManager->getOption(Options::SHOULD_CREATE_NEW_SHEETS_AUTOMATICALLY)) { + $currentWorksheet = $this->addNewSheetAndMakeItCurrent(); + + $this->addRowWithStyleToWorksheet($currentWorksheet, $dataRow, $style); + } else { + // otherwise, do nothing as the data won't be written anyways + } + } else { + $this->addRowWithStyleToWorksheet($currentWorksheet, $dataRow, $style); + } + } + + /** + * @return bool Whether the current worksheet has reached the maximum number of rows per sheet. + */ + private function hasCurrentWorkseetReachedMaxRows() + { + $currentWorksheet = $this->getCurrentWorksheet(); + return ($currentWorksheet->getLastWrittenRowIndex() >= $this->getMaxRowsPerWorksheet()); + } + + /** + * Adds data with the given style to the given sheet. + * + * @param Worksheet $worksheet Worksheet to write the row to + * @param array $dataRow Array containing data to be written. Cannot be empty. + * Example $dataRow = ['data1', 1234, null, '', 'data5']; + * @param Style $style Style to be applied to the row. + * @return void + * @throws WriterException If unable to write data + */ + private function addRowWithStyleToWorksheet(Worksheet $worksheet, $dataRow, Style $style) + { + $updatedStyle = $this->styleHelper->applyExtraStylesIfNeeded($style, $dataRow); + $registeredStyle = $this->styleHelper->registerStyle($updatedStyle); + $this->worksheetManager->addRow($worksheet, $dataRow, $registeredStyle); + + // update max num columns for the worksheet + $currentMaxNumColumns = $worksheet->getMaxNumColumns(); + $cellsCount = count($dataRow); + $worksheet->setMaxNumColumns(max($currentMaxNumColumns, $cellsCount)); + } + + /** + * Closes the workbook and all its associated sheets. + * All the necessary files are written to disk and zipped together to create the final file. + * All the temporary files are then deleted. + * + * @param resource $finalFilePointer Pointer to the spreadsheet that will be created + * @return void + */ + public function close($finalFilePointer) + { + $this->closeAllWorksheets(); + $this->closeRemainingObjects(); + $this->writeAllFilesToDiskAndZipThem($finalFilePointer); + $this->cleanupTempFolder(); + } + + /** + * Closes custom objects that are still opened + * + * @return void + */ + protected function closeRemainingObjects() + { + // do nothing by default + } + + /** + * Writes all the necessary files to disk and zip them together to create the final file. + * + * @param resource $finalFilePointer Pointer to the spreadsheet that will be created + * @return void + */ + abstract protected function writeAllFilesToDiskAndZipThem($finalFilePointer); + + /** + * Closes all workbook's associated sheets. + * + * @return void + */ + private function closeAllWorksheets() + { + $worksheets = $this->getWorksheets(); + + foreach ($worksheets as $worksheet) { + $this->worksheetManager->close($worksheet); + } + } + + /** + * Deletes the root folder created in the temp folder and all its contents. + * + * @return void + */ + protected function cleanupTempFolder() + { + $rootFolder = $this->fileSystemHelper->getRootFolder(); + $this->fileSystemHelper->deleteFolderRecursively($rootFolder); + } +} \ No newline at end of file diff --git a/src/Spout/Writer/Manager/WorkbookManagerInterface.php b/src/Spout/Writer/Manager/WorkbookManagerInterface.php new file mode 100644 index 0000000..2645991 --- /dev/null +++ b/src/Spout/Writer/Manager/WorkbookManagerInterface.php @@ -0,0 +1,80 @@ +entityFactory = $entityFactory; + } + + /** + * @param OptionsManagerInterface $optionsManager + * @return WorkbookManager + */ + public function createWorkbookManager(OptionsManagerInterface $optionsManager) + { + $workbook = $this->entityFactory->createWorkbook(); + + $fileSystemHelper = $this->createFileSystemHelper($optionsManager); + $fileSystemHelper->createBaseFilesAndFolders(); + + $styleHelper = $this->createStyleHelper($optionsManager); + $worksheetManager = $this->createWorksheetManager($styleHelper); + + return new WorkbookManager($workbook, $optionsManager, $worksheetManager, $styleHelper, $fileSystemHelper, $this->entityFactory); + } + + /** + * @param StyleHelper $styleHelper + * @return WorksheetManager + */ + private function createWorksheetManager(StyleHelper $styleHelper) + { + $stringsEscaper = $this->createStringsEscaper(); + $stringsHelper = $this->createStringHelper(); + + return new WorksheetManager($styleHelper, $stringsEscaper, $stringsHelper); + } + + /** + * @param OptionsManagerInterface $optionsManager + * @return FileSystemHelper + */ + public function createFileSystemHelper(OptionsManagerInterface $optionsManager) + { + $tempFolder = $optionsManager->getOption(Options::TEMP_FOLDER); + return new FileSystemHelper($tempFolder); + } + + /** + * @param OptionsManagerInterface $optionsManager + * @return StyleHelper + */ + private function createStyleHelper(OptionsManagerInterface $optionsManager) + { + $defaultRowStyle = $optionsManager->getOption(Options::DEFAULT_ROW_STYLE); + return new StyleHelper($defaultRowStyle); + } + + /** + * @return Escaper\ODS + */ + private function createStringsEscaper() + { + return Escaper\ODS::getInstance(); + } + + /** + * @return StringHelper + */ + private function createStringHelper() + { + return new StringHelper(); + } +} \ No newline at end of file diff --git a/src/Spout/Writer/ODS/Helper/FileSystemHelper.php b/src/Spout/Writer/ODS/Helper/FileSystemHelper.php index 34ace0a..4603465 100644 --- a/src/Spout/Writer/ODS/Helper/FileSystemHelper.php +++ b/src/Spout/Writer/ODS/Helper/FileSystemHelper.php @@ -2,8 +2,10 @@ namespace Box\Spout\Writer\ODS\Helper; +use Box\Spout\Writer\Common\Helper\FileSystemWithRootFolderHelperInterface; use Box\Spout\Writer\Common\Helper\ZipHelper; -use Box\Spout\Writer\ODS\Internal\Worksheet; +use Box\Spout\Writer\Entity\Worksheet; +use Box\Spout\Writer\ODS\Manager\WorksheetManager; /** * Class FileSystemHelper @@ -12,7 +14,7 @@ use Box\Spout\Writer\ODS\Internal\Worksheet; * * @package Box\Spout\Writer\ODS\Helper */ -class FileSystemHelper extends \Box\Spout\Common\Helper\FileSystemHelper +class FileSystemHelper extends \Box\Spout\Common\Helper\FileSystemHelper implements FileSystemWithRootFolderHelperInterface { const APP_NAME = 'Spout'; const MIMETYPE = 'application/vnd.oasis.opendocument.spreadsheet'; @@ -172,11 +174,12 @@ EOD; /** * Creates the "content.xml" file under the root folder * + * @param WorksheetManager $worksheetManager * @param Worksheet[] $worksheets * @param StyleHelper $styleHelper * @return FileSystemHelper */ - public function createContentFile($worksheets, $styleHelper) + public function createContentFile($worksheetManager, $worksheets, $styleHelper) { $contentXmlFileContents = << @@ -196,9 +199,9 @@ EOD; foreach ($worksheets as $worksheet) { // write the "" node, with the final sheet's name - fwrite($contentXmlHandle, $worksheet->getTableElementStartAsString()); + fwrite($contentXmlHandle, $worksheetManager->getTableElementStartAsString($worksheet)); - $worksheetFilePath = $worksheet->getWorksheetFilePath(); + $worksheetFilePath = $worksheet->getFilePath(); $this->copyFileContentsToTarget($worksheetFilePath, $contentXmlHandle); fwrite($contentXmlHandle, ''); diff --git a/src/Spout/Writer/ODS/Helper/StyleHelper.php b/src/Spout/Writer/ODS/Helper/StyleHelper.php index f5ad3bc..e8a4110 100644 --- a/src/Spout/Writer/ODS/Helper/StyleHelper.php +++ b/src/Spout/Writer/ODS/Helper/StyleHelper.php @@ -2,7 +2,7 @@ namespace Box\Spout\Writer\ODS\Helper; -use Box\Spout\Writer\Common\Helper\AbstractStyleHelper; +use Box\Spout\Writer\Common\Helper\StyleHelperAbstract; use Box\Spout\Writer\Style\BorderPart; /** @@ -11,7 +11,7 @@ use Box\Spout\Writer\Style\BorderPart; * * @package Box\Spout\Writer\ODS\Helper */ -class StyleHelper extends AbstractStyleHelper +class StyleHelper extends StyleHelperAbstract { /** @var string[] [FONT_NAME] => [] Map whose keys contain all the fonts used */ protected $usedFontsSet = []; diff --git a/src/Spout/Writer/ODS/Internal/Workbook.php b/src/Spout/Writer/ODS/Internal/Workbook.php deleted file mode 100644 index 70bc94f..0000000 --- a/src/Spout/Writer/ODS/Internal/Workbook.php +++ /dev/null @@ -1,121 +0,0 @@ -getOption(Options::TEMP_FOLDER); - $this->fileSystemHelper = new FileSystemHelper($tempFolder); - $this->fileSystemHelper->createBaseFilesAndFolders(); - - $defaultRowStyle = $optionsManager->getOption(Options::DEFAULT_ROW_STYLE); - $this->styleHelper = new StyleHelper($defaultRowStyle); - } - - /** - * @return \Box\Spout\Writer\ODS\Helper\StyleHelper Helper to apply styles to ODS files - */ - protected function getStyleHelper() - { - return $this->styleHelper; - } - - /** - * @return int Maximum number of rows/columns a sheet can contain - */ - protected function getMaxRowsPerWorksheet() - { - return self::$maxRowsPerWorksheet; - } - - /** - * Creates a new sheet in the workbook. The current sheet remains unchanged. - * - * @return Worksheet The created sheet - * @throws \Box\Spout\Common\Exception\IOException If unable to open the sheet for writing - */ - public function addNewSheet() - { - $newSheetIndex = count($this->worksheets); - $sheet = new Sheet($newSheetIndex, $this->internalId); - - $sheetsContentTempFolder = $this->fileSystemHelper->getSheetsContentTempFolder(); - $worksheet = new Worksheet($sheet, $sheetsContentTempFolder); - $this->worksheets[] = $worksheet; - - return $worksheet; - } - - /** - * Closes the workbook and all its associated sheets. - * All the necessary files are written to disk and zipped together to create the ODS file. - * All the temporary files are then deleted. - * - * @param resource $finalFilePointer Pointer to the ODS that will be created - * @return void - */ - public function close($finalFilePointer) - { - /** @var Worksheet[] $worksheets */ - $worksheets = $this->worksheets; - $numWorksheets = count($worksheets); - - foreach ($worksheets as $worksheet) { - $worksheet->close(); - } - - // Finish creating all the necessary files before zipping everything together - $this->fileSystemHelper - ->createContentFile($worksheets, $this->styleHelper) - ->deleteWorksheetTempFolder() - ->createStylesFile($this->styleHelper, $numWorksheets) - ->zipRootFolderAndCopyToStream($finalFilePointer); - - $this->cleanupTempFolder(); - } - - /** - * Deletes the root folder created in the temp folder and all its contents. - * - * @return void - */ - protected function cleanupTempFolder() - { - $xlsxRootFolder = $this->fileSystemHelper->getRootFolder(); - $this->fileSystemHelper->deleteFolderRecursively($xlsxRootFolder); - } -} diff --git a/src/Spout/Writer/ODS/Manager/WorkbookManager.php b/src/Spout/Writer/ODS/Manager/WorkbookManager.php new file mode 100644 index 0000000..0e0efbd --- /dev/null +++ b/src/Spout/Writer/ODS/Manager/WorkbookManager.php @@ -0,0 +1,71 @@ +fileSystemHelper->getSheetsContentTempFolder(); + return $sheetsContentTempFolder . '/sheet' . $sheet->getIndex() . '.xml'; + } + + /** + * Writes all the necessary files to disk and zip them together to create the final file. + * + * @param resource $finalFilePointer Pointer to the spreadsheet that will be created + * @return void + */ + protected function writeAllFilesToDiskAndZipThem($finalFilePointer) + { + $worksheets = $this->getWorksheets(); + $numWorksheets = count($worksheets); + + $this->fileSystemHelper + ->createContentFile($this->worksheetManager, $worksheets, $this->styleHelper) + ->deleteWorksheetTempFolder() + ->createStylesFile($this->styleHelper, $numWorksheets) + ->zipRootFolderAndCopyToStream($finalFilePointer); + } +} \ No newline at end of file diff --git a/src/Spout/Writer/ODS/Internal/Worksheet.php b/src/Spout/Writer/ODS/Manager/WorksheetManager.php similarity index 52% rename from src/Spout/Writer/ODS/Internal/Worksheet.php rename to src/Spout/Writer/ODS/Manager/WorksheetManager.php index 9c44798..729b23b 100644 --- a/src/Spout/Writer/ODS/Internal/Worksheet.php +++ b/src/Spout/Writer/ODS/Manager/WorksheetManager.php @@ -1,147 +1,116 @@ externalSheet = $externalSheet; - /** @noinspection PhpUnnecessaryFullyQualifiedNameInspection */ - $this->stringsEscaper = \Box\Spout\Common\Escaper\ODS::getInstance(); - $this->worksheetFilePath = $worksheetFilesFolder . '/sheet' . $externalSheet->getIndex() . '.xml'; - - $this->stringHelper = new StringHelper(); - - $this->startSheet(); + $this->styleHelper = $styleHelper; + $this->stringsEscaper = $stringsEscaper; + $this->stringHelper = $stringHelper; } /** * Prepares the worksheet to accept data - * The XML file does not contain the "" node as it contains the sheet's name - * which may change during the execution of the program. It will be added at the end. * + * @param Worksheet $worksheet The worksheet to start * @return void * @throws \Box\Spout\Common\Exception\IOException If the sheet data file cannot be opened for writing */ - protected function startSheet() + public function startSheet(Worksheet $worksheet) { - $this->sheetFilePointer = fopen($this->worksheetFilePath, 'w'); - $this->throwIfSheetFilePointerIsNotAvailable(); + $sheetFilePointer = fopen($worksheet->getFilePath(), 'w'); + $this->throwIfSheetFilePointerIsNotAvailable($sheetFilePointer); + + $worksheet->setFilePointer($sheetFilePointer); } /** - * Checks if the book has been created. Throws an exception if not created yet. + * Checks if the sheet has been sucessfully created. Throws an exception if not. * + * @param bool|resource $sheetFilePointer Pointer to the sheet data file or FALSE if unable to open the file * @return void - * @throws \Box\Spout\Common\Exception\IOException If the sheet data file cannot be opened for writing + * @throws IOException If the sheet data file cannot be opened for writing */ - protected function throwIfSheetFilePointerIsNotAvailable() + private function throwIfSheetFilePointerIsNotAvailable($sheetFilePointer) { - if (!$this->sheetFilePointer) { + if (!$sheetFilePointer) { throw new IOException('Unable to open sheet for writing.'); } } - /** - * @return string Path to the temporary sheet content XML file - */ - public function getWorksheetFilePath() - { - return $this->worksheetFilePath; - } - /** * Returns the table XML root node as string. * + * @param Worksheet $worksheet * @return string node as string */ - public function getTableElementStartAsString() + public function getTableElementStartAsString(Worksheet $worksheet) { - $escapedSheetName = $this->stringsEscaper->escape($this->externalSheet->getName()); - $tableStyleName = 'ta' . ($this->externalSheet->getIndex() + 1); + $externalSheet = $worksheet->getExternalSheet(); + $escapedSheetName = $this->stringsEscaper->escape($externalSheet->getName()); + $tableStyleName = 'ta' . ($externalSheet->getIndex() + 1); $tableElement = ''; - $tableElement .= ''; + $tableElement .= ''; return $tableElement; } /** - * @return \Box\Spout\Writer\Common\Sheet The "external" sheet - */ - public function getExternalSheet() - { - return $this->externalSheet; - } - - /** - * @return int The index of the last written row - */ - public function getLastWrittenRowIndex() - { - return $this->lastWrittenRowIndex; - } - - /** - * Adds data to the worksheet. + * Adds data to the given worksheet. * + * @param Worksheet $worksheet The worksheet to add the row to * @param array $dataRow Array containing data to be written. Cannot be empty. * Example $dataRow = ['data1', 1234, null, '', 'data5']; - * @param \Box\Spout\Writer\Style\Style $style Style to be applied to the row. NULL means use default style. + * @param Style $rowStyle Style to be applied to the row. NULL means use default style. * @return void - * @throws \Box\Spout\Common\Exception\IOException If the data cannot be written - * @throws \Box\Spout\Common\Exception\InvalidArgumentException If a cell value's type is not supported + * @throws IOException If the data cannot be written + * @throws InvalidArgumentException If a cell value's type is not supported */ - public function addRow($dataRow, $style) + public function addRow(Worksheet $worksheet, $dataRow, $rowStyle) { // $dataRow can be an associative array. We need to transform // it into a regular array, as we'll use the numeric indexes. $dataRowWithNumericIndexes = array_values($dataRow); - $styleIndex = ($style->getId() + 1); // 1-based + $styleIndex = ($rowStyle->getId() + 1); // 1-based $cellsCount = count($dataRow); - $this->maxNumColumns = max($this->maxNumColumns, $cellsCount); $data = ''; @@ -166,13 +135,14 @@ class Worksheet implements WorksheetInterface $data .= ''; - $wasWriteSuccessful = fwrite($this->sheetFilePointer, $data); + $wasWriteSuccessful = fwrite($worksheet->getFilePointer(), $data); if ($wasWriteSuccessful === false) { - throw new IOException("Unable to write data in {$this->worksheetFilePath}"); + throw new IOException("Unable to write data in {$worksheet->getFilePath()}"); } // only update the count if the write worked - $this->lastWrittenRowIndex++; + $lastWrittenRowIndex = $worksheet->getLastWrittenRowIndex(); + $worksheet->setLastWrittenRowIndex($lastWrittenRowIndex + 1); } /** @@ -184,7 +154,7 @@ class Worksheet implements WorksheetInterface * @return string The cell XML content * @throws \Box\Spout\Common\Exception\InvalidArgumentException If a cell value's type is not supported */ - protected function getCellXML($cellValue, $styleIndex, $numTimesValueRepeated) + private function getCellXML($cellValue, $styleIndex, $numTimesValueRepeated) { $data = 'sheetFilePointer)) { + $worksheetFilePointer = $worksheet->getFilePointer(); + + if (!is_resource($worksheetFilePointer)) { return; } - fclose($this->sheetFilePointer); + fclose($worksheetFilePointer); } -} +} \ No newline at end of file diff --git a/src/Spout/Writer/ODS/Writer.php b/src/Spout/Writer/ODS/Writer.php index fa0805e..374f920 100644 --- a/src/Spout/Writer/ODS/Writer.php +++ b/src/Spout/Writer/ODS/Writer.php @@ -2,10 +2,8 @@ namespace Box\Spout\Writer\ODS; -use Box\Spout\Writer\AbstractMultiSheetsWriter; -use Box\Spout\Writer\Common; use Box\Spout\Writer\Common\Options; -use Box\Spout\Writer\ODS\Internal\Workbook; +use Box\Spout\Writer\WriterMultiSheetsAbstract; /** * Class Writer @@ -13,14 +11,11 @@ use Box\Spout\Writer\ODS\Internal\Workbook; * * @package Box\Spout\Writer\ODS */ -class Writer extends AbstractMultiSheetsWriter +class Writer extends WriterMultiSheetsAbstract { /** @var string Content-Type value for the header */ protected static $headerContentType = 'application/vnd.oasis.opendocument.spreadsheet'; - /** @var Internal\Workbook The workbook for the ODS file */ - protected $book; - /** * Sets a custom temporary folder for creating intermediate files/folders. * This must be set before opening the writer. @@ -37,54 +32,4 @@ class Writer extends AbstractMultiSheetsWriter $this->optionsManager->setOption(Options::TEMP_FOLDER, $tempFolder); return $this; } - - /** - * Configures the write and sets the current sheet pointer to a new sheet. - * - * @return void - * @throws \Box\Spout\Common\Exception\IOException If unable to open the file for writing - */ - protected function openWriter() - { - $this->book = new Workbook($this->optionsManager); - $this->book->addNewSheetAndMakeItCurrent(); - } - - /** - * @return Internal\Workbook The workbook representing the file to be written - */ - protected function getWorkbook() - { - return $this->book; - } - - /** - * Adds data to the currently opened writer. - * If shouldCreateNewSheetsAutomatically option is set to true, it will handle pagination - * with the creation of new worksheets if one worksheet has reached its maximum capicity. - * - * @param array $dataRow Array containing data to be written. - * Example $dataRow = ['data1', 1234, null, '', 'data5']; - * @param \Box\Spout\Writer\Style\Style $style Style to be applied to the row. - * @return void - * @throws \Box\Spout\Writer\Exception\WriterNotOpenedException If the book is not created yet - * @throws \Box\Spout\Common\Exception\IOException If unable to write data - */ - protected function addRowToWriter(array $dataRow, $style) - { - $this->throwIfBookIsNotAvailable(); - $this->book->addRowToCurrentWorksheet($dataRow, $style); - } - - /** - * Closes the writer, preventing any additional writing. - * - * @return void - */ - protected function closeWriter() - { - if ($this->book) { - $this->book->close($this->filePointer); - } - } } diff --git a/src/Spout/Writer/AbstractWriter.php b/src/Spout/Writer/WriterAbstract.php similarity index 97% rename from src/Spout/Writer/AbstractWriter.php rename to src/Spout/Writer/WriterAbstract.php index 7f7a7a3..d383b0b 100644 --- a/src/Spout/Writer/AbstractWriter.php +++ b/src/Spout/Writer/WriterAbstract.php @@ -2,8 +2,8 @@ namespace Box\Spout\Writer; -use Box\Spout\Common\Exception\IOException; use Box\Spout\Common\Exception\InvalidArgumentException; +use Box\Spout\Common\Exception\IOException; use Box\Spout\Common\Exception\SpoutException; use Box\Spout\Common\Helper\FileSystemHelper; use Box\Spout\Writer\Common\Manager\OptionsManagerInterface; @@ -12,12 +12,12 @@ use Box\Spout\Writer\Exception\WriterAlreadyOpenedException; use Box\Spout\Writer\Exception\WriterNotOpenedException; /** - * Class AbstractWriter + * Class WriterAbstract * * @package Box\Spout\Writer * @abstract */ -abstract class AbstractWriter implements WriterInterface +abstract class WriterAbstract implements WriterInterface { /** @var string Path to the output file */ protected $outputFilePath; @@ -80,7 +80,7 @@ abstract class AbstractWriter implements WriterInterface * @see https://github.com/box/spout/issues/272 * * @param Style\Style $defaultStyle - * @return AbstractWriter + * @return WriterAbstract */ public function setDefaultRowStyle($defaultStyle) { @@ -91,7 +91,7 @@ abstract class AbstractWriter implements WriterInterface /** * @param \Box\Spout\Common\Helper\GlobalFunctionsHelper $globalFunctionsHelper - * @return AbstractWriter + * @return WriterAbstract */ public function setGlobalFunctionsHelper($globalFunctionsHelper) { @@ -105,7 +105,7 @@ abstract class AbstractWriter implements WriterInterface * * @api * @param string $outputFilePath Path of the output file that will contain the data - * @return AbstractWriter + * @return WriterAbstract * @throws \Box\Spout\Common\Exception\IOException If the writer cannot be opened or if the given path is not writable */ public function openToFile($outputFilePath) @@ -129,7 +129,7 @@ abstract class AbstractWriter implements WriterInterface * * @api * @param string $outputFileName Name of the output file that will contain the data. If a path is passed in, only the file name will be kept - * @return AbstractWriter + * @return WriterAbstract * @throws \Box\Spout\Common\Exception\IOException If the writer cannot be opened */ public function openToBrowser($outputFileName) @@ -199,7 +199,7 @@ abstract class AbstractWriter implements WriterInterface * If empty, no data is added (i.e. not even as a blank row) * Example: $dataRow = ['data1', 1234, null, '', 'data5', false]; * @api - * @return AbstractWriter + * @return WriterAbstract * @throws \Box\Spout\Writer\Exception\WriterNotOpenedException If this function is called before opening the writer * @throws \Box\Spout\Common\Exception\IOException If unable to write data * @throws \Box\Spout\Common\Exception\SpoutException If anything else goes wrong while writing data @@ -234,7 +234,7 @@ abstract class AbstractWriter implements WriterInterface * @api * @param array $dataRow Array of array containing data to be streamed. * @param Style\Style $style Style to be applied to the row. - * @return AbstractWriter + * @return WriterAbstract * @throws \Box\Spout\Common\Exception\InvalidArgumentException If the input param is not valid * @throws \Box\Spout\Writer\Exception\WriterNotOpenedException If this function is called before opening the writer * @throws \Box\Spout\Common\Exception\IOException If unable to write data @@ -262,7 +262,7 @@ abstract class AbstractWriter implements WriterInterface * ['data11', 12, , '', 'data13'], * ['data21', 'data22', null, false], * ]; - * @return AbstractWriter + * @return WriterAbstract * @throws \Box\Spout\Common\Exception\InvalidArgumentException If the input param is not valid * @throws \Box\Spout\Writer\Exception\WriterNotOpenedException If this function is called before opening the writer * @throws \Box\Spout\Common\Exception\IOException If unable to write data @@ -290,7 +290,7 @@ abstract class AbstractWriter implements WriterInterface * @api * @param array $dataRows Array of array containing data to be streamed. * @param Style\Style $style Style to be applied to the rows. - * @return AbstractWriter + * @return WriterAbstract * @throws \Box\Spout\Common\Exception\InvalidArgumentException If the input param is not valid * @throws \Box\Spout\Writer\Exception\WriterNotOpenedException If this function is called before opening the writer * @throws \Box\Spout\Common\Exception\IOException If unable to write data diff --git a/src/Spout/Writer/WriterFactory.php b/src/Spout/Writer/WriterFactory.php index a6408cb..185bcd0 100644 --- a/src/Spout/Writer/WriterFactory.php +++ b/src/Spout/Writer/WriterFactory.php @@ -5,6 +5,7 @@ namespace Box\Spout\Writer; use Box\Spout\Common\Exception\UnsupportedTypeException; use Box\Spout\Common\Helper\GlobalFunctionsHelper; use Box\Spout\Common\Type; +use Box\Spout\Writer\Factory\EntityFactory; use Box\Spout\Writer\Style\StyleBuilder; /** @@ -64,8 +65,9 @@ class WriterFactory { $styleBuilder = new StyleBuilder(); $optionsManager = new XLSX\Manager\OptionsManager($styleBuilder); + $generalFactory = new XLSX\Factory\InternalFactory(new EntityFactory()); - return new XLSX\Writer($optionsManager); + return new XLSX\Writer($optionsManager, $generalFactory); } /** @@ -75,7 +77,8 @@ class WriterFactory { $styleBuilder = new StyleBuilder(); $optionsManager = new ODS\Manager\OptionsManager($styleBuilder); + $generalFactory = new ODS\Factory\InternalFactory(new EntityFactory()); - return new ODS\Writer($optionsManager); + return new ODS\Writer($optionsManager, $generalFactory); } } diff --git a/src/Spout/Writer/WriterMultiSheetsAbstract.php b/src/Spout/Writer/WriterMultiSheetsAbstract.php new file mode 100644 index 0000000..88e7446 --- /dev/null +++ b/src/Spout/Writer/WriterMultiSheetsAbstract.php @@ -0,0 +1,177 @@ +internalFactory = $internalFactory; + } + + /** + * Sets whether new sheets should be automatically created when the max rows limit per sheet is reached. + * This must be set before opening the writer. + * + * @api + * @param bool $shouldCreateNewSheetsAutomatically Whether new sheets should be automatically created when the max rows limit per sheet is reached + * @return WriterMultiSheetsAbstract + * @throws \Box\Spout\Writer\Exception\WriterAlreadyOpenedException If the writer was already opened + */ + public function setShouldCreateNewSheetsAutomatically($shouldCreateNewSheetsAutomatically) + { + $this->throwIfWriterAlreadyOpened('Writer must be configured before opening it.'); + + $this->optionsManager->setOption(Options::SHOULD_CREATE_NEW_SHEETS_AUTOMATICALLY, $shouldCreateNewSheetsAutomatically); + return $this; + } + + /** + * Configures the write and sets the current sheet pointer to a new sheet. + * + * @return void + * @throws \Box\Spout\Common\Exception\IOException If unable to open the file for writing + */ + protected function openWriter() + { + if (!$this->workbookManager) { + $this->workbookManager = $this->internalFactory->createWorkbookManager($this->optionsManager); + $this->workbookManager->addNewSheetAndMakeItCurrent(); + } + } + + /** + * Returns all the workbook's sheets + * + * @api + * @return Common\Sheet[] All the workbook's sheets + * @throws \Box\Spout\Writer\Exception\WriterNotOpenedException If the writer has not been opened yet + */ + public function getSheets() + { + $this->throwIfWorkbookIsNotAvailable(); + + $externalSheets = []; + $worksheets = $this->workbookManager->getWorksheets(); + + /** @var Worksheet $worksheet */ + foreach ($worksheets as $worksheet) { + $externalSheets[] = $worksheet->getExternalSheet(); + } + + return $externalSheets; + } + + /** + * Creates a new sheet and make it the current sheet. The data will now be written to this sheet. + * + * @api + * @return Common\Sheet The created sheet + * @throws \Box\Spout\Writer\Exception\WriterNotOpenedException If the writer has not been opened yet + */ + public function addNewSheetAndMakeItCurrent() + { + $this->throwIfWorkbookIsNotAvailable(); + $worksheet = $this->workbookManager->addNewSheetAndMakeItCurrent(); + + return $worksheet->getExternalSheet(); + } + + /** + * Returns the current sheet + * + * @api + * @return Common\Sheet The current sheet + * @throws \Box\Spout\Writer\Exception\WriterNotOpenedException If the writer has not been opened yet + */ + public function getCurrentSheet() + { + $this->throwIfWorkbookIsNotAvailable(); + return $this->workbookManager->getCurrentWorksheet()->getExternalSheet(); + } + + /** + * Sets the given sheet as the current one. New data will be written to this sheet. + * The writing will resume where it stopped (i.e. data won't be truncated). + * + * @api + * @param Common\Sheet $sheet The sheet to set as current + * @return void + * @throws \Box\Spout\Writer\Exception\WriterNotOpenedException If the writer has not been opened yet + * @throws \Box\Spout\Writer\Exception\SheetNotFoundException If the given sheet does not exist in the workbook + */ + public function setCurrentSheet($sheet) + { + $this->throwIfWorkbookIsNotAvailable(); + $this->workbookManager->setCurrentSheet($sheet); + } + + /** + * Checks if the workbook has been created. Throws an exception if not created yet. + * + * @return void + * @throws \Box\Spout\Writer\Exception\WriterNotOpenedException If the workbook is not created yet + */ + protected function throwIfWorkbookIsNotAvailable() + { + if (!$this->workbookManager->getWorkbook()) { + throw new WriterNotOpenedException('The writer must be opened before performing this action.'); + } + } + + /** + * Adds data to the currently opened writer. + * If shouldCreateNewSheetsAutomatically option is set to true, it will handle pagination + * with the creation of new worksheets if one worksheet has reached its maximum capicity. + * + * @param array $dataRow Array containing data to be written. + * Example $dataRow = ['data1', 1234, null, '', 'data5']; + * @param \Box\Spout\Writer\Style\Style $style Style to be applied to the row. + * @return void + * @throws \Box\Spout\Writer\Exception\WriterNotOpenedException If the book is not created yet + * @throws \Box\Spout\Common\Exception\IOException If unable to write data + */ + protected function addRowToWriter(array $dataRow, $style) + { + $this->throwIfWorkbookIsNotAvailable(); + $this->workbookManager->addRowToCurrentWorksheet($dataRow, $style); + } + + /** + * Closes the writer, preventing any additional writing. + * + * @return void + */ + protected function closeWriter() + { + if ($this->workbookManager) { + $this->workbookManager->close($this->filePointer); + } + } +} + diff --git a/src/Spout/Writer/XLSX/Factory/InternalFactory.php b/src/Spout/Writer/XLSX/Factory/InternalFactory.php new file mode 100644 index 0000000..d1991ce --- /dev/null +++ b/src/Spout/Writer/XLSX/Factory/InternalFactory.php @@ -0,0 +1,123 @@ +entityFactory = $entityFactory; + } + + /** + * @param OptionsManagerInterface $optionsManager + * @return WorkbookManager + */ + public function createWorkbookManager(OptionsManagerInterface $optionsManager) + { + $workbook = $this->entityFactory->createWorkbook(); + + $fileSystemHelper = $this->createFileSystemHelper($optionsManager); + $fileSystemHelper->createBaseFilesAndFolders(); + + $xlFolder = $fileSystemHelper->getXlFolder(); + $sharedStringsHelper = $this->createSharedStringsHelper($xlFolder); + + $styleHelper = $this->createStyleHelper($optionsManager); + + $worksheetManager = $this->createWorksheetManager($optionsManager, $sharedStringsHelper, $styleHelper); + + return new WorkbookManager($workbook, $optionsManager, $worksheetManager, $styleHelper, $fileSystemHelper, $this->entityFactory); + } + + /** + * @param OptionsManagerInterface $optionsManager + * @param SharedStringsHelper $sharedStringsHelper + * @param StyleHelper $styleHelper + * @return WorksheetManager + */ + private function createWorksheetManager( + OptionsManagerInterface $optionsManager, + SharedStringsHelper $sharedStringsHelper, + StyleHelper $styleHelper + ) + { + $stringsEscaper = $this->createStringsEscaper(); + $stringsHelper = $this->createStringHelper(); + + return new WorksheetManager($optionsManager, $sharedStringsHelper, $styleHelper, $stringsEscaper, $stringsHelper); + } + + /** + * @param string $xlFolder Path to the "xl" folder + * @return SharedStringsHelper + */ + private function createSharedStringsHelper($xlFolder) + { + return new SharedStringsHelper($xlFolder); + } + + /** + * @param OptionsManagerInterface $optionsManager + * @return FileSystemHelper + */ + private function createFileSystemHelper(OptionsManagerInterface $optionsManager) + { + $tempFolder = $optionsManager->getOption(Options::TEMP_FOLDER); + return new FileSystemHelper($tempFolder); + } + + /** + * @param OptionsManagerInterface $optionsManager + * @return StyleHelper + */ + private function createStyleHelper(OptionsManagerInterface $optionsManager) + { + $defaultRowStyle = $optionsManager->getOption(Options::DEFAULT_ROW_STYLE); + return new StyleHelper($defaultRowStyle); + } + + /** + * @return Escaper\XLSX + */ + private function createStringsEscaper() + { + return Escaper\XLSX::getInstance(); + } + + /** + * @return StringHelper + */ + private function createStringHelper() + { + return new StringHelper(); + } +} \ No newline at end of file diff --git a/src/Spout/Writer/XLSX/Helper/FileSystemHelper.php b/src/Spout/Writer/XLSX/Helper/FileSystemHelper.php index 86515f3..752183d 100644 --- a/src/Spout/Writer/XLSX/Helper/FileSystemHelper.php +++ b/src/Spout/Writer/XLSX/Helper/FileSystemHelper.php @@ -2,8 +2,9 @@ namespace Box\Spout\Writer\XLSX\Helper; +use Box\Spout\Writer\Common\Helper\FileSystemWithRootFolderHelperInterface; use Box\Spout\Writer\Common\Helper\ZipHelper; -use Box\Spout\Writer\XLSX\Internal\Worksheet; +use Box\Spout\Writer\Entity\Worksheet; /** * Class FileSystemHelper @@ -12,7 +13,7 @@ use Box\Spout\Writer\XLSX\Internal\Worksheet; * * @package Box\Spout\Writer\XLSX\Helper */ -class FileSystemHelper extends \Box\Spout\Common\Helper\FileSystemHelper +class FileSystemHelper extends \Box\Spout\Common\Helper\FileSystemHelper implements FileSystemWithRootFolderHelperInterface { const APP_NAME = 'Spout'; @@ -30,22 +31,22 @@ class FileSystemHelper extends \Box\Spout\Common\Helper\FileSystemHelper const STYLES_XML_FILE_NAME = 'styles.xml'; /** @var string Path to the root folder inside the temp folder where the files to create the XLSX will be stored */ - protected $rootFolder; + private $rootFolder; /** @var string Path to the "_rels" folder inside the root folder */ - protected $relsFolder; + private $relsFolder; /** @var string Path to the "docProps" folder inside the root folder */ - protected $docPropsFolder; + private $docPropsFolder; /** @var string Path to the "xl" folder inside the root folder */ - protected $xlFolder; + private $xlFolder; /** @var string Path to the "_rels" folder inside the "xl" folder */ - protected $xlRelsFolder; + private $xlRelsFolder; /** @var string Path to the "worksheets" folder inside the "xl" folder */ - protected $xlWorksheetsFolder; + private $xlWorksheetsFolder; /** * @return string @@ -92,7 +93,7 @@ class FileSystemHelper extends \Box\Spout\Common\Helper\FileSystemHelper * @return FileSystemHelper * @throws \Box\Spout\Common\Exception\IOException If unable to create the folder */ - protected function createRootFolder() + private function createRootFolder() { $this->rootFolder = $this->createFolder($this->baseFolderRealPath, uniqid('xlsx', true)); return $this; @@ -104,7 +105,7 @@ class FileSystemHelper extends \Box\Spout\Common\Helper\FileSystemHelper * @return FileSystemHelper * @throws \Box\Spout\Common\Exception\IOException If unable to create the folder or the ".rels" file */ - protected function createRelsFolderAndFile() + private function createRelsFolderAndFile() { $this->relsFolder = $this->createFolder($this->rootFolder, self::RELS_FOLDER_NAME); @@ -119,7 +120,7 @@ class FileSystemHelper extends \Box\Spout\Common\Helper\FileSystemHelper * @return FileSystemHelper * @throws \Box\Spout\Common\Exception\IOException If unable to create the file */ - protected function createRelsFile() + private function createRelsFile() { $relsFileContents = << @@ -141,7 +142,7 @@ EOD; * @return FileSystemHelper * @throws \Box\Spout\Common\Exception\IOException If unable to create the folder or one of the files */ - protected function createDocPropsFolderAndFiles() + private function createDocPropsFolderAndFiles() { $this->docPropsFolder = $this->createFolder($this->rootFolder, self::DOC_PROPS_FOLDER_NAME); @@ -157,7 +158,7 @@ EOD; * @return FileSystemHelper * @throws \Box\Spout\Common\Exception\IOException If unable to create the file */ - protected function createAppXmlFile() + private function createAppXmlFile() { $appName = self::APP_NAME; $appXmlFileContents = <<format(\DateTime::W3C); $coreXmlFileContents = <<xlFolder = $this->createFolder($this->rootFolder, self::XL_FOLDER_NAME); $this->createXlRelsFolder(); @@ -217,7 +218,7 @@ EOD; * @return FileSystemHelper * @throws \Box\Spout\Common\Exception\IOException If unable to create the folder */ - protected function createXlRelsFolder() + private function createXlRelsFolder() { $this->xlRelsFolder = $this->createFolder($this->xlFolder, self::RELS_FOLDER_NAME); return $this; @@ -229,7 +230,7 @@ EOD; * @return FileSystemHelper * @throws \Box\Spout\Common\Exception\IOException If unable to create the folder */ - protected function createXlWorksheetsFolder() + private function createXlWorksheetsFolder() { $this->xlWorksheetsFolder = $this->createFolder($this->xlFolder, self::WORKSHEETS_FOLDER_NAME); return $this; diff --git a/src/Spout/Writer/XLSX/Helper/StyleHelper.php b/src/Spout/Writer/XLSX/Helper/StyleHelper.php index 4a13c95..2795c87 100644 --- a/src/Spout/Writer/XLSX/Helper/StyleHelper.php +++ b/src/Spout/Writer/XLSX/Helper/StyleHelper.php @@ -2,7 +2,7 @@ namespace Box\Spout\Writer\XLSX\Helper; -use Box\Spout\Writer\Common\Helper\AbstractStyleHelper; +use Box\Spout\Writer\Common\Helper\StyleHelperAbstract; use Box\Spout\Writer\Style\Color; use Box\Spout\Writer\Style\Style; @@ -12,7 +12,7 @@ use Box\Spout\Writer\Style\Style; * * @package Box\Spout\Writer\XLSX\Helper */ -class StyleHelper extends AbstractStyleHelper +class StyleHelper extends StyleHelperAbstract { /** * @var array diff --git a/src/Spout/Writer/XLSX/Internal/Workbook.php b/src/Spout/Writer/XLSX/Internal/Workbook.php deleted file mode 100644 index 532cd95..0000000 --- a/src/Spout/Writer/XLSX/Internal/Workbook.php +++ /dev/null @@ -1,135 +0,0 @@ -getOption(Options::TEMP_FOLDER); - $this->fileSystemHelper = new FileSystemHelper($tempFolder); - $this->fileSystemHelper->createBaseFilesAndFolders(); - - $defaultRowStyle = $optionsManager->getOption(Options::DEFAULT_ROW_STYLE); - $this->styleHelper = new StyleHelper($defaultRowStyle); - - // This helper will be shared by all sheets - $xlFolder = $this->fileSystemHelper->getXlFolder(); - $this->sharedStringsHelper = new SharedStringsHelper($xlFolder); - } - - /** - * @return \Box\Spout\Writer\XLSX\Helper\StyleHelper Helper to apply styles to XLSX files - */ - protected function getStyleHelper() - { - return $this->styleHelper; - } - - /** - * @return int Maximum number of rows/columns a sheet can contain - */ - protected function getMaxRowsPerWorksheet() - { - return self::$maxRowsPerWorksheet; - } - - /** - * Creates a new sheet in the workbook. The current sheet remains unchanged. - * - * @return Worksheet The created sheet - * @throws \Box\Spout\Common\Exception\IOException If unable to open the sheet for writing - */ - public function addNewSheet() - { - $newSheetIndex = count($this->worksheets); - $sheet = new Sheet($newSheetIndex, $this->internalId); - - $worksheetFilesFolder = $this->fileSystemHelper->getXlWorksheetsFolder(); - $worksheet = new Worksheet($sheet, $worksheetFilesFolder, $this->sharedStringsHelper, $this->styleHelper, $this->optionManager); - $this->worksheets[] = $worksheet; - - return $worksheet; - } - - /** - * Closes the workbook and all its associated sheets. - * All the necessary files are written to disk and zipped together to create the XLSX file. - * All the temporary files are then deleted. - * - * @param resource $finalFilePointer Pointer to the XLSX that will be created - * @return void - */ - public function close($finalFilePointer) - { - /** @var Worksheet[] $worksheets */ - $worksheets = $this->worksheets; - - foreach ($worksheets as $worksheet) { - $worksheet->close(); - } - - $this->sharedStringsHelper->close(); - - // Finish creating all the necessary files before zipping everything together - $this->fileSystemHelper - ->createContentTypesFile($worksheets) - ->createWorkbookFile($worksheets) - ->createWorkbookRelsFile($worksheets) - ->createStylesFile($this->styleHelper) - ->zipRootFolderAndCopyToStream($finalFilePointer); - - $this->cleanupTempFolder(); - } - - /** - * Deletes the root folder created in the temp folder and all its contents. - * - * @return void - */ - protected function cleanupTempFolder() - { - $xlsxRootFolder = $this->fileSystemHelper->getRootFolder(); - $this->fileSystemHelper->deleteFolderRecursively($xlsxRootFolder); - } -} diff --git a/src/Spout/Writer/XLSX/Manager/WorkbookManager.php b/src/Spout/Writer/XLSX/Manager/WorkbookManager.php new file mode 100644 index 0000000..29c559c --- /dev/null +++ b/src/Spout/Writer/XLSX/Manager/WorkbookManager.php @@ -0,0 +1,78 @@ +fileSystemHelper->getXlWorksheetsFolder(); + return $worksheetFilesFolder . '/' . strtolower($sheet->getName()) . '.xml'; + } + + /** + * Closes custom objects that are still opened + * + * @return void + */ + protected function closeRemainingObjects() + { + $this->worksheetManager->getSharedStringsHelper()->close(); + } + + /** + * Writes all the necessary files to disk and zip them together to create the final file. + * + * @param resource $finalFilePointer Pointer to the spreadsheet that will be created + * @return void + */ + protected function writeAllFilesToDiskAndZipThem($finalFilePointer) + { + $worksheets = $this->getWorksheets(); + + $this->fileSystemHelper + ->createContentTypesFile($worksheets) + ->createWorkbookFile($worksheets) + ->createWorkbookRelsFile($worksheets) + ->createStylesFile($this->styleHelper) + ->zipRootFolderAndCopyToStream($finalFilePointer); + } +} \ No newline at end of file diff --git a/src/Spout/Writer/XLSX/Internal/Worksheet.php b/src/Spout/Writer/XLSX/Manager/WorksheetManager.php similarity index 59% rename from src/Spout/Writer/XLSX/Internal/Worksheet.php rename to src/Spout/Writer/XLSX/Manager/WorksheetManager.php index 3e6dfa0..45903f4 100644 --- a/src/Spout/Writer/XLSX/Internal/Worksheet.php +++ b/src/Spout/Writer/XLSX/Manager/WorksheetManager.php @@ -1,24 +1,27 @@ EOD; - /** @var \Box\Spout\Writer\Common\Sheet The "external" sheet */ - protected $externalSheet; - - /** @var string Path to the XML file that will contain the sheet data */ - protected $worksheetFilePath; - - /** @var \Box\Spout\Writer\XLSX\Helper\SharedStringsHelper Helper to write shared strings */ - protected $sharedStringsHelper; - - /** @var \Box\Spout\Writer\XLSX\Helper\StyleHelper Helper to work with styles */ - protected $styleHelper; - /** @var bool Whether inline or shared strings should be used */ protected $shouldUseInlineStrings; + /** @var SharedStringsHelper Helper to write shared strings */ + private $sharedStringsHelper; + + /** @var StyleHelper Helper to work with styles */ + private $styleHelper; + /** @var \Box\Spout\Common\Escaper\XLSX Strings escaper */ - protected $stringsEscaper; + private $stringsEscaper; - /** @var \Box\Spout\Common\Helper\StringHelper String helper */ - protected $stringHelper; - - /** @var Resource Pointer to the sheet data file (e.g. xl/worksheets/sheet1.xml) */ - protected $sheetFilePointer; - - /** @var int Index of the last written row */ - protected $lastWrittenRowIndex = 0; + /** @var StringHelper String helper */ + private $stringHelper; /** - * @param \Box\Spout\Writer\Common\Sheet $externalSheet The associated "external" sheet - * @param string $worksheetFilesFolder Temporary folder where the files to create the XLSX will be stored - * @param \Box\Spout\Writer\XLSX\Helper\SharedStringsHelper $sharedStringsHelper Helper for shared strings - * @param \Box\Spout\Writer\XLSX\Helper\StyleHelper $styleHelper Helper to work with styles - * @param \Box\Spout\Writer\Common\Manager\OptionsManagerInterface $optionsManager Options manager - * @throws \Box\Spout\Common\Exception\IOException If the sheet data file cannot be opened for writing + * WorksheetManager constructor. + * + * @param OptionsManagerInterface $optionsManager + * @param SharedStringsHelper $sharedStringsHelper + * @param StyleHelper $styleHelper + * @param \Box\Spout\Common\Escaper\XLSX $stringsEscaper + * @param StringHelper $stringHelper */ - public function __construct($externalSheet, $worksheetFilesFolder, $sharedStringsHelper, $styleHelper, OptionsManagerInterface $optionsManager) + public function __construct( + OptionsManagerInterface $optionsManager, + SharedStringsHelper $sharedStringsHelper, + StyleHelper $styleHelper, + \Box\Spout\Common\Escaper\XLSX $stringsEscaper, + StringHelper $stringHelper) { - $this->externalSheet = $externalSheet; + $this->shouldUseInlineStrings = $optionsManager->getOption(Options::SHOULD_USE_INLINE_STRINGS); $this->sharedStringsHelper = $sharedStringsHelper; $this->styleHelper = $styleHelper; - $this->shouldUseInlineStrings = $optionsManager->getOption(Options::SHOULD_USE_INLINE_STRINGS); - - /** @noinspection PhpUnnecessaryFullyQualifiedNameInspection */ - $this->stringsEscaper = \Box\Spout\Common\Escaper\XLSX::getInstance(); - $this->stringHelper = new StringHelper(); - - $this->worksheetFilePath = $worksheetFilesFolder . '/' . strtolower($this->externalSheet->getName()) . '.xml'; - $this->startSheet(); + $this->stringsEscaper = $stringsEscaper; + $this->stringHelper = $stringHelper; } + /** + * @return SharedStringsHelper + */ + public function getSharedStringsHelper() + { + return $this->sharedStringsHelper; + } + + /** * Prepares the worksheet to accept data * + * @param Worksheet $worksheet The worksheet to start * @return void * @throws \Box\Spout\Common\Exception\IOException If the sheet data file cannot be opened for writing */ - protected function startSheet() + public function startSheet(Worksheet $worksheet) { - $this->sheetFilePointer = fopen($this->worksheetFilePath, 'w'); - $this->throwIfSheetFilePointerIsNotAvailable(); + $sheetFilePointer = fopen($worksheet->getFilePath(), 'w'); + $this->throwIfSheetFilePointerIsNotAvailable($sheetFilePointer); - fwrite($this->sheetFilePointer, self::SHEET_XML_FILE_HEADER); - fwrite($this->sheetFilePointer, ''); + $worksheet->setFilePointer($sheetFilePointer); + + fwrite($sheetFilePointer, self::SHEET_XML_FILE_HEADER); + fwrite($sheetFilePointer, ''); } /** - * Checks if the book has been created. Throws an exception if not created yet. + * Checks if the sheet has been sucessfully created. Throws an exception if not. * + * @param bool|resource $sheetFilePointer Pointer to the sheet data file or FALSE if unable to open the file * @return void - * @throws \Box\Spout\Common\Exception\IOException If the sheet data file cannot be opened for writing + * @throws IOException If the sheet data file cannot be opened for writing */ - protected function throwIfSheetFilePointerIsNotAvailable() + private function throwIfSheetFilePointerIsNotAvailable($sheetFilePointer) { - if (!$this->sheetFilePointer) { + if (!$sheetFilePointer) { throw new IOException('Unable to open sheet for writing.'); } } /** - * @return \Box\Spout\Writer\Common\Sheet The "external" sheet - */ - public function getExternalSheet() - { - return $this->externalSheet; - } - - /** - * @return int The index of the last written row - */ - public function getLastWrittenRowIndex() - { - return $this->lastWrittenRowIndex; - } - - /** - * @return int The ID of the worksheet - */ - public function getId() - { - // sheet index is zero-based, while ID is 1-based - return $this->externalSheet->getIndex() + 1; - } - - /** - * Adds data to the worksheet. + * Adds data to the given worksheet. * + * @param Worksheet $worksheet The worksheet to add the row to * @param array $dataRow Array containing data to be written. Cannot be empty. * Example $dataRow = ['data1', 1234, null, '', 'data5']; - * @param \Box\Spout\Writer\Style\Style $style Style to be applied to the row. NULL means use default style. + * @param Style $rowStyle Style to be applied to the row. NULL means use default style. * @return void - * @throws \Box\Spout\Common\Exception\IOException If the data cannot be written - * @throws \Box\Spout\Common\Exception\InvalidArgumentException If a cell value's type is not supported + * @throws IOException If the data cannot be written + * @throws InvalidArgumentException If a cell value's type is not supported */ - public function addRow($dataRow, $style) + public function addRow(Worksheet $worksheet, $dataRow, $rowStyle) { if (!$this->isEmptyRow($dataRow)) { - $this->addNonEmptyRow($dataRow, $style); + $this->addNonEmptyRow($worksheet, $dataRow, $rowStyle); } - $this->lastWrittenRowIndex++; + $worksheet->setLastWrittenRowIndex($worksheet->getLastWrittenRowIndex() + 1); } /** @@ -172,6 +152,7 @@ EOD; /** * Adds non empty row to the worksheet. * + * @param Worksheet $worksheet The worksheet to add the row to * @param array $dataRow Array containing data to be written. Cannot be empty. * Example $dataRow = ['data1', 1234, null, '', 'data5']; * @param \Box\Spout\Writer\Style\Style $style Style to be applied to the row. NULL means use default style. @@ -179,10 +160,10 @@ EOD; * @throws \Box\Spout\Common\Exception\IOException If the data cannot be written * @throws \Box\Spout\Common\Exception\InvalidArgumentException If a cell value's type is not supported */ - private function addNonEmptyRow($dataRow, $style) + private function addNonEmptyRow(Worksheet $worksheet, $dataRow, $style) { $cellNumber = 0; - $rowIndex = $this->lastWrittenRowIndex + 1; + $rowIndex = $worksheet->getLastWrittenRowIndex() + 1; $numCells = count($dataRow); $rowXML = ''; @@ -194,9 +175,9 @@ EOD; $rowXML .= ''; - $wasWriteSuccessful = fwrite($this->sheetFilePointer, $rowXML); + $wasWriteSuccessful = fwrite($worksheet->getFilePointer(), $rowXML); if ($wasWriteSuccessful === false) { - throw new IOException("Unable to write data in {$this->worksheetFilePath}"); + throw new IOException("Unable to write data in {$worksheet->getFilePath()}"); } } @@ -270,16 +251,19 @@ EOD; /** * Closes the worksheet * + * @param Worksheet $worksheet * @return void */ - public function close() + public function close(Worksheet $worksheet) { - if (!is_resource($this->sheetFilePointer)) { + $worksheetFilePointer = $worksheet->getFilePointer(); + + if (!is_resource($worksheetFilePointer)) { return; } - fwrite($this->sheetFilePointer, ''); - fwrite($this->sheetFilePointer, ''); - fclose($this->sheetFilePointer); + fwrite($worksheetFilePointer, ''); + fwrite($worksheetFilePointer, ''); + fclose($worksheetFilePointer); } -} +} \ No newline at end of file diff --git a/src/Spout/Writer/XLSX/Writer.php b/src/Spout/Writer/XLSX/Writer.php index 1fdb650..7aeb096 100644 --- a/src/Spout/Writer/XLSX/Writer.php +++ b/src/Spout/Writer/XLSX/Writer.php @@ -2,10 +2,8 @@ namespace Box\Spout\Writer\XLSX; -use Box\Spout\Writer\AbstractMultiSheetsWriter; use Box\Spout\Writer\Common\Options; -use Box\Spout\Writer\Style\StyleBuilder; -use Box\Spout\Writer\XLSX\Internal\Workbook; +use Box\Spout\Writer\WriterMultiSheetsAbstract; /** * Class Writer @@ -13,14 +11,11 @@ use Box\Spout\Writer\XLSX\Internal\Workbook; * * @package Box\Spout\Writer\XLSX */ -class Writer extends AbstractMultiSheetsWriter +class Writer extends WriterMultiSheetsAbstract { /** @var string Content-Type value for the header */ protected static $headerContentType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'; - /** @var Internal\Workbook The workbook for the XLSX file */ - protected $book; - /** * Sets a custom temporary folder for creating intermediate files/folders. * This must be set before opening the writer. @@ -54,56 +49,4 @@ class Writer extends AbstractMultiSheetsWriter $this->optionsManager->setOption(Options::SHOULD_USE_INLINE_STRINGS, $shouldUseInlineStrings); return $this; } - - /** - * Configures the write and sets the current sheet pointer to a new sheet. - * - * @return void - * @throws \Box\Spout\Common\Exception\IOException If unable to open the file for writing - */ - protected function openWriter() - { - if (!$this->book) { - $this->book = new Workbook($this->optionsManager); - $this->book->addNewSheetAndMakeItCurrent(); - } - } - - /** - * @return Internal\Workbook The workbook representing the file to be written - */ - protected function getWorkbook() - { - return $this->book; - } - - /** - * Adds data to the currently opened writer. - * If shouldCreateNewSheetsAutomatically option is set to true, it will handle pagination - * with the creation of new worksheets if one worksheet has reached its maximum capicity. - * - * @param array $dataRow Array containing data to be written. - * Example $dataRow = ['data1', 1234, null, '', 'data5']; - * @param \Box\Spout\Writer\Style\Style $style Style to be applied to the row. - * @return void - * @throws \Box\Spout\Writer\Exception\WriterNotOpenedException If the book is not created yet - * @throws \Box\Spout\Common\Exception\IOException If unable to write data - */ - protected function addRowToWriter(array $dataRow, $style) - { - $this->throwIfBookIsNotAvailable(); - $this->book->addRowToCurrentWorksheet($dataRow, $style); - } - - /** - * Closes the writer, preventing any additional writing. - * - * @return void - */ - protected function closeWriter() - { - if ($this->book) { - $this->book->close($this->filePointer); - } - } } diff --git a/tests/Spout/Writer/ODS/SheetTest.php b/tests/Spout/Writer/ODS/SheetTest.php index ee59501..e9028c5 100644 --- a/tests/Spout/Writer/ODS/SheetTest.php +++ b/tests/Spout/Writer/ODS/SheetTest.php @@ -62,6 +62,7 @@ class SheetTest extends \PHPUnit_Framework_TestCase $this->createGeneratedFolderIfNeeded($fileName); $resourcePath = $this->getGeneratedResourcePath($fileName); + /** @var \Box\Spout\Writer\ODS\Writer $writer */ $writer = WriterFactory::create(Type::ODS); $writer->openToFile($resourcePath); @@ -85,6 +86,7 @@ class SheetTest extends \PHPUnit_Framework_TestCase $this->createGeneratedFolderIfNeeded($fileName); $resourcePath = $this->getGeneratedResourcePath($fileName); + /** @var \Box\Spout\Writer\ODS\Writer $writer */ $writer = WriterFactory::create(Type::ODS); $writer->openToFile($resourcePath); diff --git a/tests/Spout/Writer/ODS/WriterTest.php b/tests/Spout/Writer/ODS/WriterTest.php index df60af9..38b29b0 100644 --- a/tests/Spout/Writer/ODS/WriterTest.php +++ b/tests/Spout/Writer/ODS/WriterTest.php @@ -155,6 +155,7 @@ class WriterTest extends \PHPUnit_Framework_TestCase $this->createGeneratedFolderIfNeeded($fileName); $resourcePath = $this->getGeneratedResourcePath($fileName); + /** @var Writer $writer */ $writer = WriterFactory::create(Type::ODS); $writer->openToFile($resourcePath); @@ -376,7 +377,7 @@ class WriterTest extends \PHPUnit_Framework_TestCase ]; // set the maxRowsPerSheet limit to 2 - \ReflectionHelper::setStaticValue('\Box\Spout\Writer\ODS\Internal\Workbook', 'maxRowsPerWorksheet', 2); + \ReflectionHelper::setStaticValue('\Box\Spout\Writer\ODS\Manager\WorkbookManager', 'maxRowsPerWorksheet', 2); $writer = $this->writeToODSFile($dataRows, $fileName, $shouldCreateSheetsAutomatically = true); $this->assertEquals(2, count($writer->getSheets()), '2 sheets should have been created.'); @@ -400,7 +401,7 @@ class WriterTest extends \PHPUnit_Framework_TestCase ]; // set the maxRowsPerSheet limit to 2 - \ReflectionHelper::setStaticValue('\Box\Spout\Writer\ODS\Internal\Workbook', 'maxRowsPerWorksheet', 2); + \ReflectionHelper::setStaticValue('\Box\Spout\Writer\ODS\Manager\WorkbookManager', 'maxRowsPerWorksheet', 2); $writer = $this->writeToODSFile($dataRows, $fileName, $shouldCreateSheetsAutomatically = false); $this->assertEquals(1, count($writer->getSheets()), 'Only 1 sheet should have been created.'); @@ -500,7 +501,7 @@ class WriterTest extends \PHPUnit_Framework_TestCase foreach ($dataRows as $dataRow) { /** @var Cell $cell */ foreach ($dataRow as $cell) { - $this->assertValueWasWritten($fileName, (string)$cell->getValue(), '', true); + $this->assertValueWasWritten($fileName, (string)$cell->getValue(), ''); } } } diff --git a/tests/Spout/Writer/XLSX/WriterTest.php b/tests/Spout/Writer/XLSX/WriterTest.php index fe89deb..9fe0ab2 100644 --- a/tests/Spout/Writer/XLSX/WriterTest.php +++ b/tests/Spout/Writer/XLSX/WriterTest.php @@ -7,7 +7,7 @@ use Box\Spout\Common\Type; use Box\Spout\TestUsingResource; use Box\Spout\Writer\Common\Cell; use Box\Spout\Writer\WriterFactory; -use Box\Spout\Writer\XLSX\Internal\Worksheet; +use Box\Spout\Writer\XLSX\Manager\WorksheetManager; /** * Class WriterTest @@ -101,7 +101,7 @@ class WriterTest extends \PHPUnit_Framework_TestCase { $fileName = 'test_add_row_should_throw_exception_if_unsupported_data_type_passed_in.xlsx'; $dataRows = [ - [str_repeat('a', Worksheet::MAX_CHARACTERS_PER_CELL + 1)], + [str_repeat('a', WorksheetManager::MAX_CHARACTERS_PER_CELL + 1)], ]; $this->writeToXLSXFile($dataRows, $fileName); @@ -428,7 +428,7 @@ class WriterTest extends \PHPUnit_Framework_TestCase ]; // set the maxRowsPerSheet limit to 2 - \ReflectionHelper::setStaticValue('\Box\Spout\Writer\XLSX\Internal\Workbook', 'maxRowsPerWorksheet', 2); + \ReflectionHelper::setStaticValue('\Box\Spout\Writer\XLSX\Manager\WorkbookManager', 'maxRowsPerWorksheet', 2); $writer = $this->writeToXLSXFile($dataRows, $fileName, true, $shouldCreateSheetsAutomatically = true); $this->assertEquals(2, count($writer->getSheets()), '2 sheets should have been created.'); @@ -452,7 +452,7 @@ class WriterTest extends \PHPUnit_Framework_TestCase ]; // set the maxRowsPerSheet limit to 2 - \ReflectionHelper::setStaticValue('\Box\Spout\Writer\XLSX\Internal\Workbook', 'maxRowsPerWorksheet', 2); + \ReflectionHelper::setStaticValue('\Box\Spout\Writer\XLSX\Manager\WorkbookManager', 'maxRowsPerWorksheet', 2); $writer = $this->writeToXLSXFile($dataRows, $fileName, true, $shouldCreateSheetsAutomatically = false); $this->assertEquals(1, count($writer->getSheets()), 'Only 1 sheet should have been created.');