Make XLSX reader return Row objects

This commit is contained in:
Adrien Loison 2017-11-18 20:39:50 +01:00
parent a665b974fa
commit 78b6639480
12 changed files with 272 additions and 96 deletions

View File

@ -27,8 +27,8 @@ class RowIterator implements IteratorInterface
/** @var int Number of read rows */ /** @var int Number of read rows */
protected $numReadRows = 0; protected $numReadRows = 0;
/** @var Row|null Buffer used to store the row data, while checking if there are more rows to read */ /** @var Row|null Buffer used to store the current row, while checking if there are more rows to read */
protected $rowDataBuffer; protected $rowBuffer;
/** @var bool Indicates whether all rows have been read */ /** @var bool Indicates whether all rows have been read */
protected $hasReachedEndOfFile = false; protected $hasReachedEndOfFile = false;
@ -89,7 +89,7 @@ class RowIterator implements IteratorInterface
$this->rewindAndSkipBom(); $this->rewindAndSkipBom();
$this->numReadRows = 0; $this->numReadRows = 0;
$this->rowDataBuffer = null; $this->rowBuffer = null;
$this->next(); $this->next();
} }
@ -148,7 +148,7 @@ class RowIterator implements IteratorInterface
if ($rowData !== false) { if ($rowData !== false) {
// str_replace will replace NULL values by empty strings // str_replace will replace NULL values by empty strings
$rowDataBufferAsArray = str_replace(null, null, $rowData); $rowDataBufferAsArray = str_replace(null, null, $rowData);
$this->rowDataBuffer = $this->entityFactory->createRowFromArray($rowDataBufferAsArray); $this->rowBuffer = $this->entityFactory->createRowFromArray($rowDataBufferAsArray);
$this->numReadRows++; $this->numReadRows++;
} else { } else {
// If we reach this point, it means end of file was reached. // If we reach this point, it means end of file was reached.
@ -226,7 +226,7 @@ class RowIterator implements IteratorInterface
*/ */
public function current() public function current()
{ {
return $this->rowDataBuffer; return $this->rowBuffer;
} }
/** /**

View File

@ -29,7 +29,7 @@ class Row
/** /**
* @param Cell[] $cells * @param Cell[] $cells
* @return $this * @return Row
*/ */
public function setCells(array $cells) public function setCells(array $cells)
{ {
@ -41,6 +41,19 @@ class Row
return $this; return $this;
} }
/**
* @param Cell $cell
* @param mixed $cellIndex
* @parma int $cellIndex
* @return Row
*/
public function setCellAtIndex(Cell $cell, $cellIndex)
{
$this->cells[$cellIndex] = $cell;
return $this;
}
/** /**
* @param Cell $cell * @param Cell $cell
* @return Row * @return Row

View File

@ -3,7 +3,9 @@
namespace Box\Spout\Reader\XLSX\Creator; namespace Box\Spout\Reader\XLSX\Creator;
use Box\Spout\Reader\Common\Creator\InternalEntityFactoryInterface; use Box\Spout\Reader\Common\Creator\InternalEntityFactoryInterface;
use Box\Spout\Reader\Common\Entity\Cell;
use Box\Spout\Reader\Common\Entity\Options; use Box\Spout\Reader\Common\Entity\Options;
use Box\Spout\Reader\Common\Entity\Row;
use Box\Spout\Reader\Common\XMLProcessor; use Box\Spout\Reader\Common\XMLProcessor;
use Box\Spout\Reader\Wrapper\XMLReader; use Box\Spout\Reader\Wrapper\XMLReader;
use Box\Spout\Reader\XLSX\Manager\SharedStringsManager; use Box\Spout\Reader\XLSX\Manager\SharedStringsManager;
@ -85,6 +87,7 @@ class InternalEntityFactory implements InternalEntityFactoryInterface
$xmlProcessor = $this->createXMLProcessor($xmlReader); $xmlProcessor = $this->createXMLProcessor($xmlReader);
$styleManager = $this->managerFactory->createStyleManager($filePath, $this); $styleManager = $this->managerFactory->createStyleManager($filePath, $this);
$rowManager = $this->managerFactory->createRowManager($this);
$shouldFormatDates = $optionsManager->getOption(Options::SHOULD_FORMAT_DATES); $shouldFormatDates = $optionsManager->getOption(Options::SHOULD_FORMAT_DATES);
$shouldUse1904Dates = $optionsManager->getOption(Options::SHOULD_USE_1904_DATES); $shouldUse1904Dates = $optionsManager->getOption(Options::SHOULD_USE_1904_DATES);
@ -103,10 +106,30 @@ class InternalEntityFactory implements InternalEntityFactoryInterface
$shouldPreserveEmptyRows, $shouldPreserveEmptyRows,
$xmlReader, $xmlReader,
$xmlProcessor, $xmlProcessor,
$cellValueFormatter $cellValueFormatter,
$rowManager,
$this
); );
} }
/**
* @param Cell[] $cells
* @return Row
*/
public function createRow(array $cells)
{
return new Row($cells);
}
/**
* @param mixed $cellValue
* @return Cell
*/
public function createCell($cellValue)
{
return new Cell($cellValue);
}
/** /**
* @return \ZipArchive * @return \ZipArchive
*/ */

View File

@ -2,6 +2,7 @@
namespace Box\Spout\Reader\XLSX\Creator; namespace Box\Spout\Reader\XLSX\Creator;
use Box\Spout\Reader\XLSX\Manager\RowManager;
use Box\Spout\Reader\XLSX\Manager\SharedStringsCaching\CachingStrategyFactory; use Box\Spout\Reader\XLSX\Manager\SharedStringsCaching\CachingStrategyFactory;
use Box\Spout\Reader\XLSX\Manager\SharedStringsManager; use Box\Spout\Reader\XLSX\Manager\SharedStringsManager;
use Box\Spout\Reader\XLSX\Manager\SheetManager; use Box\Spout\Reader\XLSX\Manager\SheetManager;
@ -92,4 +93,13 @@ class ManagerFactory
return new StyleManager($filePath, $workbookRelationshipsManager, $entityFactory); return new StyleManager($filePath, $workbookRelationshipsManager, $entityFactory);
} }
/**
* @param InternalEntityFactory $entityFactory Factory to create entities
* @return RowManager
*/
public function createRowManager($entityFactory)
{
return new RowManager($entityFactory);
}
} }

