diff --git a/src/Spout/Reader/XLSX/Helper/SheetHelper.php b/src/Spout/Reader/XLSX/Helper/SheetHelper.php index b74ba01..aee3fd2 100644 --- a/src/Spout/Reader/XLSX/Helper/SheetHelper.php +++ b/src/Spout/Reader/XLSX/Helper/SheetHelper.php @@ -27,8 +27,11 @@ class SheetHelper const XML_ATTRIBUTE_ACTIVE_TAB = 'activeTab'; const XML_ATTRIBUTE_R_ID = 'r:id'; const XML_ATTRIBUTE_NAME = 'name'; + const XML_ATTRIBUTE_STATE = 'state'; const XML_ATTRIBUTE_ID = 'Id'; const XML_ATTRIBUTE_TARGET = 'Target'; + + const SHEET_STATE_VISIBLE = 'visible'; /** @var string Path of the XLSX file being read */ protected $filePath; @@ -105,16 +108,18 @@ class SheetHelper { $sheetId = $xmlReaderOnSheetNode->getAttribute(self::XML_ATTRIBUTE_R_ID); $escapedSheetName = $xmlReaderOnSheetNode->getAttribute(self::XML_ATTRIBUTE_NAME); + $sheetState = $xmlReaderOnSheetNode->getAttribute(self::XML_ATTRIBUTE_STATE); /** @noinspection PhpUnnecessaryFullyQualifiedNameInspection */ $escaper = \Box\Spout\Common\Escaper\XLSX::getInstance(); $sheetName = $escaper->unescape($escapedSheetName); + $isSheetVisible = ($sheetState === self::SHEET_STATE_VISIBLE); $sheetDataXMLFilePath = $this->getSheetDataXMLFilePathForSheetId($sheetId); return new Sheet( $this->filePath, $sheetDataXMLFilePath, - $sheetIndexZeroBased, $sheetName, $isSheetActive, + $sheetIndexZeroBased, $sheetName, $isSheetActive, $isSheetVisible, $this->options, $this->sharedStringsHelper ); } diff --git a/src/Spout/Reader/XLSX/Sheet.php b/src/Spout/Reader/XLSX/Sheet.php index 9baaef2..08ef569 100644 --- a/src/Spout/Reader/XLSX/Sheet.php +++ b/src/Spout/Reader/XLSX/Sheet.php @@ -24,21 +24,26 @@ class Sheet implements SheetInterface /** @var bool Whether the sheet was the active one */ protected $isActive; + /** @var bool Whether the sheet is visible or not */ + protected $isVisible; + /** * @param string $filePath Path of the XLSX file being read * @param string $sheetDataXMLFilePath Path of the sheet data XML file as in [Content_Types].xml * @param int $sheetIndex Index of the sheet, based on order in the workbook (zero-based) * @param string $sheetName Name of the sheet + * @param bool $isSheetVisible Whether the sheet is visible or not * @param bool $isSheetActive Whether the sheet was defined as active * @param \Box\Spout\Reader\XLSX\ReaderOptions $options Reader's current options * @param Helper\SharedStringsHelper Helper to work with shared strings */ - public function __construct($filePath, $sheetDataXMLFilePath, $sheetIndex, $sheetName, $isSheetActive, $options, $sharedStringsHelper) + public function __construct($filePath, $sheetDataXMLFilePath, $sheetIndex, $sheetName, $isSheetActive, $isSheetVisible, $options, $sharedStringsHelper) { $this->rowIterator = new RowIterator($filePath, $sheetDataXMLFilePath, $options, $sharedStringsHelper); $this->index = $sheetIndex; $this->name = $sheetName; $this->isActive = $isSheetActive; + $this->isVisible = $isSheetVisible; } /** @@ -76,4 +81,13 @@ class Sheet implements SheetInterface { return $this->isActive; } + + /** + * @api + * @return bool Whether the sheet is visible or not + */ + public function isVisible() + { + return $this->isVisible; + } } diff --git a/src/Spout/Writer/Common/Sheet.php b/src/Spout/Writer/Common/Sheet.php index 0d8c63b..a9f6b97 100644 --- a/src/Spout/Writer/Common/Sheet.php +++ b/src/Spout/Writer/Common/Sheet.php @@ -33,6 +33,9 @@ class Sheet /** @var string Name of the sheet */ protected $name; + /** @var bool Visibility of the sheet */ + protected $isVisible; + /** @var \Box\Spout\Common\Helper\StringHelper */ protected $stringHelper; @@ -50,6 +53,7 @@ class Sheet $this->stringHelper = new StringHelper(); $this->setName(self::DEFAULT_SHEET_NAME_PREFIX . ($sheetIndex + 1)); + $this->setIsVisible(true); } /** @@ -70,6 +74,28 @@ class Sheet return $this->name; } + /** + * @api + * @return bool isVisible visibility of the sheet + */ + public function isVisible() + { + return $this->isVisible; + } + + /** + * @api + * @param string $visibility Visibility of the sheet + * @return Sheet + */ + public function setIsVisible($isVisible = true) + { + $this->isVisible = $isVisible; + + return $this; + } + + /** * Sets the name of the sheet. Note that Excel has some restrictions on the name: * - it should not be blank diff --git a/src/Spout/Writer/XLSX/Helper/FileSystemHelper.php b/src/Spout/Writer/XLSX/Helper/FileSystemHelper.php index 86515f3..7238dcc 100644 --- a/src/Spout/Writer/XLSX/Helper/FileSystemHelper.php +++ b/src/Spout/Writer/XLSX/Helper/FileSystemHelper.php @@ -289,8 +289,10 @@ EOD; /** @var Worksheet $worksheet */ foreach ($worksheets as $worksheet) { $worksheetName = $worksheet->getExternalSheet()->getName(); + $worksheetState = ( $worksheet->getExternalSheet()->isVisible() ) ? 'visible' : 'hidden'; + $worksheetId = $worksheet->getId(); - $workbookXmlFileContents .= ''; + $workbookXmlFileContents .= ''; } $workbookXmlFileContents .= <<openFileAndReturnSheets('two_sheets_one_hidden_one_not.xlsx'); + + $this->assertFalse($sheets[0]->isVisible()); + + $this->assertTrue($sheets[1]->isVisible()); + } } diff --git a/tests/Spout/Writer/XLSX/SheetTest.php b/tests/Spout/Writer/XLSX/SheetTest.php index 58c4b05..0c90bd5 100644 --- a/tests/Spout/Writer/XLSX/SheetTest.php +++ b/tests/Spout/Writer/XLSX/SheetTest.php @@ -47,11 +47,12 @@ class SheetTest extends \PHPUnit_Framework_TestCase { $fileName = 'test_set_name_should_create_sheet_with_custom_name.xlsx'; $customSheetName = 'CustomName'; - $this->writeDataAndReturnSheetWithCustomName($fileName, $customSheetName); + $this->writeDataToSheetWithCustomName($fileName, $customSheetName); $this->assertSheetNameEquals($customSheetName, $fileName, "The sheet name should have been changed to '$customSheetName'"); } + /** * @expectedException \Box\Spout\Writer\Exception\InvalidSheetNameException * @return void @@ -75,12 +76,23 @@ class SheetTest extends \PHPUnit_Framework_TestCase $sheet->setName($customSheetName); } + /** + * @return void + */ + public function testSetSheetVisibilityShouldCreateSheetHidden() + { + $fileName = 'test_set_visibility_should_create_sheet_hidden.xlsx'; + $this->writeDataToHiddenSheet($fileName); + + $this->assertIsHiddenSheet( $fileName, "The sheet visibility should have been changed to 'hidden'"); + } + /** * @param string $fileName * @param string $sheetName * @return Sheet */ - private function writeDataAndReturnSheetWithCustomName($fileName, $sheetName) + private function writeDataToSheetWithCustomName($fileName, $sheetName) { $this->createGeneratedFolderIfNeeded($fileName); $resourcePath = $this->getGeneratedResourcePath($fileName); @@ -117,6 +129,25 @@ class SheetTest extends \PHPUnit_Framework_TestCase return $writer->getSheets(); } + /** + * @param string $fileName + * @return void + */ + private function writeDataToHiddenSheet($fileName) + { + $this->createGeneratedFolderIfNeeded($fileName); + $resourcePath = $this->getGeneratedResourcePath($fileName); + + $writer = WriterFactory::create(Type::XLSX); + $writer->openToFile($resourcePath); + + $sheet = $writer->getCurrentSheet(); + $sheet->setIsVisible(false); + + $writer->addRow(['xlsx--11', 'xlsx--12']); + $writer->close(); + } + /** * @param string $expectedName * @param string $fileName @@ -131,4 +162,18 @@ class SheetTest extends \PHPUnit_Framework_TestCase $this->assertContains("getGeneratedResourcePath($fileName); + $pathToWorkbookFile = $resourcePath . '#xl/workbook.xml'; + $xmlContents = file_get_contents('zip://' . $pathToWorkbookFile); + + $this->assertContains(" state=\"hidden\"", $xmlContents, $message); + } } diff --git a/tests/resources/xlsx/two_sheets_one_hidden_one_not.xlsx b/tests/resources/xlsx/two_sheets_one_hidden_one_not.xlsx new file mode 100644 index 0000000..f6d571f Binary files /dev/null and b/tests/resources/xlsx/two_sheets_one_hidden_one_not.xlsx differ