Sheet visibility - XLSX writer and reader

This commit is contained in:
Adrien Loison 2017-11-10 23:45:07 +01:00
parent ddfa40e8b3
commit b9206fcb4b
8 changed files with 102 additions and 8 deletions

View File

@ -53,6 +53,7 @@ class EntityFactory implements EntityFactoryInterface
* @param int $sheetIndex Index of the sheet, based on order in the workbook (zero-based) * @param int $sheetIndex Index of the sheet, based on order in the workbook (zero-based)
* @param string $sheetName Name of the sheet * @param string $sheetName Name of the sheet
* @param bool $isSheetActive Whether the sheet was defined as active * @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 \Box\Spout\Common\Manager\OptionsManagerInterface $optionsManager Reader's options manager
* @param SharedStringsManager $sharedStringsManager Manages shared strings * @param SharedStringsManager $sharedStringsManager Manages shared strings
* @return Sheet * @return Sheet
@ -63,12 +64,13 @@ class EntityFactory implements EntityFactoryInterface
$sheetIndex, $sheetIndex,
$sheetName, $sheetName,
$isSheetActive, $isSheetActive,
$isSheetVisible,
$optionsManager, $optionsManager,
$sharedStringsManager $sharedStringsManager
) { ) {
$rowIterator = $this->createRowIterator($filePath, $sheetDataXMLFilePath, $optionsManager, $sharedStringsManager); $rowIterator = $this->createRowIterator($filePath, $sheetDataXMLFilePath, $optionsManager, $sharedStringsManager);
return new Sheet($rowIterator, $sheetIndex, $sheetName, $isSheetActive); return new Sheet($rowIterator, $sheetIndex, $sheetName, $isSheetActive, $isSheetVisible);
} }
/** /**

View File

@ -29,9 +29,13 @@ class SheetManager
const XML_ATTRIBUTE_ACTIVE_TAB = 'activeTab'; const XML_ATTRIBUTE_ACTIVE_TAB = 'activeTab';
const XML_ATTRIBUTE_R_ID = 'r:id'; const XML_ATTRIBUTE_R_ID = 'r:id';
const XML_ATTRIBUTE_NAME = 'name'; const XML_ATTRIBUTE_NAME = 'name';
const XML_ATTRIBUTE_STATE = 'state';
const XML_ATTRIBUTE_ID = 'Id'; const XML_ATTRIBUTE_ID = 'Id';
const XML_ATTRIBUTE_TARGET = 'Target'; 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 */ /** @var string Path of the XLSX file being read */
protected $filePath; protected $filePath;
@ -163,6 +167,10 @@ class SheetManager
protected function getSheetFromSheetXMLNode($xmlReaderOnSheetNode, $sheetIndexZeroBased, $isSheetActive) protected function getSheetFromSheetXMLNode($xmlReaderOnSheetNode, $sheetIndexZeroBased, $isSheetActive)
{ {
$sheetId = $xmlReaderOnSheetNode->getAttribute(self::XML_ATTRIBUTE_R_ID); $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); $escapedSheetName = $xmlReaderOnSheetNode->getAttribute(self::XML_ATTRIBUTE_NAME);
$sheetName = $this->escaper->unescape($escapedSheetName); $sheetName = $this->escaper->unescape($escapedSheetName);
@ -174,6 +182,7 @@ class SheetManager
$sheetIndexZeroBased, $sheetIndexZeroBased,
$sheetName, $sheetName,
$isSheetActive, $isSheetActive,
$isSheetVisible,
$this->optionsManager, $this->optionsManager,
$this->sharedStringsManager $this->sharedStringsManager
); );

View File

@ -22,18 +22,23 @@ class Sheet implements SheetInterface
/** @var bool Whether the sheet was the active one */ /** @var bool Whether the sheet was the active one */
protected $isActive; protected $isActive;
/** @var bool Whether the sheet is visible */
protected $isVisible;
/** /**
* @param RowIterator $rowIterator The corresponding row iterator * @param RowIterator $rowIterator The corresponding row iterator
* @param int $sheetIndex Index of the sheet, based on order in the workbook (zero-based) * @param int $sheetIndex Index of the sheet, based on order in the workbook (zero-based)
* @param string $sheetName Name of the sheet * @param string $sheetName Name of the sheet
* @param bool $isSheetActive Whether the sheet was defined as active * @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->rowIterator = $rowIterator;
$this->index = $sheetIndex; $this->index = $sheetIndex;
$this->name = $sheetName; $this->name = $sheetName;
$this->isActive = $isSheetActive; $this->isActive = $isSheetActive;
$this->isVisible = $isSheetVisible;
} }
/** /**
@ -67,4 +72,12 @@ class Sheet implements SheetInterface
{ {
return $this->isActive; return $this->isActive;
} }
/**
* @return bool Whether the sheet is visible
*/
public function isVisible()
{
return $this->isVisible;
}
} }