View File

@ -18,30 +18,6 @@ class CellHelper
'V' => 21, 'W' => 22, 'X' => 23, 'Y' => 24, 'Z' => 25, 'V' => 21, 'W' => 22, 'X' => 23, 'Y' => 24, 'Z' => 25,
]; ];
/**
* Fills the missing indexes of an array with a given value.
* For instance, $dataArray = []; $a[1] = 1; $a[3] = 3;
* Calling fillMissingArrayIndexes($dataArray, 'FILL') will return this array: ['FILL', 1, 'FILL', 3]
*
* @param array $dataArray The array to fill
* @param string $fillValue optional
* @return array
*/
public static function fillMissingArrayIndexes($dataArray, $fillValue = '')
{
if (empty($dataArray)) {
return [];
}
$existingIndexes = array_keys($dataArray);
$newIndexes = array_fill_keys(range(0, max($existingIndexes)), $fillValue);
$dataArray += $newIndexes;
ksort($dataArray);
return $dataArray;
}
/** /**
* Returns the base 10 column index associated to the cell index (base 26). * Returns the base 10 column index associated to the cell index (base 26).
* Excel uses A to Z letters for column indexing, where A is the 1st column, * Excel uses A to Z letters for column indexing, where A is the 1st column,

View File

@ -0,0 +1,65 @@
<?php
namespace Box\Spout\Reader\XLSX\Manager;
use Box\Spout\Reader\Common\Entity\Row;
use Box\Spout\Reader\XLSX\Creator\InternalEntityFactory;
/**
* Class RowManager
*/
class RowManager
{
/** @var InternalEntityFactory Factory to create entities */
private $entityFactory;
/**
* @param InternalEntityFactory $entityFactory Factory to create entities
*/
public function __construct(InternalEntityFactory $entityFactory)
{
$this->entityFactory = $entityFactory;
}
/**
* Detect whether a row is considered empty.
* An empty row has all of its cells empty.
*
* @param Row $row
* @return bool
*/
public function isEmpty(Row $row)
{
foreach ($row->getCells() as $cell) {
if (!$cell->isEmpty()) {
return false;
}
}
return true;
}
/**
* Fills the missing indexes of a row with empty cells.
*
* @param Row $row
* @return Row
*/
public function fillMissingIndexesWithEmptyCells(Row $row)
{
$rowCells = $row->getCells();
if (count($rowCells) === 0) {
return $row;
}
$maxCellIndex = max(array_keys($rowCells));
for ($cellIndex = 0; $cellIndex < $maxCellIndex; $cellIndex++) {
if (!isset($rowCells[$cellIndex])) {
$row->setCellAtIndex($this->entityFactory->createCell(''), $cellIndex);
}
}
return $row;
}
}

