Tests Added 'addOption' to OptionsManagerInterface Moved 'setColumnWidths' and 'mergeCells' methods to Xlsx Writer implementation since the actual feature only works for Xlsx at the moment
783 lines
27 KiB
PHP
783 lines
27 KiB
PHP
<?php
|
|
|
|
namespace Box\Spout\Writer\XLSX;
|
|
|
|
use Box\Spout\Common\Entity\Cell;
|
|
use Box\Spout\Common\Entity\Row;
|
|
use Box\Spout\Common\Exception\InvalidArgumentException;
|
|
use Box\Spout\Common\Exception\IOException;
|
|
use Box\Spout\Common\Exception\SpoutException;
|
|
use Box\Spout\Reader\Wrapper\XMLReader;
|
|
use Box\Spout\TestUsingResource;
|
|
use Box\Spout\Writer\Common\Creator\WriterEntityFactory;
|
|
use Box\Spout\Writer\Exception\WriterAlreadyOpenedException;
|
|
use Box\Spout\Writer\Exception\WriterNotOpenedException;
|
|
use Box\Spout\Writer\RowCreationHelper;
|
|
use Box\Spout\Writer\XLSX\Manager\WorksheetManager;
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
/**
|
|
* Class WriterTest
|
|
*/
|
|
class WriterTest extends TestCase
|
|
{
|
|
use TestUsingResource;
|
|
use RowCreationHelper;
|
|
|
|
/**
|
|
* @return void
|
|
*/
|
|
public function testAddRowShouldThrowExceptionIfCannotOpenAFileForWriting()
|
|
{
|
|
$this->expectException(IOException::class);
|
|
|
|
$fileName = 'file_that_wont_be_written.xlsx';
|
|
$this->createUnwritableFolderIfNeeded();
|
|
$filePath = $this->getGeneratedUnwritableResourcePath($fileName);
|
|
|
|
$writer = WriterEntityFactory::createXLSXWriter();
|
|
@$writer->openToFile($filePath);
|
|
}
|
|
|
|
/**
|
|
* @return void
|
|
*/
|
|
public function testAddRowShouldThrowExceptionIfCallAddRowBeforeOpeningWriter()
|
|
{
|
|
$this->expectException(WriterNotOpenedException::class);
|
|
|
|
$writer = WriterEntityFactory::createXLSXWriter();
|
|
$writer->addRow($this->createRowFromValues(['xlsx--11', 'xlsx--12']));
|
|
}
|
|
|
|
/**
|
|
* @return void
|
|
*/
|
|
public function testAddRowShouldThrowExceptionIfCalledBeforeOpeningWriter()
|
|
{
|
|
$this->expectException(WriterNotOpenedException::class);
|
|
|
|
$writer = WriterEntityFactory::createXLSXWriter();
|
|
$writer->addRows($this->createRowsFromValues([['xlsx--11', 'xlsx--12']]));
|
|
}
|
|
|
|
/**
|
|
* @return void
|
|
*/
|
|
public function testSetTempFolderShouldThrowExceptionIfCalledAfterOpeningWriter()
|
|
{
|
|
$this->expectException(WriterAlreadyOpenedException::class);
|
|
|
|
$fileName = 'file_that_wont_be_written.xlsx';
|
|
$filePath = $this->getGeneratedResourcePath($fileName);
|
|
|
|
$writer = WriterEntityFactory::createXLSXWriter();
|
|
$writer->openToFile($filePath);
|
|
|
|
$writer->setTempFolder('');
|
|
}
|
|
|
|
/**
|
|
* @return void
|
|
*/
|
|
public function testSetShouldUseInlineStringsShouldThrowExceptionIfCalledAfterOpeningWriter()
|
|
{
|
|
$this->expectException(WriterAlreadyOpenedException::class);
|
|
|
|
$fileName = 'file_that_wont_be_written.xlsx';
|
|
$filePath = $this->getGeneratedResourcePath($fileName);
|
|
|
|
$writer = WriterEntityFactory::createXLSXWriter();
|
|
$writer->openToFile($filePath);
|
|
|
|
$writer->setShouldUseInlineStrings(true);
|
|
}
|
|
|
|
/**
|
|
* @return void
|
|
*/
|
|
public function testsetShouldCreateNewSheetsAutomaticallyShouldThrowExceptionIfCalledAfterOpeningWriter()
|
|
{
|
|
$this->expectException(WriterAlreadyOpenedException::class);
|
|
|
|
$fileName = 'file_that_wont_be_written.xlsx';
|
|
$filePath = $this->getGeneratedResourcePath($fileName);
|
|
|
|
$writer = WriterEntityFactory::createXLSXWriter();
|
|
$writer->openToFile($filePath);
|
|
|
|
$writer->setShouldCreateNewSheetsAutomatically(true);
|
|
}
|
|
|
|
/**
|
|
* @return void
|
|
*/
|
|
public function testAddRowShouldThrowExceptionIfUnsupportedDataTypePassedIn()
|
|
{
|
|
$this->expectException(InvalidArgumentException::class);
|
|
|
|
$fileName = 'test_add_row_should_throw_exception_if_unsupported_data_type_passed_in.xlsx';
|
|
$dataRows = [
|
|
[str_repeat('a', WorksheetManager::MAX_CHARACTERS_PER_CELL + 1)],
|
|
];
|
|
|
|
$this->writeToXLSXFile($dataRows, $fileName);
|
|
}
|
|
|
|
/**
|
|
* @return void
|
|
*/
|
|
public function testAddRowShouldThrowExceptionIfWritingStringExceedingMaxNumberOfCharactersAllowedPerCell()
|
|
{
|
|
$this->expectException(InvalidArgumentException::class);
|
|
|
|
$fileName = 'test_add_row_should_throw_exception_if_string_exceeds_max_num_chars_allowed_per_cell.xlsx';
|
|
$dataRows = $this->createRowsFromValues([
|
|
[new \stdClass()],
|
|
]);
|
|
|
|
$this->writeToXLSXFile($dataRows, $fileName);
|
|
}
|
|
|
|
/**
|
|
* @return void
|
|
*/
|
|
public function testAddRowShouldCleanupAllFilesIfExceptionIsThrown()
|
|
{
|
|
$fileName = 'test_add_row_should_cleanup_all_files_if_exception_thrown.xlsx';
|
|
$dataRows = $this->createRowsFromValues([
|
|
['wrong'],
|
|
[new \stdClass()],
|
|
]);
|
|
|
|
$this->createGeneratedFolderIfNeeded($fileName);
|
|
$resourcePath = $this->getGeneratedResourcePath($fileName);
|
|
|
|
$this->recreateTempFolder();
|
|
$tempFolderPath = $this->getTempFolderPath();
|
|
|
|
$writer = WriterEntityFactory::createXLSXWriter();
|
|
$writer->setTempFolder($tempFolderPath);
|
|
$writer->openToFile($resourcePath);
|
|
|
|
try {
|
|
$writer->addRows($dataRows);
|
|
$this->fail('Exception should have been thrown');
|
|
} catch (SpoutException $e) {
|
|
$this->assertFileNotExists($fileName, 'Output file should have been deleted');
|
|
|
|
$numFiles = iterator_count(new \FilesystemIterator($tempFolderPath, \FilesystemIterator::SKIP_DOTS));
|
|
$this->assertEquals(0, $numFiles, 'All temp files should have been deleted');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return void
|
|
*/
|
|
public function testAddNewSheetAndMakeItCurrent()
|
|
{
|
|
$fileName = 'test_add_new_sheet_and_make_it_current.xlsx';
|
|
$this->createGeneratedFolderIfNeeded($fileName);
|
|
$resourcePath = $this->getGeneratedResourcePath($fileName);
|
|
|
|
$writer = WriterEntityFactory::createXLSXWriter();
|
|
$writer->openToFile($resourcePath);
|
|
$writer->addNewSheetAndMakeItCurrent();
|
|
$writer->close();
|
|
|
|
$sheets = $writer->getSheets();
|
|
$this->assertCount(2, $sheets, 'There should be 2 sheets');
|
|
$this->assertEquals($sheets[1], $writer->getCurrentSheet(), 'The current sheet should be the second one.');
|
|
}
|
|
|
|
/**
|
|
* @return void
|
|
*/
|
|
public function testSetCurrentSheet()
|
|
{
|
|
$fileName = 'test_set_current_sheet.xlsx';
|
|
$this->createGeneratedFolderIfNeeded($fileName);
|
|
$resourcePath = $this->getGeneratedResourcePath($fileName);
|
|
|
|
$writer = WriterEntityFactory::createXLSXWriter();
|
|
$writer->openToFile($resourcePath);
|
|
|
|
$writer->addNewSheetAndMakeItCurrent();
|
|
$writer->addNewSheetAndMakeItCurrent();
|
|
|
|
$firstSheet = $writer->getSheets()[0];
|
|
$writer->setCurrentSheet($firstSheet);
|
|
|
|
$writer->close();
|
|
|
|
$this->assertEquals($firstSheet, $writer->getCurrentSheet(), 'The current sheet should be the first one.');
|
|
}
|
|
|
|
/**
|
|
* @return void
|
|
*/
|
|
public function testCloseShouldNoopWhenWriterIsNotOpened()
|
|
{
|
|
$fileName = 'test_double_close_calls.xlsx';
|
|
$this->createGeneratedFolderIfNeeded($fileName);
|
|
$resourcePath = $this->getGeneratedResourcePath($fileName);
|
|
|
|
$writer = WriterEntityFactory::createXLSXWriter();
|
|
$writer->close(); // This call should not cause any error
|
|
|
|
$writer->openToFile($resourcePath);
|
|
$writer->close();
|
|
$writer->close(); // This call should not cause any error
|
|
$this->expectNotToPerformAssertions();
|
|
}
|
|
|
|
/**
|
|
* @return void
|
|
*/
|
|
public function testAddRowShouldWriteGivenDataToSheetUsingInlineStrings()
|
|
{
|
|
$fileName = 'test_add_row_should_write_given_data_to_sheet_using_inline_strings.xlsx';
|
|
$dataRows = $this->createRowsFromValues([
|
|
['xlsx--11', 'xlsx--12'],
|
|
['xlsx--21', 'xlsx--22', 'xlsx--23'],
|
|
]);
|
|
|
|
$this->writeToXLSXFile($dataRows, $fileName, $shouldUseInlineStrings = true);
|
|
|
|
foreach ($dataRows as $dataRow) {
|
|
foreach ($dataRow->getCells() as $cell) {
|
|
$this->assertInlineDataWasWrittenToSheet($fileName, 1, $cell->getValue());
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return void
|
|
*/
|
|
public function testAddRowShouldWriteGivenDataToTwoSheetsUsingInlineStrings()
|
|
{
|
|
$fileName = 'test_add_row_should_write_given_data_to_two_sheets_using_inline_strings.xlsx';
|
|
$dataRows = $this->createRowsFromValues([
|
|
['xlsx--11', 'xlsx--12'],
|
|
['xlsx--21', 'xlsx--22', 'xlsx--23'],
|
|
]);
|
|
|
|
$numSheets = 2;
|
|
$this->writeToMultipleSheetsInXLSXFile($dataRows, $numSheets, $fileName, $shouldUseInlineStrings = true);
|
|
|
|
for ($i = 1; $i <= $numSheets; $i++) {
|
|
foreach ($dataRows as $dataRow) {
|
|
foreach ($dataRow->getCells() as $cell) {
|
|
$this->assertInlineDataWasWrittenToSheet($fileName, $numSheets, $cell->getValue());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return void
|
|
*/
|
|
public function testAddRowShouldWriteGivenDataToSheetUsingSharedStrings()
|
|
{
|
|
$fileName = 'test_add_row_should_write_given_data_to_sheet_using_shared_strings.xlsx';
|
|
$dataRows = $this->createRowsFromValues([
|
|
['xlsx--11', 'xlsx--12'],
|
|
['xlsx--21', 'xlsx--22', 'xlsx--23'],
|
|
]);
|
|
|
|
$this->writeToXLSXFile($dataRows, $fileName, $shouldUseInlineStrings = false);
|
|
|
|
foreach ($dataRows as $dataRow) {
|
|
foreach ($dataRow->getCells() as $cell) {
|
|
$this->assertSharedStringWasWritten($fileName, $cell->getValue());
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return void
|
|
*/
|
|
public function testAddRowShouldWriteGivenDataToTwoSheetsUsingSharedStrings()
|
|
{
|
|
$fileName = 'test_add_row_should_write_given_data_to_two_sheets_using_shared_strings.xlsx';
|
|
$dataRows = $this->createRowsFromValues([
|
|
['xlsx--11', 'xlsx--12'],
|
|
['xlsx--21', 'xlsx--22', 'xlsx--23'],
|
|
]);
|
|
|
|
$numSheets = 2;
|
|
$this->writeToMultipleSheetsInXLSXFile($dataRows, $numSheets, $fileName, $shouldUseInlineStrings = false);
|
|
|
|
for ($i = 1; $i <= $numSheets; $i++) {
|
|
foreach ($dataRows as $dataRow) {
|
|
foreach ($dataRow->getCells() as $cell) {
|
|
$this->assertSharedStringWasWritten($fileName, $cell->getValue());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return void
|
|
*/
|
|
public function testAddRowShouldSupportAssociativeArrays()
|
|
{
|
|
$fileName = 'test_add_row_should_support_associative_arrays.xlsx';
|
|
$dataRows = $this->createRowsFromValues([
|
|
['foo' => 'xlsx--11', 'bar' => 'xlsx--12'],
|
|
]);
|
|
|
|
$this->writeToXLSXFile($dataRows, $fileName);
|
|
|
|
foreach ($dataRows as $dataRow) {
|
|
foreach ($dataRow->getCells() as $cell) {
|
|
$this->assertInlineDataWasWrittenToSheet($fileName, 1, $cell->getValue());
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return void
|
|
*/
|
|
public function testAddRowShouldNotWriteEmptyRows()
|
|
{
|
|
$fileName = 'test_add_row_should_not_write_empty_rows.xlsx';
|
|
$dataRows = $this->createRowsFromValues([
|
|
[''],
|
|
['xlsx--21', 'xlsx--22'],
|
|
['key' => ''],
|
|
[''],
|
|
['xlsx--51', 'xlsx--52'],
|
|
]);
|
|
|
|
$this->writeToXLSXFile($dataRows, $fileName);
|
|
|
|
$this->assertInlineDataWasWrittenToSheet($fileName, 1, 'row r="2"');
|
|
$this->assertInlineDataWasWrittenToSheet($fileName, 1, 'row r="5"');
|
|
$this->assertInlineDataWasNotWrittenToSheet($fileName, 1, 'row r="1"');
|
|
$this->assertInlineDataWasNotWrittenToSheet($fileName, 1, 'row r="3"');
|
|
$this->assertInlineDataWasNotWrittenToSheet($fileName, 1, 'row r="4"');
|
|
}
|
|
|
|
/**
|
|
* @return void
|
|
*/
|
|
public function testAddRowShouldSupportMultipleTypesOfData()
|
|
{
|
|
$fileName = 'test_add_row_should_support_multiple_types_of_data.xlsx';
|
|
$dataRows = $this->createRowsFromValues([
|
|
['xlsx--11', true, '', 0, 10.2, null],
|
|
]);
|
|
|
|
$this->writeToXLSXFile($dataRows, $fileName, $shouldUseInlineStrings = false);
|
|
|
|
$this->assertSharedStringWasWritten($fileName, 'xlsx--11');
|
|
$this->assertInlineDataWasWrittenToSheet($fileName, 1, 1); // true is converted to 1
|
|
$this->assertInlineDataWasWrittenToSheet($fileName, 1, 0);
|
|
$this->assertInlineDataWasWrittenToSheet($fileName, 1, 10.2);
|
|
}
|
|
|
|
/**
|
|
* @return void
|
|
*/
|
|
public function testAddRowShouldSupportCellInError()
|
|
{
|
|
$fileName = 'test_add_row_should_support_cell_in_error.xlsx';
|
|
|
|
$cell = WriterEntityFactory::createCell('#DIV/0');
|
|
$cell->setType(Cell::TYPE_ERROR);
|
|
|
|
$row = WriterEntityFactory::createRow([$cell]);
|
|
|
|
$this->writeToXLSXFile([$row], $fileName);
|
|
|
|
$this->assertInlineDataWasWrittenToSheet($fileName, 1, 't="e"><v>#DIV/0</v>');
|
|
}
|
|
|
|
/**
|
|
* @return void
|
|
*/
|
|
public function testAddRowShouldWriteGivenDataToTheCorrectSheet()
|
|
{
|
|
$fileName = 'test_add_row_should_write_given_data_to_the_correct_sheet.xlsx';
|
|
$dataRowsSheet1 = $this->createRowsFromValues([
|
|
['xlsx--sheet1--11', 'xlsx--sheet1--12'],
|
|
['xlsx--sheet1--21', 'xlsx--sheet1--22', 'xlsx--sheet1--23'],
|
|
]);
|
|
$dataRowsSheet2 = $this->createRowsFromValues([
|
|
['xlsx--sheet2--11', 'xlsx--sheet2--12'],
|
|
['xlsx--sheet2--21', 'xlsx--sheet2--22', 'xlsx--sheet2--23'],
|
|
]);
|
|
$dataRowsSheet1Again = $this->createRowsFromValues([
|
|
['xlsx--sheet1--31', 'xlsx--sheet1--32'],
|
|
['xlsx--sheet1--41', 'xlsx--sheet1--42', 'xlsx--sheet1--43'],
|
|
]);
|
|
|
|
$this->createGeneratedFolderIfNeeded($fileName);
|
|
$resourcePath = $this->getGeneratedResourcePath($fileName);
|
|
|
|
$writer = WriterEntityFactory::createXLSXWriter();
|
|
$writer->setShouldUseInlineStrings(true);
|
|
|
|
$writer->openToFile($resourcePath);
|
|
|
|
$writer->addRows($dataRowsSheet1);
|
|
|
|
$writer->addNewSheetAndMakeItCurrent();
|
|
$writer->addRows($dataRowsSheet2);
|
|
|
|
$firstSheet = $writer->getSheets()[0];
|
|
$writer->setCurrentSheet($firstSheet);
|
|
|
|
$writer->addRows($dataRowsSheet1Again);
|
|
|
|
$writer->close();
|
|
|
|
foreach ($dataRowsSheet1 as $dataRow) {
|
|
foreach ($dataRow->getCells() as $cell) {
|
|
$this->assertInlineDataWasWrittenToSheet($fileName, 1, $cell->getValue(), 'Data should have been written in Sheet 1');
|
|
}
|
|
}
|
|
foreach ($dataRowsSheet2 as $dataRow) {
|
|
foreach ($dataRow->getCells() as $cell) {
|
|
$this->assertInlineDataWasWrittenToSheet($fileName, 2, $cell->getValue(), 'Data should have been written in Sheet 2');
|
|
}
|
|
}
|
|
foreach ($dataRowsSheet1Again as $dataRow) {
|
|
foreach ($dataRow->getCells() as $cell) {
|
|
$this->assertInlineDataWasWrittenToSheet($fileName, 1, $cell->getValue(), 'Data should have been written in Sheet 1');
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return void
|
|
*/
|
|
public function testAddRowShouldAutomaticallyCreateNewSheetsIfMaxRowsReachedAndOptionTurnedOn()
|
|
{
|
|
$fileName = 'test_add_row_should_automatically_create_new_sheets_if_max_rows_reached_and_option_turned_on.xlsx';
|
|
$dataRows = $this->createRowsFromValues([
|
|
['xlsx--sheet1--11', 'xlsx--sheet1--12'],
|
|
['xlsx--sheet1--21', 'xlsx--sheet1--22', 'xlsx--sheet1--23'],
|
|
['xlsx--sheet2--11', 'xlsx--sheet2--12'], // this should be written in a new sheet
|
|
]);
|
|
|
|
// set the maxRowsPerSheet limit to 2
|
|
\ReflectionHelper::setStaticValue('\Box\Spout\Writer\XLSX\Manager\WorkbookManager', 'maxRowsPerWorksheet', 2);
|
|
|
|
$writer = $this->writeToXLSXFile($dataRows, $fileName, true, $shouldCreateSheetsAutomatically = true);
|
|
$this->assertCount(2, $writer->getSheets(), '2 sheets should have been created.');
|
|
|
|
$this->assertInlineDataWasNotWrittenToSheet($fileName, 1, 'xlsx--sheet2--11');
|
|
$this->assertInlineDataWasWrittenToSheet($fileName, 2, 'xlsx--sheet2--11');
|
|
|
|
\ReflectionHelper::reset();
|
|
}
|
|
|
|
/**
|
|
* @return void
|
|
*/
|
|
public function testAddRowShouldNotCreateNewSheetsIfMaxRowsReachedAndOptionTurnedOff()
|
|
{
|
|
$fileName = 'test_add_row_should_not_create_new_sheets_if_max_rows_reached_and_option_turned_off.xlsx';
|
|
$dataRows = $this->createRowsFromValues([
|
|
['xlsx--sheet1--11', 'xlsx--sheet1--12'],
|
|
['xlsx--sheet1--21', 'xlsx--sheet1--22', 'xlsx--sheet1--23'],
|
|
['xlsx--sheet1--31', 'xlsx--sheet1--32'], // this should NOT be written in a new sheet
|
|
]);
|
|
|
|
// set the maxRowsPerSheet limit to 2
|
|
\ReflectionHelper::setStaticValue('\Box\Spout\Writer\XLSX\Manager\WorkbookManager', 'maxRowsPerWorksheet', 2);
|
|
|
|
$writer = $this->writeToXLSXFile($dataRows, $fileName, true, $shouldCreateSheetsAutomatically = false);
|
|
$this->assertCount(1, $writer->getSheets(), 'Only 1 sheet should have been created.');
|
|
|
|
$this->assertInlineDataWasNotWrittenToSheet($fileName, 1, 'xlsx--sheet1--31');
|
|
|
|
\ReflectionHelper::reset();
|
|
}
|
|
|
|
/**
|
|
* @return void
|
|
*/
|
|
public function testAddRowShouldEscapeHtmlSpecialCharacters()
|
|
{
|
|
$fileName = 'test_add_row_should_escape_html_special_characters.xlsx';
|
|
$dataRows = $this->createRowsFromValues([
|
|
['I\'m in "great" mood', 'This <must> be escaped & tested'],
|
|
]);
|
|
|
|
$this->writeToXLSXFile($dataRows, $fileName);
|
|
|
|
$this->assertInlineDataWasWrittenToSheet($fileName, 1, 'I'm in "great" mood', 'Quotes should be escaped');
|
|
$this->assertInlineDataWasWrittenToSheet($fileName, 1, 'This <must> be escaped & tested', '<, > and & should be escaped');
|
|
}
|
|
|
|
/**
|
|
* @return void
|
|
*/
|
|
public function testAddRowShouldEscapeControlCharacters()
|
|
{
|
|
$fileName = 'test_add_row_should_escape_control_characters.xlsx';
|
|
$dataRows = $this->createRowsFromValues([
|
|
['control ' . chr(21) . ' character'],
|
|
]);
|
|
|
|
$this->writeToXLSXFile($dataRows, $fileName);
|
|
|
|
$this->assertInlineDataWasWrittenToSheet($fileName, 1, 'control _x0015_ character');
|
|
}
|
|
|
|
/**
|
|
* @return void
|
|
*/
|
|
public function testAddRowShouldSupportRowHeights()
|
|
{
|
|
$fileName = 'test_add_row_should_support_row_heights.xlsx';
|
|
$dataRows = $this->createRowsFromValues([
|
|
['First row with default height'],
|
|
['Second row with custom height'],
|
|
]);
|
|
|
|
$dataRows[1]->setHeight('23');
|
|
|
|
$this->writeToXLSXFile($dataRows, $fileName);
|
|
$firstRow = $this->getXmlRowFromXmlFile($fileName, 1, 1);
|
|
$secondRow = $this->getXmlRowFromXmlFile($fileName, 1, 2);
|
|
$this->assertEquals('15', $firstRow->getAttribute('ht'), '1st row does not have default height.');
|
|
$this->assertEquals('23', $secondRow->getAttribute('ht'), '2nd row does not have custom height.');
|
|
}
|
|
|
|
/**
|
|
* @return void
|
|
*/
|
|
public function testAddRowShouldSupportColumnWidths()
|
|
{
|
|
$fileName = 'test_add_row_should_support_column_widths.xlsx';
|
|
$this->createGeneratedFolderIfNeeded($fileName);
|
|
$resourcePath = $this->getGeneratedResourcePath($fileName);
|
|
$writer = WriterEntityFactory::createXLSXWriter();
|
|
$writer->setShouldUseInlineStrings(true);
|
|
$writer->openToFile($resourcePath);
|
|
|
|
$columnWidths = [1, 2, 3, 4];
|
|
$writer->setColumnWidths($columnWidths);
|
|
$writer->addRows($this->createRowsFromValues([
|
|
['Test cell'],
|
|
]));
|
|
$writer->close();
|
|
|
|
$xmlReader = $this->getXmlReaderForSheetFromXmlFile($fileName, 1);
|
|
$xmlReader->readUntilNodeFound('cols');
|
|
$this->assertEquals('cols', $xmlReader->getCurrentNodeName(), 'Sheet does not have cols tag');
|
|
$this->assertEquals(count($columnWidths), $xmlReader->expand()->childNodes->length, 'Sheet does not have the specified number of column definitions');
|
|
foreach ($columnWidths as $index => $columnWidth) {
|
|
$xmlReader->readUntilNodeFound('col');
|
|
$this->assertEquals($index + 1, $xmlReader->expand()->getAttribute('min'));
|
|
$this->assertEquals($index + 1, $xmlReader->expand()->getAttribute('max'));
|
|
$this->assertEquals($columnWidth, $xmlReader->expand()->getAttribute('width'));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return void
|
|
*/
|
|
public function testCloseShouldAddMergeCellTags()
|
|
{
|
|
$fileName = 'test_add_row_should_support_column_widths.xlsx';
|
|
$this->createGeneratedFolderIfNeeded($fileName);
|
|
$resourcePath = $this->getGeneratedResourcePath($fileName);
|
|
$writer = WriterEntityFactory::createXLSXWriter();
|
|
$writer->setShouldUseInlineStrings(true);
|
|
$writer->openToFile($resourcePath);
|
|
|
|
$writer->mergeCells([0, 1], [3, 1]);
|
|
$writer->mergeCells([2, 3], [10, 3]);
|
|
$writer->close();
|
|
|
|
$xmlReader = $this->getXmlReaderForSheetFromXmlFile($fileName, 1);
|
|
$xmlReader->readUntilNodeFound('mergeCells');
|
|
$this->assertEquals('mergeCells', $xmlReader->getCurrentNodeName(), 'Sheet does not have mergeCells tag');
|
|
$this->assertEquals(2, $xmlReader->expand()->childNodes->length, 'Sheet does not have the specified number of mergeCell definitions');
|
|
$xmlReader->readUntilNodeFound('mergeCell');
|
|
$this->assertEquals('A1:D1', $xmlReader->expand()->getAttribute('ref'), 'Merge ref for first range is not valid.');
|
|
$xmlReader->readUntilNodeFound('mergeCell');
|
|
$this->assertEquals('C3:K3', $xmlReader->expand()->getAttribute('ref'), 'Merge ref for second range is not valid.');
|
|
}
|
|
|
|
/**
|
|
* @return void
|
|
*/
|
|
public function testGeneratedFileShouldBeValidForEmptySheets()
|
|
{
|
|
$fileName = 'test_empty_sheet.xlsx';
|
|
$this->createGeneratedFolderIfNeeded($fileName);
|
|
$resourcePath = $this->getGeneratedResourcePath($fileName);
|
|
$writer = WriterEntityFactory::createXLSXWriter();
|
|
$writer->openToFile($resourcePath);
|
|
|
|
$writer->addNewSheetAndMakeItCurrent();
|
|
$writer->close();
|
|
|
|
$xmlReader = $this->getXmlReaderForSheetFromXmlFile($fileName, 1);
|
|
$xmlReader->setParserProperty(XMLReader::VALIDATE, true);
|
|
$this->assertTrue($xmlReader->isValid(), 'worksheet xml is not valid');
|
|
$xmlReader->setParserProperty(XMLReader::VALIDATE, false);
|
|
$xmlReader->readUntilNodeFound('sheetData');
|
|
$this->assertEquals('sheetData', $xmlReader->getCurrentNodeName(), 'worksheet xml does not have sheetData');
|
|
}
|
|
|
|
/**
|
|
* @return void
|
|
*/
|
|
public function testGeneratedFileShouldHaveTheCorrectMimeType()
|
|
{
|
|
$fileName = 'test_mime_type.xlsx';
|
|
$resourcePath = $this->getGeneratedResourcePath($fileName);
|
|
$dataRows = $this->createRowsFromValues([['foo']]);
|
|
|
|
$this->writeToXLSXFile($dataRows, $fileName);
|
|
|
|
$finfo = new \finfo(FILEINFO_MIME_TYPE);
|
|
$this->assertEquals('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', $finfo->file($resourcePath));
|
|
}
|
|
|
|
/**
|
|
* @param Row[] $allRows
|
|
* @param string $fileName
|
|
* @param bool $shouldUseInlineStrings
|
|
* @param bool $shouldCreateSheetsAutomatically
|
|
* @return Writer
|
|
*/
|
|
private function writeToXLSXFile($allRows, $fileName, $shouldUseInlineStrings = true, $shouldCreateSheetsAutomatically = true)
|
|
{
|
|
$this->createGeneratedFolderIfNeeded($fileName);
|
|
$resourcePath = $this->getGeneratedResourcePath($fileName);
|
|
|
|
$writer = WriterEntityFactory::createXLSXWriter();
|
|
$writer->setShouldUseInlineStrings($shouldUseInlineStrings);
|
|
$writer->setShouldCreateNewSheetsAutomatically($shouldCreateSheetsAutomatically);
|
|
|
|
$writer->openToFile($resourcePath);
|
|
$writer->addRows($allRows);
|
|
$writer->close();
|
|
|
|
return $writer;
|
|
}
|
|
|
|
/**
|
|
* @param Row[] $allRows
|
|
* @param int $numSheets
|
|
* @param string $fileName
|
|
* @param bool $shouldUseInlineStrings
|
|
* @param bool $shouldCreateSheetsAutomatically
|
|
* @return Writer
|
|
*/
|
|
private function writeToMultipleSheetsInXLSXFile($allRows, $numSheets, $fileName, $shouldUseInlineStrings = true, $shouldCreateSheetsAutomatically = true)
|
|
{
|
|
$this->createGeneratedFolderIfNeeded($fileName);
|
|
$resourcePath = $this->getGeneratedResourcePath($fileName);
|
|
|
|
$writer = WriterEntityFactory::createXLSXWriter();
|
|
$writer->setShouldUseInlineStrings($shouldUseInlineStrings);
|
|
$writer->setShouldCreateNewSheetsAutomatically($shouldCreateSheetsAutomatically);
|
|
|
|
$writer->openToFile($resourcePath);
|
|
$writer->addRows($allRows);
|
|
|
|
for ($i = 1; $i < $numSheets; $i++) {
|
|
$writer->addNewSheetAndMakeItCurrent();
|
|
$writer->addRows($allRows);
|
|
}
|
|
|
|
$writer->close();
|
|
|
|
return $writer;
|
|
}
|
|
|
|
/**
|
|
* @param string $fileName
|
|
* @param int $sheetIndex
|
|
* @param mixed $inlineData
|
|
* @param string $message
|
|
* @return void
|
|
*/
|
|
private function assertInlineDataWasWrittenToSheet($fileName, $sheetIndex, $inlineData, $message = '')
|
|
{
|
|
$resourcePath = $this->getGeneratedResourcePath($fileName);
|
|
$pathToSheetFile = $resourcePath . '#xl/worksheets/sheet' . $sheetIndex . '.xml';
|
|
$xmlContents = file_get_contents('zip://' . $pathToSheetFile);
|
|
|
|
$this->assertContains((string) $inlineData, $xmlContents, $message);
|
|
}
|
|
|
|
/**
|
|
* @param string $fileName
|
|
* @param int $sheetIndex
|
|
* @param mixed $inlineData
|
|
* @param string $message
|
|
* @return void
|
|
*/
|
|
private function assertInlineDataWasNotWrittenToSheet($fileName, $sheetIndex, $inlineData, $message = '')
|
|
{
|
|
$resourcePath = $this->getGeneratedResourcePath($fileName);
|
|
$pathToSheetFile = $resourcePath . '#xl/worksheets/sheet' . $sheetIndex . '.xml';
|
|
$xmlContents = file_get_contents('zip://' . $pathToSheetFile);
|
|
|
|
$this->assertNotContains((string) $inlineData, $xmlContents, $message);
|
|
}
|
|
|
|
/**
|
|
* @param string $fileName
|
|
* @param string $sharedString
|
|
* @param string $message
|
|
* @return void
|
|
*/
|
|
private function assertSharedStringWasWritten($fileName, $sharedString, $message = '')
|
|
{
|
|
$resourcePath = $this->getGeneratedResourcePath($fileName);
|
|
$pathToSharedStringsFile = $resourcePath . '#xl/sharedStrings.xml';
|
|
$xmlContents = file_get_contents('zip://' . $pathToSharedStringsFile);
|
|
|
|
$this->assertContains($sharedString, $xmlContents, $message);
|
|
}
|
|
|
|
/**
|
|
* @param $fileName
|
|
* @param $sheetIndex - 1 based
|
|
* @return XMLReader
|
|
*/
|
|
private function getXmlReaderForSheetFromXmlFile($fileName, $sheetIndex)
|
|
{
|
|
$resourcePath = $this->getGeneratedResourcePath($fileName);
|
|
|
|
$xmlReader = new XMLReader();
|
|
$xmlReader->openFileInZip($resourcePath, 'xl/worksheets/sheet' . $sheetIndex . '.xml');
|
|
|
|
return $xmlReader;
|
|
}
|
|
|
|
/**
|
|
* @param $fileName
|
|
* @param $sheetIndex - 1 based
|
|
* @param $rowIndex - 1 based
|
|
* @throws \Box\Spout\Reader\Exception\XMLProcessingException
|
|
* @return \DOMNode|null
|
|
*/
|
|
private function getXmlRowFromXmlFile($fileName, $sheetIndex, $rowIndex)
|
|
{
|
|
$xmlReader = $this->getXmlReaderForSheetFromXmlFile($fileName, $sheetIndex);
|
|
$xmlReader->readUntilNodeFound('sheetData');
|
|
|
|
for ($i = 0; $i < $rowIndex; $i++) {
|
|
$xmlReader->readUntilNodeFound('row');
|
|
}
|
|
|
|
$row = $xmlReader->expand();
|
|
|
|
$xmlReader->close();
|
|
|
|
return $row;
|
|
}
|
|
}
|