Skip to content

Commit ae09dd1

Browse files
author
MarkBaker
committed
Update logic in Cell Iterators to use Cell Collection directly where appropriate, bypassing the overhead of additional calls through the worksheet with extra checks and validations
1 parent 4a071ce commit ae09dd1

File tree

4 files changed

+47
-24
lines changed

4 files changed

+47
-24
lines changed

src/PhpSpreadsheet/Worksheet/CellIterator.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Iterator;
66
use PhpOffice\PhpSpreadsheet\Cell\Cell;
7+
use PhpOffice\PhpSpreadsheet\Collection\Cells;
78

89
/**
910
* @template TKey
@@ -18,6 +19,13 @@ abstract class CellIterator implements Iterator
1819
*/
1920
protected $worksheet;
2021

22+
/**
23+
* Cell Collection to iterate.
24+
*
25+
* @var Cells
26+
*/
27+
protected $cellCollection;
28+
2129
/**
2230
* Iterate only existing cells.
2331
*
@@ -31,7 +39,7 @@ abstract class CellIterator implements Iterator
3139
public function __destruct()
3240
{
3341
// @phpstan-ignore-next-line
34-
$this->worksheet = null;
42+
$this->worksheet = $this->cellCollection = null;
3543
}
3644

3745
/**

src/PhpSpreadsheet/Worksheet/ColumnCellIterator.php

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,16 @@ class ColumnCellIterator extends CellIterator
4242
/**
4343
* Create a new row iterator.
4444
*
45-
* @param Worksheet $subject The worksheet to iterate over
45+
* @param Worksheet $worksheet The worksheet to iterate over
4646
* @param string $columnIndex The column that we want to iterate
4747
* @param int $startRow The row number at which to start iterating
4848
* @param int $endRow Optionally, the row number at which to stop iterating
4949
*/
50-
public function __construct(Worksheet $subject, $columnIndex = 'A', $startRow = 1, $endRow = null)
50+
public function __construct(Worksheet $worksheet, $columnIndex = 'A', $startRow = 1, $endRow = null)
5151
{
5252
// Set subject
53-
$this->worksheet = $subject;
53+
$this->worksheet = $worksheet;
54+
$this->cellCollection = $worksheet->getCellCollection();
5455
$this->columnIndex = Coordinate::columnIndexFromString($columnIndex);
5556
$this->resetEnd($endRow);
5657
$this->resetStart($startRow);
@@ -96,7 +97,10 @@ public function resetEnd($endRow = null)
9697
*/
9798
public function seek(int $row = 1)
9899
{
99-
if ($this->onlyExistingCells && !($this->worksheet->cellExistsByColumnAndRow($this->columnIndex, $row))) {
100+
if (
101+
$this->onlyExistingCells &&
102+
(!$this->cellCollection->has(Coordinate::stringFromColumnIndex($this->columnIndex) . $row))
103+
) {
100104
throw new PhpSpreadsheetException('In "IterateOnlyExistingCells" mode and Cell does not exist');
101105
}
102106
if (($row < $this->startRow) || ($row > $this->endRow)) {
@@ -120,7 +124,11 @@ public function rewind(): void
120124
*/
121125
public function current(): ?Cell
122126
{
123-
return $this->worksheet->getCellByColumnAndRow($this->columnIndex, $this->currentRow);
127+
$cellAddress = Coordinate::stringFromColumnIndex($this->columnIndex) . $this->currentRow;
128+
129+
return $this->cellCollection->has($cellAddress)
130+
? $this->cellCollection->get($cellAddress)
131+
: $this->worksheet->createNewCell($cellAddress);
124132
}
125133

126134
/**
@@ -136,12 +144,13 @@ public function key(): int
136144
*/
137145
public function next(): void
138146
{
147+
$columnAddress = Coordinate::stringFromColumnIndex($this->columnIndex);
139148
do {
140149
++$this->currentRow;
141150
} while (
142151
($this->onlyExistingCells) &&
143-
(!$this->worksheet->cellExistsByColumnAndRow($this->columnIndex, $this->currentRow)) &&
144-
($this->currentRow <= $this->endRow)
152+
($this->currentRow <= $this->endRow) &&
153+
(!$this->cellCollection->has($columnAddress . $this->currentRow))
145154
);
146155
}
147156

@@ -150,12 +159,13 @@ public function next(): void
150159
*/
151160
public function prev(): void
152161
{
162+
$columnAddress = Coordinate::stringFromColumnIndex($this->columnIndex);
153163
do {
154164
--$this->currentRow;
155165
} while (
156166
($this->onlyExistingCells) &&
157-
(!$this->worksheet->cellExistsByColumnAndRow($this->columnIndex, $this->currentRow)) &&
158-
($this->currentRow >= $this->startRow)
167+
($this->currentRow >= $this->startRow) &&
168+
(!$this->cellCollection->has($columnAddress . $this->currentRow))
159169
);
160170
}
161171

@@ -173,14 +183,15 @@ public function valid(): bool
173183
protected function adjustForExistingOnlyRange(): void
174184
{
175185
if ($this->onlyExistingCells) {
186+
$columnAddress = Coordinate::stringFromColumnIndex($this->columnIndex);
176187
while (
177-
(!$this->worksheet->cellExistsByColumnAndRow($this->columnIndex, $this->startRow)) &&
188+
(!$this->cellCollection->has($columnAddress . $this->startRow)) &&
178189
($this->startRow <= $this->endRow)
179190
) {
180191
++$this->startRow;
181192
}
182193
while (
183-
(!$this->worksheet->cellExistsByColumnAndRow($this->columnIndex, $this->endRow)) &&
194+
(!$this->cellCollection->has($columnAddress . $this->endRow)) &&
184195
($this->endRow >= $this->startRow)
185196
) {
186197
--$this->endRow;

src/PhpSpreadsheet/Worksheet/RowCellIterator.php

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ public function __construct(Worksheet $worksheet, $rowIndex = 1, $startColumn =
5151
{
5252
// Set subject and row index
5353
$this->worksheet = $worksheet;
54+
$this->cellCollection = $worksheet->getCellCollection();
5455
$this->rowIndex = $rowIndex;
5556
$this->resetEnd($endColumn);
5657
$this->resetStart($startColumn);
@@ -97,15 +98,14 @@ public function resetEnd($endColumn = null)
9798
*/
9899
public function seek(string $column = 'A')
99100
{
100-
$columnx = $column;
101-
$column = Coordinate::columnIndexFromString($column);
102-
if ($this->onlyExistingCells && !($this->worksheet->cellExistsByColumnAndRow($column, $this->rowIndex))) {
101+
$columnId = Coordinate::columnIndexFromString($column);
102+
if ($this->onlyExistingCells && !($this->cellCollection->has($column . $this->rowIndex))) {
103103
throw new PhpSpreadsheetException('In "IterateOnlyExistingCells" mode and Cell does not exist');
104104
}
105-
if (($column < $this->startColumnIndex) || ($column > $this->endColumnIndex)) {
106-
throw new PhpSpreadsheetException("Column $columnx is out of range ({$this->startColumnIndex} - {$this->endColumnIndex})");
105+
if (($columnId < $this->startColumnIndex) || ($columnId > $this->endColumnIndex)) {
106+
throw new PhpSpreadsheetException("Column $column is out of range ({$this->startColumnIndex} - {$this->endColumnIndex})");
107107
}
108-
$this->currentColumnIndex = $column;
108+
$this->currentColumnIndex = $columnId;
109109

110110
return $this;
111111
}
@@ -123,7 +123,11 @@ public function rewind(): void
123123
*/
124124
public function current(): ?Cell
125125
{
126-
return $this->worksheet->getCellByColumnAndRow($this->currentColumnIndex, $this->rowIndex);
126+
$cellAddress = Coordinate::stringFromColumnIndex($this->currentColumnIndex) . $this->rowIndex;
127+
128+
return $this->cellCollection->has($cellAddress)
129+
? $this->cellCollection->get($cellAddress)
130+
: $this->worksheet->createNewCell($cellAddress);
127131
}
128132

129133
/**
@@ -141,7 +145,7 @@ public function next(): void
141145
{
142146
do {
143147
++$this->currentColumnIndex;
144-
} while (($this->onlyExistingCells) && (!$this->worksheet->cellExistsByColumnAndRow($this->currentColumnIndex, $this->rowIndex)) && ($this->currentColumnIndex <= $this->endColumnIndex));
148+
} while (($this->onlyExistingCells) && (!$this->cellCollection->has(Coordinate::stringFromColumnIndex($this->currentColumnIndex) . $this->rowIndex)) && ($this->currentColumnIndex <= $this->endColumnIndex));
145149
}
146150

147151
/**
@@ -151,7 +155,7 @@ public function prev(): void
151155
{
152156
do {
153157
--$this->currentColumnIndex;
154-
} while (($this->onlyExistingCells) && (!$this->worksheet->cellExistsByColumnAndRow($this->currentColumnIndex, $this->rowIndex)) && ($this->currentColumnIndex >= $this->startColumnIndex));
158+
} while (($this->onlyExistingCells) && (!$this->cellCollection->has(Coordinate::stringFromColumnIndex($this->currentColumnIndex) . $this->rowIndex)) && ($this->currentColumnIndex >= $this->startColumnIndex));
155159
}
156160

157161
/**
@@ -176,10 +180,10 @@ public function getCurrentColumnIndex(): int
176180
protected function adjustForExistingOnlyRange(): void
177181
{
178182
if ($this->onlyExistingCells) {
179-
while ((!$this->worksheet->cellExistsByColumnAndRow($this->startColumnIndex, $this->rowIndex)) && ($this->startColumnIndex <= $this->endColumnIndex)) {
183+
while ((!$this->cellCollection->has(Coordinate::stringFromColumnIndex($this->startColumnIndex) . $this->rowIndex)) && ($this->startColumnIndex <= $this->endColumnIndex)) {
180184
++$this->startColumnIndex;
181185
}
182-
while ((!$this->worksheet->cellExistsByColumnAndRow($this->endColumnIndex, $this->rowIndex)) && ($this->endColumnIndex >= $this->startColumnIndex)) {
186+
while ((!$this->cellCollection->has(Coordinate::stringFromColumnIndex($this->endColumnIndex) . $this->rowIndex)) && ($this->endColumnIndex >= $this->startColumnIndex)) {
183187
--$this->endColumnIndex;
184188
}
185189
}

tests/PhpSpreadsheetTests/Worksheet/ColumnCellIteratorTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ public function testSeekNotExisting(): void
112112
$iterator->seek(2);
113113
}
114114

115-
public function xtestPrevOutOfRange(): void
115+
public function testPrevOutOfRange(): void
116116
{
117117
$spreadsheet = new Spreadsheet();
118118
$sheet = self::getPopulatedSheet($spreadsheet);

0 commit comments

Comments
 (0)