View File

@ -3,12 +3,16 @@
namespace Box\Spout\Reader\XLSX; namespace Box\Spout\Reader\XLSX;
use Box\Spout\Common\Exception\IOException; use Box\Spout\Common\Exception\IOException;
use Box\Spout\Reader\Common\Entity\Cell;
use Box\Spout\Reader\Common\Entity\Row;
use Box\Spout\Reader\Common\XMLProcessor; use Box\Spout\Reader\Common\XMLProcessor;
use Box\Spout\Reader\Exception\XMLProcessingException; use Box\Spout\Reader\Exception\XMLProcessingException;
use Box\Spout\Reader\IteratorInterface; use Box\Spout\Reader\IteratorInterface;
use Box\Spout\Reader\Wrapper\XMLReader; use Box\Spout\Reader\Wrapper\XMLReader;
use Box\Spout\Reader\XLSX\Creator\InternalEntityFactory;
use Box\Spout\Reader\XLSX\Helper\CellHelper; use Box\Spout\Reader\XLSX\Helper\CellHelper;
use Box\Spout\Reader\XLSX\Helper\CellValueFormatter; use Box\Spout\Reader\XLSX\Helper\CellValueFormatter;
use Box\Spout\Reader\XLSX\Manager\RowManager;
/** /**
* Class RowIterator * Class RowIterator
@ -42,17 +46,23 @@ class RowIterator implements IteratorInterface
/** @var Helper\CellValueFormatter Helper to format cell values */ /** @var Helper\CellValueFormatter Helper to format cell values */
protected $cellValueFormatter; protected $cellValueFormatter;
/** @var \Box\Spout\Reader\XLSX\Manager\RowManager Manages rows */
protected $rowManager;
/** @var \Box\Spout\Reader\XLSX\Creator\InternalEntityFactory Factory to create entities */
protected $entityFactory;
/** /**
* TODO: This variable can be deleted when row indices get preserved * TODO: This variable can be deleted when row indices get preserved
* @var int Number of read rows * @var int Number of read rows
*/ */
protected $numReadRows = 0; protected $numReadRows = 0;
/** @var array Contains the data for the currently processed row (key = cell index, value = cell value) */ /** @var Row Contains the row currently processed */
protected $currentlyProcessedRowData = []; protected $currentlyProcessedRow;
/** @var array|null Buffer used to store the row data, while checking if there are more rows to read */ /** @var Row|null Buffer used to store the current row, while checking if there are more rows to read */
protected $rowDataBuffer; protected $rowBuffer;
/** @var bool Indicates whether all rows have been read */ /** @var bool Indicates whether all rows have been read */
protected $hasReachedEndOfFile = false; protected $hasReachedEndOfFile = false;
@ -79,14 +89,26 @@ class RowIterator implements IteratorInterface
* @param XMLReader $xmlReader XML Reader * @param XMLReader $xmlReader XML Reader
* @param XMLProcessor $xmlProcessor Helper to process XML files * @param XMLProcessor $xmlProcessor Helper to process XML files
* @param CellValueFormatter $cellValueFormatter Helper to format cell values * @param CellValueFormatter $cellValueFormatter Helper to format cell values
* @param RowManager $rowManager Manages rows
* @param InternalEntityFactory $entityFactory Factory to create entities
*/ */
public function __construct($filePath, $sheetDataXMLFilePath, $shouldPreserveEmptyRows, $xmlReader, $xmlProcessor, $cellValueFormatter) public function __construct(
{ $filePath,
$sheetDataXMLFilePath,
$shouldPreserveEmptyRows,
$xmlReader,
XMLProcessor $xmlProcessor,
CellValueFormatter $cellValueFormatter,
RowManager $rowManager,
InternalEntityFactory $entityFactory
) {
$this->filePath = $filePath; $this->filePath = $filePath;
$this->sheetDataXMLFilePath = $this->normalizeSheetDataXMLFilePath($sheetDataXMLFilePath); $this->sheetDataXMLFilePath = $this->normalizeSheetDataXMLFilePath($sheetDataXMLFilePath);
$this->shouldPreserveEmptyRows = $shouldPreserveEmptyRows;
$this->xmlReader = $xmlReader; $this->xmlReader = $xmlReader;
$this->cellValueFormatter = $cellValueFormatter; $this->cellValueFormatter = $cellValueFormatter;
$this->shouldPreserveEmptyRows = $shouldPreserveEmptyRows; $this->rowManager = $rowManager;
$this->entityFactory = $entityFactory;
// Register all callbacks to process different nodes when reading the XML file // Register all callbacks to process different nodes when reading the XML file
$this->xmlProcessor = $xmlProcessor; $this->xmlProcessor = $xmlProcessor;
@ -127,7 +149,7 @@ class RowIterator implements IteratorInterface
$this->numReadRows = 0; $this->numReadRows = 0;
$this->lastRowIndexProcessed = 0; $this->lastRowIndexProcessed = 0;
$this->nextRowIndexToBeProcessed = 0; $this->nextRowIndexToBeProcessed = 0;
$this->rowDataBuffer = null; $this->rowBuffer = null;
$this->hasReachedEndOfFile = false; $this->hasReachedEndOfFile = false;
$this->numColumns = 0; $this->numColumns = 0;
@ -192,7 +214,7 @@ class RowIterator implements IteratorInterface
*/ */
protected function readDataForNextRow() protected function readDataForNextRow()
{ {
$this->currentlyProcessedRowData = []; $this->currentlyProcessedRow = $this->entityFactory->createRow([]);
try { try {
$this->xmlProcessor->readUntilStopped(); $this->xmlProcessor->readUntilStopped();
@ -200,7 +222,7 @@ class RowIterator implements IteratorInterface
throw new IOException("The {$this->sheetDataXMLFilePath} file cannot be read. [{$exception->getMessage()}]"); throw new IOException("The {$this->sheetDataXMLFilePath} file cannot be read. [{$exception->getMessage()}]");
} }
$this->rowDataBuffer = $this->currentlyProcessedRowData; $this->rowBuffer = $this->currentlyProcessedRow;
} }
/** /**
@ -238,7 +260,8 @@ class RowIterator implements IteratorInterface
$numberOfColumnsForRow = (int) $numberOfColumnsForRow; $numberOfColumnsForRow = (int) $numberOfColumnsForRow;
} }
$this->currentlyProcessedRowData = ($numberOfColumnsForRow !== 0) ? array_fill(0, $numberOfColumnsForRow, '') : []; $cells = array_fill(0, $numberOfColumnsForRow, $this->entityFactory->createCell(''));
$this->currentlyProcessedRow->setCells($cells);
return XMLProcessor::PROCESSING_CONTINUE; return XMLProcessor::PROCESSING_CONTINUE;
} }
@ -253,7 +276,9 @@ class RowIterator implements IteratorInterface
// NOTE: expand() will automatically decode all XML entities of the child nodes // NOTE: expand() will automatically decode all XML entities of the child nodes
$node = $xmlReader->expand(); $node = $xmlReader->expand();
$this->currentlyProcessedRowData[$currentColumnIndex] = $this->getCellValue($node); $cell = $this->getCell($node);
$this->currentlyProcessedRow->setCellAtIndex($cell, $currentColumnIndex);
$this->lastColumnIndexProcessed = $currentColumnIndex; $this->lastColumnIndexProcessed = $currentColumnIndex;
return XMLProcessor::PROCESSING_CONTINUE; return XMLProcessor::PROCESSING_CONTINUE;
@ -265,7 +290,7 @@ class RowIterator implements IteratorInterface
protected function processRowEndingNode() protected function processRowEndingNode()
{ {
// if the fetched row is empty and we don't want to preserve it.., // if the fetched row is empty and we don't want to preserve it..,
if (!$this->shouldPreserveEmptyRows && $this->isEmptyRow($this->currentlyProcessedRowData)) { if (!$this->shouldPreserveEmptyRows && $this->rowManager->isEmpty($this->currentlyProcessedRow)) {
// ... skip it // ... skip it
return XMLProcessor::PROCESSING_CONTINUE; return XMLProcessor::PROCESSING_CONTINUE;
} }
@ -274,7 +299,7 @@ class RowIterator implements IteratorInterface
// If needed, we fill the empty cells // If needed, we fill the empty cells
if ($this->numColumns === 0) { if ($this->numColumns === 0) {
$this->currentlyProcessedRowData = CellHelper::fillMissingArrayIndexes($this->currentlyProcessedRowData); $this->currentlyProcessedRow = $this->rowManager->fillMissingIndexesWithEmptyCells($this->currentlyProcessedRow);
} }
// at this point, we have all the data we need for the row // at this point, we have all the data we need for the row
@ -324,34 +349,27 @@ class RowIterator implements IteratorInterface
} }
/** /**
* Returns the (unescaped) correctly marshalled, cell value associated to the given XML node. * Returns the cell with (unescaped) correctly marshalled, cell value associated to the given XML node.
* *
* @param \DOMNode $node * @param \DOMNode $node
* @return string|int|float|bool|\DateTime|null The value associated with the cell (null when the cell has an error) * @return Cell The cell set with the associated with the cell
*/ */
protected function getCellValue($node) protected function getCell($node)
{ {
return $this->cellValueFormatter->extractAndFormatNodeValue($node); $cellValue = $this->cellValueFormatter->extractAndFormatNodeValue($node);
}
/** return $this->entityFactory->createCell($cellValue);
* @param array $rowData
* @return bool Whether the given row is empty
*/
protected function isEmptyRow($rowData)
{
return (count($rowData) === 1 && reset($rowData) === '');
} }
/** /**
* Return the current element, either an empty row or from the buffer. * Return the current element, either an empty row or from the buffer.
* @see http://php.net/manual/en/iterator.current.php * @see http://php.net/manual/en/iterator.current.php
* *
* @return array|null * @return Row|null
*/ */
public function current() public function current()
{ {
$rowDataForRowToBeProcessed = $this->rowDataBuffer; $rowToBeProcessed = $this->rowBuffer;
if ($this->shouldPreserveEmptyRows) { if ($this->shouldPreserveEmptyRows) {
// when we need to preserve empty rows, we will either return // when we need to preserve empty rows, we will either return
@ -361,11 +379,11 @@ class RowIterator implements IteratorInterface
if ($this->lastRowIndexProcessed !== $this->nextRowIndexToBeProcessed) { if ($this->lastRowIndexProcessed !== $this->nextRowIndexToBeProcessed) {
// return empty row if mismatch between last processed row // return empty row if mismatch between last processed row
// and the row that needs to be returned // and the row that needs to be returned
$rowDataForRowToBeProcessed = ['']; $rowToBeProcessed = $this->entityFactory->createRow([]);
} }
} }
return $rowDataForRowToBeProcessed; return $rowToBeProcessed;
} }
/** /**

View File

@ -22,15 +22,19 @@ class RowManager
/** /**
* Detect whether a row is considered empty. * Detect whether a row is considered empty.
* An empty row has either no cells at all - or only one empty cell * An empty row has all of its cells empty.
* *
* @param Row $row * @param Row $row
* @return bool * @return bool
*/ */
public function isEmpty(Row $row) public function isEmpty(Row $row)
{ {
$cells = $row->getCells(); foreach ($row->getCells() as $cell) {
if (!$cell->isEmpty()) {
return false;
}
}
return count($cells) === 0 || (count($cells) === 1 && $cells[0]->isEmpty()); return true;
} }
} }

