diff --git a/src/PhpSpreadsheet/Calculation/Engine/Operands/StructuredReference.php b/src/PhpSpreadsheet/Calculation/Engine/Operands/StructuredReference.php index d07df80926..072e66d046 100644 --- a/src/PhpSpreadsheet/Calculation/Engine/Operands/StructuredReference.php +++ b/src/PhpSpreadsheet/Calculation/Engine/Operands/StructuredReference.php @@ -179,19 +179,28 @@ private function getRowReference(Cell $cell): string foreach ($this->columns as $columnId => $columnName) { $columnName = str_replace("\u{a0}", ' ', $columnName); + $reference = $this->adjustRowReference($columnName, $reference, $cell, $columnId); + } + + /** @var string $reference */ + return $this->validateParsedReference(trim($reference, '[]@, ')); + } + + private function adjustRowReference(string $columnName, string $reference, Cell $cell, string $columnId): string + { + if ($columnName !== '') { $cellReference = $columnId . $cell->getRow(); $pattern1 = '/\[' . preg_quote($columnName) . '\]/miu'; $pattern2 = '/@' . preg_quote($columnName) . '/miu'; - /** @var string $reference */ if (preg_match($pattern1, $reference) === 1) { $reference = preg_replace($pattern1, $cellReference, $reference); } elseif (preg_match($pattern2, $reference) === 1) { $reference = preg_replace($pattern2, $cellReference, $reference); } + /** @var string $reference */ } - /** @var string $reference */ - return $this->validateParsedReference(trim($reference, '[]@, ')); + return $reference; } /** @@ -226,7 +235,10 @@ private function validateParsedReference(string $reference): string { if (preg_match('/^' . Calculation::CALCULATION_REGEXP_CELLREF . ':' . Calculation::CALCULATION_REGEXP_CELLREF . '$/miu', $reference) !== 1) { if (preg_match('/^' . Calculation::CALCULATION_REGEXP_CELLREF . '$/miu', $reference) !== 1) { - throw new Exception("Invalid Structured Reference {$this->reference} {$reference}"); + throw new Exception( + "Invalid Structured Reference {$this->reference} {$reference}", + Exception::CALCULATION_ENGINE_PUSH_TO_STACK + ); } } diff --git a/src/PhpSpreadsheet/Cell/Cell.php b/src/PhpSpreadsheet/Cell/Cell.php index 1bf2912491..aabc94f556 100644 --- a/src/PhpSpreadsheet/Cell/Cell.php +++ b/src/PhpSpreadsheet/Cell/Cell.php @@ -198,6 +198,7 @@ public function getFormattedValue(): string */ protected static function updateIfCellIsTableHeader(Worksheet $workSheet, self $cell, $oldValue, $newValue): void { +// var_dump('=>', $oldValue, $newValue); if (StringHelper::strToLower($oldValue ?? '') === StringHelper::strToLower($newValue ?? '')) { return; } diff --git a/src/PhpSpreadsheet/Worksheet/Table/Column.php b/src/PhpSpreadsheet/Worksheet/Table/Column.php index 46d3693423..30630c0d46 100644 --- a/src/PhpSpreadsheet/Worksheet/Table/Column.php +++ b/src/PhpSpreadsheet/Worksheet/Table/Column.php @@ -205,9 +205,9 @@ public function setTable(?Table $table = null): self return $this; } - public static function updateStructuredReferences(?Worksheet $workSheet, ?string $oldTitle, string $newTitle): void + public static function updateStructuredReferences(?Worksheet $workSheet, ?string $oldTitle, ?string $newTitle): void { - if ($workSheet === null || $oldTitle === null || $oldTitle === '') { + if ($workSheet === null || $oldTitle === null || $oldTitle === '' || $newTitle === null) { return; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Engine/StructuredReferenceTest.php b/tests/PhpSpreadsheetTests/Calculation/Engine/StructuredReferenceTest.php index 92c84cb5d1..a3803c5858 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Engine/StructuredReferenceTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Engine/StructuredReferenceTest.php @@ -92,6 +92,18 @@ public function testStructuredReferenceRows(string $expectedCellRange, string $s self::assertSame($expectedCellRange, $cellRange); } + public function testInvalidStructuredReferenceRow(): void + { + $cell = $this->spreadSheet->getActiveSheet()->getCell('E5'); + + $this->expectException(Exception::class); + $this->expectExceptionCode(1); + $this->expectExceptionMessage('Invalid Structured Reference'); + $this->expectExceptionCode(Exception::CALCULATION_ENGINE_PUSH_TO_STACK); + $structuredReferenceObject = new StructuredReference('DeptSales[@[Sales]:[%age Commission]]'); + $structuredReferenceObject->parse($cell); + } + public function testStructuredReferenceHeadersHidden(): void { $cell = $this->spreadSheet->getActiveSheet()->getCell('K1'); @@ -103,11 +115,12 @@ public function testStructuredReferenceHeadersHidden(): void $table->setShowHeaderRow(false); - self::expectException(Exception::class); - self::expectExceptionCode(1); - self::expectExceptionMessage('Table Headers are Hidden, and should not be Referenced'); + $this->expectException(Exception::class); + $this->expectExceptionCode(1); + $this->expectExceptionMessage('Table Headers are Hidden, and should not be Referenced'); + $this->expectExceptionCode(Exception::CALCULATION_ENGINE_PUSH_TO_STACK); $structuredReferenceObject = new StructuredReference('DeptSales[[#Headers],[% Commission]]'); - $cellRange = $structuredReferenceObject->parse($cell); + $structuredReferenceObject->parse($cell); } public function structuredReferenceProviderColumnData(): array diff --git a/tests/PhpSpreadsheetTests/Calculation/StructuredReferenceFormulaTest.php b/tests/PhpSpreadsheetTests/Calculation/StructuredReferenceFormulaTest.php index 503ca9a093..c1fef051d8 100644 --- a/tests/PhpSpreadsheetTests/Calculation/StructuredReferenceFormulaTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/StructuredReferenceFormulaTest.php @@ -46,6 +46,21 @@ public function testStructuredReferenceHiddenHeaders(): void self::assertSame(ExcelError::REF(), $result); } + public function testStructuredReferenceInvalidColumn(): void + { + $inputFileType = 'Xlsx'; + $inputFileName = __DIR__ . '/../../data/Calculation/TableFormulae.xlsx'; + + $reader = IOFactory::createReader($inputFileType); + $spreadsheet = $reader->load($inputFileName); + + $cellAddress = 'E2'; + $spreadsheet->getActiveSheet()->getCell($cellAddress)->setValue('=[@Sales Amount]*[@[%age Commission]]'); + + $result = $spreadsheet->getActiveSheet()->getCell($cellAddress)->getCalculatedValue(); + self::assertSame(ExcelError::REF(), $result); + } + public function structuredReferenceProvider(): array { return [