From ceddc13f8253ec59c7ce0aca872c1eebf1f3b330 Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Sun, 26 Apr 2015 13:00:58 +0100 Subject: [PATCH] Implement a ColumnIterator, refactoring of RowIterator Currently this disables the setIterateOnlyExistingCells option TODO Re-Implement setIterateOnlyExistingCells logic with the new structure TODO Rationalise and abstract common methods in the iterator classes --- Classes/PHPExcel/Worksheet.php | 12 + Classes/PHPExcel/Worksheet/CellIterator.php | 2 +- Classes/PHPExcel/Worksheet/Column.php | 90 +++++++ .../PHPExcel/Worksheet/ColumnCellIterator.php | 215 +++++++++++++++++ Classes/PHPExcel/Worksheet/ColumnIterator.php | 192 +++++++++++++++ Classes/PHPExcel/Worksheet/Row.php | 2 +- .../PHPExcel/Worksheet/RowCellIterator.php | 224 ++++++++++++++++++ Classes/PHPExcel/Worksheet/RowIterator.php | 7 +- .../PHPExcel/Worksheet/ColumnIteratorTest.php | 89 +++++++ .../PHPExcel/Worksheet/RowIteratorTest.php | 6 +- .../Worksheet/WorksheetColumnTest.php | 43 ++++ .../PHPExcel/Worksheet/WorksheetRowTest.php | 43 ++++ unitTests/phpunit.xml | 3 + 13 files changed, 922 insertions(+), 6 deletions(-) create mode 100644 Classes/PHPExcel/Worksheet/Column.php create mode 100644 Classes/PHPExcel/Worksheet/ColumnCellIterator.php create mode 100644 Classes/PHPExcel/Worksheet/ColumnIterator.php create mode 100644 Classes/PHPExcel/Worksheet/RowCellIterator.php create mode 100644 unitTests/Classes/PHPExcel/Worksheet/ColumnIteratorTest.php create mode 100644 unitTests/Classes/PHPExcel/Worksheet/WorksheetColumnTest.php create mode 100644 unitTests/Classes/PHPExcel/Worksheet/WorksheetRowTest.php diff --git a/Classes/PHPExcel/Worksheet.php b/Classes/PHPExcel/Worksheet.php index bb6a22fd..2b0b57ae 100644 --- a/Classes/PHPExcel/Worksheet.php +++ b/Classes/PHPExcel/Worksheet.php @@ -2568,6 +2568,18 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable return new PHPExcel_Worksheet_RowIterator($this, $startRow, $endRow); } + /** + * Get column iterator + * + * @param string $startColumn The column address at which to start iterating + * @param string $endColumn The column address at which to stop iterating + * + * @return PHPExcel_Worksheet_ColumnIterator + */ + public function getColumnIterator($startColumn = 'A', $endColumn = null) { + return new PHPExcel_Worksheet_ColumnIterator($this, $startColumn, $endColumn); + } + /** * Run PHPExcel garabage collector. * diff --git a/Classes/PHPExcel/Worksheet/CellIterator.php b/Classes/PHPExcel/Worksheet/CellIterator.php index 27cdc94c..4b968167 100644 --- a/Classes/PHPExcel/Worksheet/CellIterator.php +++ b/Classes/PHPExcel/Worksheet/CellIterator.php @@ -22,7 +22,7 @@ * @package PHPExcel_Worksheet * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version ##VERSION##, ##DATE## + * @version 1.8.0, 2014-03-02 */ diff --git a/Classes/PHPExcel/Worksheet/Column.php b/Classes/PHPExcel/Worksheet/Column.php new file mode 100644 index 00000000..a251f396 --- /dev/null +++ b/Classes/PHPExcel/Worksheet/Column.php @@ -0,0 +1,90 @@ +_parent = $parent; + $this->_columnIndex = $columnIndex; + } + + /** + * Destructor + */ + public function __destruct() { + unset($this->_parent); + } + + /** + * Get column index + * + * @return int + */ + public function getColumnIndex() { + return $this->_columnIndex; + } + + /** + * Get cell iterator + * + * @return PHPExcel_Worksheet_CellIterator + */ + public function getCellIterator() { + return new PHPExcel_Worksheet_ColumnCellIterator($this->_parent, $this->_columnIndex); + } +} diff --git a/Classes/PHPExcel/Worksheet/ColumnCellIterator.php b/Classes/PHPExcel/Worksheet/ColumnCellIterator.php new file mode 100644 index 00000000..ac4c87a2 --- /dev/null +++ b/Classes/PHPExcel/Worksheet/ColumnCellIterator.php @@ -0,0 +1,215 @@ +_subject = $subject; + $this->_columnIndex = PHPExcel_Cell::columnIndexFromString($columnIndex) - 1; + $this->resetEnd($endRow); + $this->resetStart($startRow); + } + + /** + * Destructor + */ + public function __destruct() { + unset($this->_subject); + } + + /** + * (Re)Set the start row and the current row pointer + * + * @param integer $startRow The row number at which to start iterating + * @return PHPExcel_Worksheet_RowIterator + */ + public function resetStart($startRow = 1) { + $this->_startRow = $startRow; + $this->seek($startRow); + + return $this; + } + + /** + * (Re)Set the end row + * + * @param integer $endRow The row number at which to stop iterating + * @return PHPExcel_Worksheet_RowIterator + */ + public function resetEnd($endRow = null) { + $this->_endRow = ($endRow) ? $endRow : $this->_subject->getHighestRow(); + + return $this; + } + + /** + * Set the row pointer to the selected row + * + * @param integer $row The row number to set the current pointer at + * @return PHPExcel_Worksheet_RowIterator + * @throws PHPExcel_Exception + */ + public function seek($row = 1) { + if (($row < $this->_startRow) || ($row > $this->_endRow)) { + throw new PHPExcel_Exception("Row $row is out of range ({$this->_startRow} - {$this->_endRow})"); + } + $this->_position = $row; + + return $this; + } + + /** + * Rewind the iterator to the starting row + */ + public function rewind() { + $this->_position = $this->_startRow; + } + + /** + * Return the current row in this worksheet + * + * @return PHPExcel_Worksheet_Row + */ + public function current() { + return $this->_subject->getCellByColumnAndRow($this->_columnIndex, $this->_position); + } + + /** + * Return the current iterator key + * + * @return int + */ + public function key() { + return $this->_position; + } + + /** + * Set the iterator to its next value + */ + public function next() { + ++$this->_position; + } + + /** + * Set the iterator to its previous value + */ + public function prev() { + if ($this->_position <= $this->_startRow) { + throw new PHPExcel_Exception("Row is already at the beginning of range ({$this->_startRow} - {$this->_endRow})"); + } + + --$this->_position; + } + + /** + * Indicate if more rows exist in the worksheet range of rows that we're iterating + * + * @return boolean + */ + public function valid() { + return $this->_position <= $this->_endRow; + } + + /** + * Get loop only existing cells + * + * @return boolean + */ + public function getIterateOnlyExistingCells() { + return $this->_onlyExistingCells; + } + + /** + * Set the iterator to loop only existing cells + * + * @param boolean $value + */ + public function setIterateOnlyExistingCells($value = true) { + $this->_onlyExistingCells = $value; + } +} diff --git a/Classes/PHPExcel/Worksheet/ColumnIterator.php b/Classes/PHPExcel/Worksheet/ColumnIterator.php new file mode 100644 index 00000000..3030b3f4 --- /dev/null +++ b/Classes/PHPExcel/Worksheet/ColumnIterator.php @@ -0,0 +1,192 @@ +_subject = $subject; + $this->resetEnd($endColumn); + $this->resetStart($startColumn); + } + + /** + * Destructor + */ + public function __destruct() { + unset($this->_subject); + } + + /** + * (Re)Set the start column and the current column pointer + * + * @param integer $startColumn The column address at which to start iterating + * @return PHPExcel_Worksheet_ColumnIterator + */ + public function resetStart($startColumn = 'A') { + $startColumnIndex = PHPExcel_Cell::columnIndexFromString($startColumn) - 1; + $this->_startColumn = $startColumnIndex; + $this->seek($startColumn); + + return $this; + } + + /** + * (Re)Set the end column + * + * @param string $endColumn The column address at which to stop iterating + * @return PHPExcel_Worksheet_ColumnIterator + */ + public function resetEnd($endColumn = null) { + $endColumn = ($endColumn) ? $endColumn : $this->_subject->getHighestColumn(); + $this->_endColumn = PHPExcel_Cell::columnIndexFromString($endColumn) - 1; + + return $this; + } + + /** + * Set the column pointer to the selected column + * + * @param string $column The column address to set the current pointer at + * @return PHPExcel_Worksheet_ColumnIterator + * @throws PHPExcel_Exception + */ + public function seek($column = 'A') { + $column = PHPExcel_Cell::columnIndexFromString($column) - 1; + if (($column < $this->_startColumn) || ($column > $this->_endColumn)) { + throw new PHPExcel_Exception("Column $column is out of range ({$this->_startColumn} - {$this->_endColumn})"); + } + $this->_position = $column; + + return $this; + } + + /** + * Rewind the iterator to the starting column + */ + public function rewind() { + $this->_position = $this->_startColumn; + } + + /** + * Return the current column in this worksheet + * + * @return PHPExcel_Worksheet_Column + */ + public function current() { + return new PHPExcel_Worksheet_Column($this->_subject, PHPExcel_Cell::stringFromColumnIndex($this->_position)); + } + + /** + * Return the current iterator key + * + * @return string + */ + public function key() { + return PHPExcel_Cell::stringFromColumnIndex($this->_position); + } + + /** + * Set the iterator to its next value + */ + public function next() { + ++$this->_position; + } + + /** + * Set the iterator to its previous value + * + * @throws PHPExcel_Exception + */ + public function prev() { + if ($this->_position <= $this->_startColumn) { + throw new PHPExcel_Exception( + "Column is already at the beginning of range (" . + PHPExcel_Cell::stringFromColumnIndex($this->_endColumn) . " - " . + PHPExcel_Cell::stringFromColumnIndex($this->_endColumn) . ")" + ); + } + + --$this->_position; + } + + /** + * Indicate if more columns exist in the worksheet range of columns that we're iterating + * + * @return boolean + */ + public function valid() { + return $this->_position <= $this->_endColumn; + } +} diff --git a/Classes/PHPExcel/Worksheet/Row.php b/Classes/PHPExcel/Worksheet/Row.php index df16d33c..32b63cea 100644 --- a/Classes/PHPExcel/Worksheet/Row.php +++ b/Classes/PHPExcel/Worksheet/Row.php @@ -85,6 +85,6 @@ class PHPExcel_Worksheet_Row * @return PHPExcel_Worksheet_CellIterator */ public function getCellIterator() { - return new PHPExcel_Worksheet_CellIterator($this->_parent, $this->_rowIndex); + return new PHPExcel_Worksheet_RowCellIterator($this->_parent, $this->_rowIndex); } } diff --git a/Classes/PHPExcel/Worksheet/RowCellIterator.php b/Classes/PHPExcel/Worksheet/RowCellIterator.php new file mode 100644 index 00000000..048ca9d3 --- /dev/null +++ b/Classes/PHPExcel/Worksheet/RowCellIterator.php @@ -0,0 +1,224 @@ +_subject = $subject; + $this->_rowIndex = $rowIndex; + $this->resetEnd($endColumn); + $this->resetStart($startColumn); + } + + /** + * Destructor + */ + public function __destruct() { + unset($this->_subject); + } + + /** + * (Re)Set the start column and the current column pointer + * + * @param integer $startColumn The column address at which to start iterating + * @return PHPExcel_Worksheet_RowCellIterator + */ + public function resetStart($startColumn = 'A') { + $startColumnIndex = PHPExcel_Cell::columnIndexFromString($startColumn) - 1; + $this->_startColumn = $startColumnIndex; + $this->seek($startColumn); + + return $this; + } + + /** + * (Re)Set the end column + * + * @param string $endColumn The column address at which to stop iterating + * @return PHPExcel_Worksheet_RowCellIterator + */ + public function resetEnd($endColumn = null) { + $endColumn = ($endColumn) ? $endColumn : $this->_subject->getHighestColumn(); + $this->_endColumn = PHPExcel_Cell::columnIndexFromString($endColumn) - 1; + + return $this; + } + + /** + * Set the column pointer to the selected column + * + * @param string $column The column address to set the current pointer at + * @return PHPExcel_Worksheet_RowCellIterator + * @throws PHPExcel_Exception + */ + public function seek($column = 'A') { + $column = PHPExcel_Cell::columnIndexFromString($column) - 1; + if (($column < $this->_startColumn) || ($column > $this->_endColumn)) { + throw new PHPExcel_Exception("Column $column is out of range ({$this->_startColumn} - {$this->_endColumn})"); + } + $this->_position = $column; + + return $this; + } + + /** + * Rewind the iterator to the starting column + */ + public function rewind() { + $this->_position = $this->_startColumn; + } + + /** + * Return the current cell in this worksheet row + * + * @return PHPExcel_Cell + */ + public function current() { + return $this->_subject->getCellByColumnAndRow($this->_position, $this->_rowIndex); + } + + /** + * Return the current iterator key + * + * @return string + */ + public function key() { + return PHPExcel_Cell::stringFromColumnIndex($this->_position); + } + + /** + * Set the iterator to its next value + */ + public function next() { + ++$this->_position; + } + + /** + * Set the iterator to its previous value + * + * @throws PHPExcel_Exception + */ + public function prev() { + if ($this->_position <= $this->_startColumn) { + throw new PHPExcel_Exception( + "Column is already at the beginning of range (" . + PHPExcel_Cell::stringFromColumnIndex($this->_endColumn) . " - " . + PHPExcel_Cell::stringFromColumnIndex($this->_endColumn) . ")" + ); + } + + --$this->_position; + } + + /** + * Indicate if more columns exist in the worksheet range of columns that we're iterating + * + * @return boolean + */ + public function valid() { + return $this->_position <= $this->_endColumn; + } + + /** + * Get loop only existing cells + * + * @return boolean + */ + public function getIterateOnlyExistingCells() { + return $this->_onlyExistingCells; + } + + /** + * Set the iterator to loop only existing cells + * + * @param boolean $value + */ + public function setIterateOnlyExistingCells($value = true) { + $this->_onlyExistingCells = $value; + } +} diff --git a/Classes/PHPExcel/Worksheet/RowIterator.php b/Classes/PHPExcel/Worksheet/RowIterator.php index 295ed60e..110d8621 100644 --- a/Classes/PHPExcel/Worksheet/RowIterator.php +++ b/Classes/PHPExcel/Worksheet/RowIterator.php @@ -92,6 +92,7 @@ class PHPExcel_Worksheet_RowIterator implements Iterator * (Re)Set the start row and the current row pointer * * @param integer $startRow The row number at which to start iterating + * @return PHPExcel_Worksheet_RowIterator */ public function resetStart($startRow = 1) { $this->_startRow = $startRow; @@ -104,6 +105,7 @@ class PHPExcel_Worksheet_RowIterator implements Iterator * (Re)Set the end row * * @param integer $endRow The row number at which to stop iterating + * @return PHPExcel_Worksheet_RowIterator */ public function resetEnd($endRow = null) { $this->_endRow = ($endRow) ? $endRow : $this->_subject->getHighestRow(); @@ -115,13 +117,16 @@ class PHPExcel_Worksheet_RowIterator implements Iterator * Set the row pointer to the selected row * * @param integer $row The row number to set the current pointer at + * @return PHPExcel_Worksheet_RowIterator + * @throws PHPExcel_Exception */ public function seek($row = 1) { if (($row < $this->_startRow) || ($row > $this->_endRow)) { throw new PHPExcel_Exception("Row $row is out of range ({$this->_startRow} - {$this->_endRow})"); } - $this->_position = $row; + + return $this; } /** diff --git a/unitTests/Classes/PHPExcel/Worksheet/ColumnIteratorTest.php b/unitTests/Classes/PHPExcel/Worksheet/ColumnIteratorTest.php new file mode 100644 index 00000000..4129b85c --- /dev/null +++ b/unitTests/Classes/PHPExcel/Worksheet/ColumnIteratorTest.php @@ -0,0 +1,89 @@ +mockColumn = $this->getMockBuilder('PHPExcel_Worksheet_Column') + ->disableOriginalConstructor() + ->getMock(); + + $this->mockWorksheet = $this->getMockBuilder('PHPExcel_Worksheet') + ->disableOriginalConstructor() + ->getMock(); + + $this->mockWorksheet->expects($this->any()) + ->method('getHighestColumn') + ->will($this->returnValue('E')); + $this->mockWorksheet->expects($this->any()) + ->method('current') + ->will($this->returnValue($this->mockColumn)); + } + + + public function testIteratorFullRange() + { + $iterator = new PHPExcel_Worksheet_ColumnIterator($this->mockWorksheet); + $columnIndexResult = 'A'; + $this->assertEquals($columnIndexResult, $iterator->key()); + + foreach($iterator as $key => $column) { + $this->assertEquals($columnIndexResult++, $key); + $this->assertInstanceOf('PHPExcel_Worksheet_Column', $column); + } + } + + public function testIteratorStartEndRange() + { + $iterator = new PHPExcel_Worksheet_ColumnIterator($this->mockWorksheet, 'B', 'D'); + $columnIndexResult = 'B'; + $this->assertEquals($columnIndexResult, $iterator->key()); + + foreach($iterator as $key => $column) { + $this->assertEquals($columnIndexResult++, $key); + $this->assertInstanceOf('PHPExcel_Worksheet_Column', $column); + } + } + + public function testIteratorSeekAndPrev() + { + $ranges = range('A','E'); + $iterator = new PHPExcel_Worksheet_ColumnIterator($this->mockWorksheet, 'B', 'D'); + $columnIndexResult = 'D'; + $iterator->seek('D'); + $this->assertEquals($columnIndexResult, $iterator->key()); + + for($i = 1; $i < array_search($columnIndexResult, $ranges); $i++) { + $iterator->prev(); + $expectedResult = $ranges[array_search($columnIndexResult, $ranges) - $i]; + $this->assertEquals($expectedResult, $iterator->key()); + } + } + + /** + * @expectedException PHPExcel_Exception + */ + public function testSeekOutOfRange() + { + $iterator = new PHPExcel_Worksheet_ColumnIterator($this->mockWorksheet, 'B', 'D'); + $iterator->seek(1); + } + + /** + * @expectedException PHPExcel_Exception + */ + public function testPrevOutOfRange() + { + $iterator = new PHPExcel_Worksheet_ColumnIterator($this->mockWorksheet, 'B', 'D'); + $iterator->prev(); + } + +} diff --git a/unitTests/Classes/PHPExcel/Worksheet/RowIteratorTest.php b/unitTests/Classes/PHPExcel/Worksheet/RowIteratorTest.php index f39f33d5..48d8b6bb 100644 --- a/unitTests/Classes/PHPExcel/Worksheet/RowIteratorTest.php +++ b/unitTests/Classes/PHPExcel/Worksheet/RowIteratorTest.php @@ -55,12 +55,12 @@ class RowIteratorTest extends PHPUnit_Framework_TestCase public function testIteratorSeekAndPrev() { - $iterator = new PHPExcel_Worksheet_RowIterator($this->mockWorksheet); + $iterator = new PHPExcel_Worksheet_RowIterator($this->mockWorksheet, 2, 4); $columnIndexResult = 4; $iterator->seek(4); - $this->assertEquals($columnIndexResult, $iterator->key(), 2, 4); + $this->assertEquals($columnIndexResult, $iterator->key()); - for($i = 1; $i < $columnIndexResult; $i++) { + for($i = 1; $i < $columnIndexResult-1; $i++) { $iterator->prev(); $this->assertEquals($columnIndexResult - $i, $iterator->key()); } diff --git a/unitTests/Classes/PHPExcel/Worksheet/WorksheetColumnTest.php b/unitTests/Classes/PHPExcel/Worksheet/WorksheetColumnTest.php new file mode 100644 index 00000000..a867bd7d --- /dev/null +++ b/unitTests/Classes/PHPExcel/Worksheet/WorksheetColumnTest.php @@ -0,0 +1,43 @@ +mockWorksheet = $this->getMockBuilder('PHPExcel_Worksheet') + ->disableOriginalConstructor() + ->getMock(); + } + + + public function testInstantiateColumnDefault() + { + $column = new PHPExcel_Worksheet_Column($this->mockWorksheet); + $this->assertInstanceOf('PHPExcel_Worksheet_Column', $column); + $columnIndex = $column->getColumnIndex(); + $this->assertEquals('A', $columnIndex); + } + + public function testInstantiateColumnSpecified() + { + $column = new PHPExcel_Worksheet_Column($this->mockWorksheet, 'E'); + $this->assertInstanceOf('PHPExcel_Worksheet_Column', $column); + $columnIndex = $column->getColumnIndex(); + $this->assertEquals('E', $columnIndex); + } + + public function testGetCellIterator() + { + $column = new PHPExcel_Worksheet_Column($this->mockWorksheet); + $cellIterator = $column->getCellIterator(); + $this->assertInstanceOf('PHPExcel_Worksheet_CellIterator', $cellIterator); + } +} diff --git a/unitTests/Classes/PHPExcel/Worksheet/WorksheetRowTest.php b/unitTests/Classes/PHPExcel/Worksheet/WorksheetRowTest.php new file mode 100644 index 00000000..dd80e0d5 --- /dev/null +++ b/unitTests/Classes/PHPExcel/Worksheet/WorksheetRowTest.php @@ -0,0 +1,43 @@ +mockWorksheet = $this->getMockBuilder('PHPExcel_Worksheet') + ->disableOriginalConstructor() + ->getMock(); + } + + + public function testInstantiateRowDefault() + { + $row = new PHPExcel_Worksheet_Row($this->mockWorksheet); + $this->assertInstanceOf('PHPExcel_Worksheet_Row', $row); + $rowIndex = $row->getRowIndex(); + $this->assertEquals(1, $rowIndex); + } + + public function testInstantiateRowSpecified() + { + $row = new PHPExcel_Worksheet_Row($this->mockWorksheet, 5); + $this->assertInstanceOf('PHPExcel_Worksheet_Row', $row); + $rowIndex = $row->getRowIndex(); + $this->assertEquals(5, $rowIndex); + } + + public function testGetCellIterator() + { + $row = new PHPExcel_Worksheet_Row($this->mockWorksheet); + $cellIterator = $row->getCellIterator(); + $this->assertInstanceOf('PHPExcel_Worksheet_CellIterator', $cellIterator); + } +} diff --git a/unitTests/phpunit.xml b/unitTests/phpunit.xml index d18d1461..d024c28f 100644 --- a/unitTests/phpunit.xml +++ b/unitTests/phpunit.xml @@ -13,6 +13,9 @@ stopOnFailure="false" stopOnIncomplete="false" stopOnSkipped="false"> + + + ./Classes