diff --git a/src/Spout/Reader/XLSX/Creator/EntityFactory.php b/src/Spout/Reader/XLSX/Creator/EntityFactory.php index 8699529..8ef648a 100644 --- a/src/Spout/Reader/XLSX/Creator/EntityFactory.php +++ b/src/Spout/Reader/XLSX/Creator/EntityFactory.php @@ -53,6 +53,7 @@ class EntityFactory implements EntityFactoryInterface * @param int $sheetIndex Index of the sheet, based on order in the workbook (zero-based) * @param string $sheetName Name of the sheet * @param bool $isSheetActive Whether the sheet was defined as active + * @param bool $isSheetVisible Whether the sheet is visible * @param \Box\Spout\Common\Manager\OptionsManagerInterface $optionsManager Reader's options manager * @param SharedStringsManager $sharedStringsManager Manages shared strings * @return Sheet @@ -63,12 +64,13 @@ class EntityFactory implements EntityFactoryInterface $sheetIndex, $sheetName, $isSheetActive, + $isSheetVisible, $optionsManager, $sharedStringsManager ) { $rowIterator = $this->createRowIterator($filePath, $sheetDataXMLFilePath, $optionsManager, $sharedStringsManager); - return new Sheet($rowIterator, $sheetIndex, $sheetName, $isSheetActive); + return new Sheet($rowIterator, $sheetIndex, $sheetName, $isSheetActive, $isSheetVisible); } /** diff --git a/src/Spout/Reader/XLSX/Manager/SheetManager.php b/src/Spout/Reader/XLSX/Manager/SheetManager.php index 1dbcc95..ac400e3 100644 --- a/src/Spout/Reader/XLSX/Manager/SheetManager.php +++ b/src/Spout/Reader/XLSX/Manager/SheetManager.php @@ -29,9 +29,13 @@ class SheetManager 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'; + /** State value to represent a hidden sheet */ + const SHEET_STATE_HIDDEN = 'hidden'; + /** @var string Path of the XLSX file being read */ protected $filePath; @@ -163,6 +167,10 @@ class SheetManager protected function getSheetFromSheetXMLNode($xmlReaderOnSheetNode, $sheetIndexZeroBased, $isSheetActive) { $sheetId = $xmlReaderOnSheetNode->getAttribute(self::XML_ATTRIBUTE_R_ID); + + $sheetState = $xmlReaderOnSheetNode->getAttribute(self::XML_ATTRIBUTE_STATE); + $isSheetVisible = ($sheetState !== self::SHEET_STATE_HIDDEN); + $escapedSheetName = $xmlReaderOnSheetNode->getAttribute(self::XML_ATTRIBUTE_NAME); $sheetName = $this->escaper->unescape($escapedSheetName); @@ -174,6 +182,7 @@ class SheetManager $sheetIndexZeroBased, $sheetName, $isSheetActive, + $isSheetVisible, $this->optionsManager, $this->sharedStringsManager ); diff --git a/src/Spout/Reader/XLSX/Sheet.php b/src/Spout/Reader/XLSX/Sheet.php index 592c7c3..575af2d 100644 --- a/src/Spout/Reader/XLSX/Sheet.php +++ b/src/Spout/Reader/XLSX/Sheet.php @@ -22,18 +22,23 @@ class Sheet implements SheetInterface /** @var bool Whether the sheet was the active one */ protected $isActive; + /** @var bool Whether the sheet is visible */ + protected $isVisible; + /** * @param RowIterator $rowIterator The corresponding row iterator * @param int $sheetIndex Index of the sheet, based on order in the workbook (zero-based) * @param string $sheetName Name of the sheet * @param bool $isSheetActive Whether the sheet was defined as active + * @param bool $isSheetVisible Whether the sheet is visible */ - public function __construct($rowIterator, $sheetIndex, $sheetName, $isSheetActive) + public function __construct($rowIterator, $sheetIndex, $sheetName, $isSheetActive, $isSheetVisible) { $this->rowIterator = $rowIterator; $this->index = $sheetIndex; $this->name = $sheetName; $this->isActive = $isSheetActive; + $this->isVisible = $isSheetVisible; } /** @@ -67,4 +72,12 @@ class Sheet implements SheetInterface { return $this->isActive; } + + /** + * @return bool Whether the sheet is visible + */ + public function isVisible() + { + return $this->isVisible; + } } diff --git a/src/Spout/Writer/Common/Entity/Sheet.php b/src/Spout/Writer/Common/Entity/Sheet.php index 5713175..c2f5366 100644 --- a/src/Spout/Writer/Common/Entity/Sheet.php +++ b/src/Spout/Writer/Common/Entity/Sheet.php @@ -21,6 +21,9 @@ class Sheet /** @var string Name of the sheet */ private $name; + /** @var bool Visibility of the sheet */ + private $isVisible; + /** @var SheetManager Sheet manager */ private $sheetManager; @@ -38,6 +41,7 @@ class Sheet $this->sheetManager->markWorkbookIdAsUsed($associatedWorkbookId); $this->setName(self::DEFAULT_SHEET_NAME_PREFIX . ($sheetIndex + 1)); + $this->setIsVisible(true); } /** @@ -85,4 +89,23 @@ class Sheet return $this; } + + /** + * @return bool isVisible Visibility of the sheet + */ + public function isVisible() + { + return $this->isVisible; + } + + /** + * @param bool $isVisible Visibility of the sheet + * @return Sheet + */ + public function setIsVisible($isVisible) + { + $this->isVisible = $isVisible; + + return $this; + } } diff --git a/src/Spout/Writer/XLSX/Helper/FileSystemHelper.php b/src/Spout/Writer/XLSX/Helper/FileSystemHelper.php index 8bba670..06d5481 100644 --- a/src/Spout/Writer/XLSX/Helper/FileSystemHelper.php +++ b/src/Spout/Writer/XLSX/Helper/FileSystemHelper.php @@ -307,8 +307,9 @@ EOD; /** @var Worksheet $worksheet */ foreach ($worksheets as $worksheet) { $worksheetName = $worksheet->getExternalSheet()->getName(); + $worksheetVisibility = $worksheet->getExternalSheet()->isVisible() ? 'visible' : 'hidden'; $worksheetId = $worksheet->getId(); - $workbookXmlFileContents .= ''; + $workbookXmlFileContents .= ''; } $workbookXmlFileContents .= <<<'EOD' diff --git a/tests/Spout/Reader/XLSX/SheetTest.php b/tests/Spout/Reader/XLSX/SheetTest.php index b4291fb..96eee4a 100644 --- a/tests/Spout/Reader/XLSX/SheetTest.php +++ b/tests/Spout/Reader/XLSX/SheetTest.php @@ -30,6 +30,17 @@ class SheetTest extends \PHPUnit_Framework_TestCase $this->assertTrue($sheets[1]->isActive()); } + /** + * @return void + */ + public function testReaderShouldReturnCorrectSheetVisibility() + { + $sheets = $this->openFileAndReturnSheets('two_sheets_one_hidden_one_not.xlsx'); + + $this->assertFalse($sheets[0]->isVisible()); + $this->assertTrue($sheets[1]->isVisible()); + } + /** * @param string $fileName * @return Sheet[] diff --git a/tests/Spout/Writer/XLSX/SheetTest.php b/tests/Spout/Writer/XLSX/SheetTest.php index ec636ad..64b276b 100644 --- a/tests/Spout/Writer/XLSX/SheetTest.php +++ b/tests/Spout/Writer/XLSX/SheetTest.php @@ -22,7 +22,7 @@ class SheetTest extends \PHPUnit_Framework_TestCase */ public function testGetSheetIndex() { - $sheets = $this->writeDataToMulitpleSheetsAndReturnSheets('test_get_sheet_index.xlsx'); + $sheets = $this->writeDataToMultipleSheetsAndReturnSheets('test_get_sheet_index.xlsx'); $this->assertEquals(2, count($sheets), '2 sheets should have been created'); $this->assertEquals(0, $sheets[0]->getIndex(), 'The first sheet should be index 0'); @@ -34,7 +34,7 @@ class SheetTest extends \PHPUnit_Framework_TestCase */ public function testGetSheetName() { - $sheets = $this->writeDataToMulitpleSheetsAndReturnSheets('test_get_sheet_name.xlsx'); + $sheets = $this->writeDataToMultipleSheetsAndReturnSheets('test_get_sheet_name.xlsx'); $this->assertEquals(2, count($sheets), '2 sheets should have been created'); $this->assertEquals('Sheet1', $sheets[0]->getName(), 'Invalid name for the first sheet'); @@ -48,7 +48,7 @@ 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'"); } @@ -78,12 +78,27 @@ 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); + + $resourcePath = $this->getGeneratedResourcePath($fileName); + $pathToWorkbookFile = $resourcePath . '#xl/workbook.xml'; + $xmlContents = file_get_contents('zip://' . $pathToWorkbookFile); + + $this->assertContains(" state=\"hidden\"", $xmlContents, '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); @@ -105,7 +120,7 @@ class SheetTest extends \PHPUnit_Framework_TestCase * @param string $fileName * @return Sheet[] */ - private function writeDataToMulitpleSheetsAndReturnSheets($fileName) + private function writeDataToMultipleSheetsAndReturnSheets($fileName) { $this->createGeneratedFolderIfNeeded($fileName); $resourcePath = $this->getGeneratedResourcePath($fileName); @@ -123,6 +138,26 @@ 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); + + /** @var \Box\Spout\Writer\XLSX\Writer $writer */ + $writer = EntityFactory::createWriter(Type::XLSX); + $writer->openToFile($resourcePath); + + $sheet = $writer->getCurrentSheet(); + $sheet->setIsVisible(false); + + $writer->addRow($this->createRowFromValues(['xlsx--11', 'xlsx--12'])); + $writer->close(); + } + /** * @param string $expectedName * @param string $fileName 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