Skip to content

Commit ea165dc

Browse files
authored
Merge pull request #2807 from PHPOffice/Performance-CellIterator
Update get cell logic in Cell Iterators
2 parents 4a071ce + ae09dd1 commit ea165dc

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)