Skip to content

For Structured References, an Invalid column reference should return an Excel #REF! error #3311

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

/**
Expand Down Expand Up @@ -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
);
}
}

Expand Down
1 change: 1 addition & 0 deletions src/PhpSpreadsheet/Cell/Cell.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
4 changes: 2 additions & 2 deletions src/PhpSpreadsheet/Worksheet/Table/Column.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 [
Expand Down