From 269e9ba14de6e26e60eda088a58f53e359cef9a8 Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Fri, 19 Aug 2022 11:28:51 +0200 Subject: [PATCH] Bugfix for Issue #3013, Named ranges not usable as anchors in OFFSET function --- src/PhpSpreadsheet/Calculation/Functions.php | 2 +- .../Calculation/LookupRef/Offset.php | 11 ++++++ .../Functions/LookupRef/HLookupTest.php | 39 +++++++++++++++++++ .../Functions/LookupRef/OffsetTest.php | 15 +++++++ 4 files changed, 66 insertions(+), 1 deletion(-) diff --git a/src/PhpSpreadsheet/Calculation/Functions.php b/src/PhpSpreadsheet/Calculation/Functions.php index b3d6998c..172f2022 100644 --- a/src/PhpSpreadsheet/Calculation/Functions.php +++ b/src/PhpSpreadsheet/Calculation/Functions.php @@ -687,7 +687,7 @@ class Functions $worksheet2 = $defined->getWorkSheet(); if (!$defined->isFormula() && $worksheet2 !== null) { $coordinate = "'" . $worksheet2->getTitle() . "'!" . - (string) preg_replace('/^=/', '', $defined->getValue()); + (string) preg_replace('/^=/', '', str_replace('$', '', $defined->getValue())); } } diff --git a/src/PhpSpreadsheet/Calculation/LookupRef/Offset.php b/src/PhpSpreadsheet/Calculation/LookupRef/Offset.php index 9f3377f6..02a25581 100644 --- a/src/PhpSpreadsheet/Calculation/LookupRef/Offset.php +++ b/src/PhpSpreadsheet/Calculation/LookupRef/Offset.php @@ -99,6 +99,8 @@ class Offset private static function extractWorksheet($cellAddress, Cell $cell): array { + $cellAddress = self::assessCellAddress($cellAddress, $cell); + $sheetName = ''; if (strpos($cellAddress, '!') !== false) { [$sheetName, $cellAddress] = Worksheet::extractSheetTitle($cellAddress, true); @@ -112,6 +114,15 @@ class Offset return [$cellAddress, $worksheet]; } + private static function assessCellAddress(string $cellAddress, Cell $cell): string + { + if (preg_match('/^' . Calculation::CALCULATION_REGEXP_DEFINEDNAME . '$/mui', $cellAddress) !== false) { + $cellAddress = Functions::expandDefinedName($cellAddress, $cell); + } + + return $cellAddress; + } + private static function adjustEndCellColumnForWidth(string $endCellColumn, $width, int $startCellColumn, $columns) { $endCellColumn = Coordinate::columnIndexFromString($endCellColumn) - 1; diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/HLookupTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/HLookupTest.php index 0ce3513b..084e3d9f 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/HLookupTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/HLookupTest.php @@ -5,6 +5,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\LookupRef; use PhpOffice\PhpSpreadsheet\Calculation\Calculation; use PhpOffice\PhpSpreadsheet\Calculation\LookupRef; use PhpOffice\PhpSpreadsheet\Cell\Coordinate; +use PhpOffice\PhpSpreadsheet\NamedRange; use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; @@ -91,6 +92,44 @@ class HLookupTest extends TestCase self::assertSame($expectedResult, $result); } + /** + * @dataProvider providerHLookupNamedRange + */ + public function testHLookupNamedRange(string $expectedResult, string $cellAddress): void + { + $lookupData = [ + ['Rating', 1, 2, 3, 4], + ['Level', 'Poor', 'Average', 'Good', 'Excellent'], + ]; + $formData = [ + ['Category', 'Rating', 'Level'], + ['Service', 2, '=HLOOKUP(C5,Lookup_Table,2,FALSE)'], + ['Quality', 3, '=HLOOKUP(C6,Lookup_Table,2,FALSE)'], + ['Value', 4, '=HLOOKUP(C7,Lookup_Table,2,FALSE)'], + ['Cleanliness', 3, '=HLOOKUP(C8,Lookup_Table,2,FALSE)'], + ]; + + $spreadsheet = new Spreadsheet(); + $worksheet = $spreadsheet->getActiveSheet(); + $worksheet->fromArray($lookupData, null, 'F4'); + $worksheet->fromArray($formData, null, 'B4'); + + $spreadsheet->addNamedRange(new NamedRange('Lookup_Table', $worksheet, '=$G$4:$J$5')); + + $result = $worksheet->getCell($cellAddress)->getCalculatedValue(); + self::assertEquals($expectedResult, $result); + } + + public function providerHLookupNamedRange(): array + { + return [ + ['Average', 'D5'], + ['Good', 'D6'], + ['Excellent', 'D7'], + ['Good', 'D8'], + ]; + } + /** * @dataProvider providerHLookupArray */ diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/OffsetTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/OffsetTest.php index e0786505..22787e25 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/OffsetTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/OffsetTest.php @@ -3,6 +3,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\LookupRef; use PhpOffice\PhpSpreadsheet\Calculation\LookupRef; +use PhpOffice\PhpSpreadsheet\NamedRange; class OffsetTest extends AllSetupTeardown { @@ -46,4 +47,18 @@ class OffsetTest extends AllSetupTeardown $sheet->getCell('A5')->setValue('=OFFSET(C1, 0, 0)'); self::assertSame(5, $sheet->getCell('A5')->getCalculatedValue()); } + + public function testOffsetNamedRange(): void + { + $workSheet = $this->getSheet(); + $workSheet->setCellValue('A1', 1); + $workSheet->setCellValue('A2', 2); + + $this->getSpreadsheet()->addNamedRange(new NamedRange('demo', $workSheet, '=$A$1')); + + $workSheet->setCellValue('B1', '=demo'); + $workSheet->setCellValue('B2', '=OFFSET(demo, 1, 0)'); + + self::assertSame(2, $workSheet->getCell('B2')->getCalculatedValue()); + } }