Skip to content

Commit 5419eee

Browse files
authored
Merge pull request #3311 from PHPOffice/StructuredReference_Invalid-Column-return-#REF!
For Structured References, an Invalid column reference should return an Excel #REF! error
2 parents 84e4896 + 346ec07 commit 5419eee

File tree

5 files changed

+51
-10
lines changed

5 files changed

+51
-10
lines changed

src/PhpSpreadsheet/Calculation/Engine/Operands/StructuredReference.php

+16-4
Original file line numberDiff line numberDiff line change
@@ -179,19 +179,28 @@ private function getRowReference(Cell $cell): string
179179

180180
foreach ($this->columns as $columnId => $columnName) {
181181
$columnName = str_replace("\u{a0}", ' ', $columnName);
182+
$reference = $this->adjustRowReference($columnName, $reference, $cell, $columnId);
183+
}
184+
185+
/** @var string $reference */
186+
return $this->validateParsedReference(trim($reference, '[]@, '));
187+
}
188+
189+
private function adjustRowReference(string $columnName, string $reference, Cell $cell, string $columnId): string
190+
{
191+
if ($columnName !== '') {
182192
$cellReference = $columnId . $cell->getRow();
183193
$pattern1 = '/\[' . preg_quote($columnName) . '\]/miu';
184194
$pattern2 = '/@' . preg_quote($columnName) . '/miu';
185-
/** @var string $reference */
186195
if (preg_match($pattern1, $reference) === 1) {
187196
$reference = preg_replace($pattern1, $cellReference, $reference);
188197
} elseif (preg_match($pattern2, $reference) === 1) {
189198
$reference = preg_replace($pattern2, $cellReference, $reference);
190199
}
200+
/** @var string $reference */
191201
}
192202

193-
/** @var string $reference */
194-
return $this->validateParsedReference(trim($reference, '[]@, '));
203+
return $reference;
195204
}
196205

197206
/**
@@ -226,7 +235,10 @@ private function validateParsedReference(string $reference): string
226235
{
227236
if (preg_match('/^' . Calculation::CALCULATION_REGEXP_CELLREF . ':' . Calculation::CALCULATION_REGEXP_CELLREF . '$/miu', $reference) !== 1) {
228237
if (preg_match('/^' . Calculation::CALCULATION_REGEXP_CELLREF . '$/miu', $reference) !== 1) {
229-
throw new Exception("Invalid Structured Reference {$this->reference} {$reference}");
238+
throw new Exception(
239+
"Invalid Structured Reference {$this->reference} {$reference}",
240+
Exception::CALCULATION_ENGINE_PUSH_TO_STACK
241+
);
230242
}
231243
}
232244

src/PhpSpreadsheet/Cell/Cell.php

+1
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ public function getFormattedValue(): string
198198
*/
199199
protected static function updateIfCellIsTableHeader(Worksheet $workSheet, self $cell, $oldValue, $newValue): void
200200
{
201+
// var_dump('=>', $oldValue, $newValue);
201202
if (StringHelper::strToLower($oldValue ?? '') === StringHelper::strToLower($newValue ?? '')) {
202203
return;
203204
}

src/PhpSpreadsheet/Worksheet/Table/Column.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -205,9 +205,9 @@ public function setTable(?Table $table = null): self
205205
return $this;
206206
}
207207

208-
public static function updateStructuredReferences(?Worksheet $workSheet, ?string $oldTitle, string $newTitle): void
208+
public static function updateStructuredReferences(?Worksheet $workSheet, ?string $oldTitle, ?string $newTitle): void
209209
{
210-
if ($workSheet === null || $oldTitle === null || $oldTitle === '') {
210+
if ($workSheet === null || $oldTitle === null || $oldTitle === '' || $newTitle === null) {
211211
return;
212212
}
213213

tests/PhpSpreadsheetTests/Calculation/Engine/StructuredReferenceTest.php

+17-4
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,18 @@ public function testStructuredReferenceRows(string $expectedCellRange, string $s
9292
self::assertSame($expectedCellRange, $cellRange);
9393
}
9494

95+
public function testInvalidStructuredReferenceRow(): void
96+
{
97+
$cell = $this->spreadSheet->getActiveSheet()->getCell('E5');
98+
99+
$this->expectException(Exception::class);
100+
$this->expectExceptionCode(1);
101+
$this->expectExceptionMessage('Invalid Structured Reference');
102+
$this->expectExceptionCode(Exception::CALCULATION_ENGINE_PUSH_TO_STACK);
103+
$structuredReferenceObject = new StructuredReference('DeptSales[@[Sales]:[%age Commission]]');
104+
$structuredReferenceObject->parse($cell);
105+
}
106+
95107
public function testStructuredReferenceHeadersHidden(): void
96108
{
97109
$cell = $this->spreadSheet->getActiveSheet()->getCell('K1');
@@ -103,11 +115,12 @@ public function testStructuredReferenceHeadersHidden(): void
103115

104116
$table->setShowHeaderRow(false);
105117

106-
self::expectException(Exception::class);
107-
self::expectExceptionCode(1);
108-
self::expectExceptionMessage('Table Headers are Hidden, and should not be Referenced');
118+
$this->expectException(Exception::class);
119+
$this->expectExceptionCode(1);
120+
$this->expectExceptionMessage('Table Headers are Hidden, and should not be Referenced');
121+
$this->expectExceptionCode(Exception::CALCULATION_ENGINE_PUSH_TO_STACK);
109122
$structuredReferenceObject = new StructuredReference('DeptSales[[#Headers],[% Commission]]');
110-
$cellRange = $structuredReferenceObject->parse($cell);
123+
$structuredReferenceObject->parse($cell);
111124
}
112125

113126
public function structuredReferenceProviderColumnData(): array

tests/PhpSpreadsheetTests/Calculation/StructuredReferenceFormulaTest.php

+15
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,21 @@ public function testStructuredReferenceHiddenHeaders(): void
4646
self::assertSame(ExcelError::REF(), $result);
4747
}
4848

49+
public function testStructuredReferenceInvalidColumn(): void
50+
{
51+
$inputFileType = 'Xlsx';
52+
$inputFileName = __DIR__ . '/../../data/Calculation/TableFormulae.xlsx';
53+
54+
$reader = IOFactory::createReader($inputFileType);
55+
$spreadsheet = $reader->load($inputFileName);
56+
57+
$cellAddress = 'E2';
58+
$spreadsheet->getActiveSheet()->getCell($cellAddress)->setValue('=[@Sales Amount]*[@[%age Commission]]');
59+
60+
$result = $spreadsheet->getActiveSheet()->getCell($cellAddress)->getCalculatedValue();
61+
self::assertSame(ExcelError::REF(), $result);
62+
}
63+
4964
public function structuredReferenceProvider(): array
5065
{
5166
return [

0 commit comments

Comments
 (0)