View File

@ -9,29 +9,6 @@ use Box\Spout\Common\Exception\InvalidArgumentException;
*/ */
class CellHelperTest extends \PHPUnit_Framework_TestCase class CellHelperTest extends \PHPUnit_Framework_TestCase
{ {
/**
* @return array
*/
public function dataProviderForTestFillMissingArrayIndexes()
{
return [
[null, []],
[[], []],
[[1 => 1, 3 => 3], ['FILL', 1, 'FILL', 3]],
];
}
/**
* @dataProvider dataProviderForTestFillMissingArrayIndexes
* @param array $arrayToFill
* @param array $expectedFilledArray
*/
public function testFillMissingArrayIndexes($arrayToFill, array $expectedFilledArray)
{
$filledArray = CellHelper::fillMissingArrayIndexes($arrayToFill, 'FILL');
$this->assertEquals($expectedFilledArray, $filledArray);
}
/** /**
* @return array * @return array
*/ */

View File

@ -0,0 +1,90 @@
<?php
namespace Box\Spout\Reader\XLSX\Manager;
use Box\Spout\Reader\Common\Entity\Cell;
use Box\Spout\Reader\Common\Entity\Row;
use Box\Spout\Reader\XLSX\Creator\HelperFactory;
use Box\Spout\Reader\XLSX\Creator\InternalEntityFactory;
use Box\Spout\Reader\XLSX\Creator\ManagerFactory;
/**
* Class SharedStringsManagerTest
*/
class RowManagerTest extends \PHPUnit_Framework_TestCase
{
/**
* @return array
*/
public function dataProviderForTestFillMissingIndexesWithEmptyCells()
{
$cell1 = new Cell(1);
$cell3 = new Cell(3);
return [
[[], []],
[[1 => $cell1, 3 => $cell3], [new Cell(''), $cell1, new Cell(''), $cell3]],
];
}
/**
* @dataProvider dataProviderForTestFillMissingIndexesWithEmptyCells
*
* @param Cell[]|null $rowCells
* @param Cell[] $expectedFilledCells
*/
public function testFillMissingIndexesWithEmptyCells($rowCells, $expectedFilledCells)
{
$rowManager = $this->createRowManager();
$rowToFill = new Row([]);
foreach ($rowCells as $cellIndex => $cell) {
$rowToFill->setCellAtIndex($cell, $cellIndex);
}
$filledRow = $rowManager->fillMissingIndexesWithEmptyCells($rowToFill);
$this->assertEquals($expectedFilledCells, $filledRow->getCells());
}
/**
* @return array
*/
public function dataProviderForTestIsEmptyRow()
{
return [
// cells, expected isEmpty
[[], true],
[[new Cell('')], true],
[[new Cell(''), new Cell('')], true],
[[new Cell(''), new Cell(''), new Cell('Okay')], false],
];
}
/**
* @dataProvider dataProviderForTestIsEmptyRow
*
* @param array $cells
* @param bool $expectedIsEmpty
* @return void
*/
public function testIsEmptyRow(array $cells, $expectedIsEmpty)
{
$rowManager = $this->createRowManager();
$row = new Row($cells);
$this->assertEquals($expectedIsEmpty, $rowManager->isEmpty($row));
}
/**
* @return RowManager
*/
private function createRowManager()
{
$entityFactory = new InternalEntityFactory(
$this->createMock(ManagerFactory::class),
$this->createMock(HelperFactory::class)
);
return new RowManager($entityFactory);
}
}

View File

@ -237,7 +237,6 @@ class ReaderTest extends \PHPUnit_Framework_TestCase
'weird string', // valid 'str' string 'weird string', // valid 'str' string
null, // invalid date null, // invalid date
], ],
['', '', '', '', '', '', '', '', ''],
]; ];
$this->assertEquals($expectedRows, $allRows); $this->assertEquals($expectedRows, $allRows);
} }
@ -451,10 +450,10 @@ class ReaderTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(6, count($allRows), 'There should be 6 rows'); $this->assertEquals(6, count($allRows), 'There should be 6 rows');
$expectedRows = [ $expectedRows = [
[''], [],
['s1--A2', 's1--B2', 's1--C2'], ['s1--A2', 's1--B2', 's1--C2'],
[''], [],
[''], [],
['s1--A5', 's1--B5', 's1--C5'], ['s1--A5', 's1--B5', 's1--C5'],
['s1--A6', 's1--B6', 's1--C6'], ['s1--A6', 's1--B6', 's1--C6'],
]; ];
@ -580,14 +579,14 @@ class ReaderTest extends \PHPUnit_Framework_TestCase
foreach ($reader->getSheetIterator() as $sheet) { foreach ($reader->getSheetIterator() as $sheet) {
// this loop should only add the first row of the first sheet // this loop should only add the first row of the first sheet
foreach ($sheet->getRowIterator() as $row) { foreach ($sheet->getRowIterator() as $row) {
$allRows[] = $row; $allRows[] = $row->toArray();
break; break;
} }
// this loop should rewind the iterator and restart reading from the 1st row again // this loop should rewind the iterator and restart reading from the 1st row again
// therefore, it should only add the first row of the first sheet // therefore, it should only add the first row of the first sheet
foreach ($sheet->getRowIterator() as $row) { foreach ($sheet->getRowIterator() as $row) {
$allRows[] = $row; $allRows[] = $row->toArray();
break; break;
} }
@ -598,7 +597,7 @@ class ReaderTest extends \PHPUnit_Framework_TestCase
foreach ($reader->getSheetIterator() as $sheet) { foreach ($reader->getSheetIterator() as $sheet) {
// this loop should only add the first row of the current sheet // this loop should only add the first row of the current sheet
foreach ($sheet->getRowIterator() as $row) { foreach ($sheet->getRowIterator() as $row) {
$allRows[] = $row; $allRows[] = $row->toArray();
break; break;
} }
@ -708,7 +707,7 @@ class ReaderTest extends \PHPUnit_Framework_TestCase
foreach ($reader->getSheetIterator() as $sheetIndex => $sheet) { foreach ($reader->getSheetIterator() as $sheetIndex => $sheet) {
foreach ($sheet->getRowIterator() as $rowIndex => $row) { foreach ($sheet->getRowIterator() as $rowIndex => $row) {
$allRows[] = $row; $allRows[] = $row->toArray();
} }
} }

View File

@ -19,6 +19,7 @@ class RowManagerTest extends TestCase
// cells, expected isEmpty // cells, expected isEmpty
[[], true], [[], true],
[[new Cell('')], true], [[new Cell('')], true],
[[new Cell(''), new Cell('')], true],
[[new Cell(''), new Cell(''), new Cell('Okay')], false], [[new Cell(''), new Cell(''), new Cell('Okay')], false],
]; ];
} }
@ -34,7 +35,7 @@ class RowManagerTest extends TestCase
{ {
$rowManager = new RowManager(new StyleMerger()); $rowManager = new RowManager(new StyleMerger());
$row = new Row($cells, null, $rowManager); $row = new Row($cells, null);
$this->assertEquals($expectedIsEmpty, $rowManager->isEmpty($row)); $this->assertEquals($expectedIsEmpty, $rowManager->isEmpty($row));
} }
} }