View File

@ -21,6 +21,9 @@ class Sheet
/** @var string Name of the sheet */ /** @var string Name of the sheet */
private $name; private $name;
/** @var bool Visibility of the sheet */
private $isVisible;
/** @var SheetManager Sheet manager */ /** @var SheetManager Sheet manager */
private $sheetManager; private $sheetManager;
@ -38,6 +41,7 @@ class Sheet
$this->sheetManager->markWorkbookIdAsUsed($associatedWorkbookId); $this->sheetManager->markWorkbookIdAsUsed($associatedWorkbookId);
$this->setName(self::DEFAULT_SHEET_NAME_PREFIX . ($sheetIndex + 1)); $this->setName(self::DEFAULT_SHEET_NAME_PREFIX . ($sheetIndex + 1));
$this->setIsVisible(true);
} }
/** /**
@ -85,4 +89,23 @@ class Sheet
return $this; 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;
}
} }

View File

@ -307,8 +307,9 @@ EOD;
/** @var Worksheet $worksheet */ /** @var Worksheet $worksheet */
foreach ($worksheets as $worksheet) { foreach ($worksheets as $worksheet) {
$worksheetName = $worksheet->getExternalSheet()->getName(); $worksheetName = $worksheet->getExternalSheet()->getName();
$worksheetVisibility = $worksheet->getExternalSheet()->isVisible() ? 'visible' : 'hidden';
$worksheetId = $worksheet->getId(); $worksheetId = $worksheet->getId();
$workbookXmlFileContents .= '<sheet name="' . $this->escaper->escape($worksheetName) . '" sheetId="' . $worksheetId . '" r:id="rIdSheet' . $worksheetId . '"/>'; $workbookXmlFileContents .= '<sheet name="' . $this->escaper->escape($worksheetName) . '" sheetId="' . $worksheetId . '" r:id="rIdSheet' . $worksheetId . '" state="' . $worksheetVisibility. '"/>';
} }
$workbookXmlFileContents .= <<<'EOD' $workbookXmlFileContents .= <<<'EOD'

View File

@ -30,6 +30,17 @@ class SheetTest extends \PHPUnit_Framework_TestCase
$this->assertTrue($sheets[1]->isActive()); $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 * @param string $fileName
* @return Sheet[] * @return Sheet[]

View File

@ -22,7 +22,7 @@ class SheetTest extends \PHPUnit_Framework_TestCase
*/ */
public function testGetSheetIndex() 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(2, count($sheets), '2 sheets should have been created');
$this->assertEquals(0, $sheets[0]->getIndex(), 'The first sheet should be index 0'); $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() 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(2, count($sheets), '2 sheets should have been created');
$this->assertEquals('Sheet1', $sheets[0]->getName(), 'Invalid name for the first sheet'); $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'; $fileName = 'test_set_name_should_create_sheet_with_custom_name.xlsx';
$customSheetName = 'CustomName'; $customSheetName = 'CustomName';
$this->writeDataAndReturnSheetWithCustomName($fileName, $customSheetName); $this->writeDataToSheetWithCustomName($fileName, $customSheetName);
$this->assertSheetNameEquals($customSheetName, $fileName, "The sheet name should have been changed to '$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); $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 $fileName
* @param string $sheetName * @param string $sheetName
* @return Sheet * @return Sheet
*/ */
private function writeDataAndReturnSheetWithCustomName($fileName, $sheetName) private function writeDataToSheetWithCustomName($fileName, $sheetName)
{ {
$this->createGeneratedFolderIfNeeded($fileName); $this->createGeneratedFolderIfNeeded($fileName);
$resourcePath = $this->getGeneratedResourcePath($fileName); $resourcePath = $this->getGeneratedResourcePath($fileName);
@ -105,7 +120,7 @@ class SheetTest extends \PHPUnit_Framework_TestCase
* @param string $fileName * @param string $fileName
* @return Sheet[] * @return Sheet[]
*/ */
private function writeDataToMulitpleSheetsAndReturnSheets($fileName) private function writeDataToMultipleSheetsAndReturnSheets($fileName)
{ {
$this->createGeneratedFolderIfNeeded($fileName); $this->createGeneratedFolderIfNeeded($fileName);
$resourcePath = $this->getGeneratedResourcePath($fileName); $resourcePath = $this->getGeneratedResourcePath($fileName);
@ -123,6 +138,26 @@ class SheetTest extends \PHPUnit_Framework_TestCase
return $writer->getSheets(); 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 $expectedName
* @param string $fileName * @param string $fileName