Skip to content

Commit 1c333d1

Browse files
committed
Reference to Defined Name Specifying Worksheet Name
Fix #296, another entry in our magical history tour (closed as stale in 2018). Excel allows you to use a name defined on another worksheet by prefixing the sheet name, even when the scope of the defined name is its worksheet rather than the entire workbook.
1 parent 1b68270 commit 1c333d1

File tree

2 files changed

+57
-4
lines changed

2 files changed

+57
-4
lines changed

src/PhpSpreadsheet/Calculation/Calculation.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5074,9 +5074,10 @@ private function processTokenStack(mixed $tokens, ?string $cellID = null, ?Cell
50745074
if ($cell === null || $pCellWorksheet === null) {
50755075
return $this->raiseFormulaError("undefined name '$token'");
50765076
}
5077+
$specifiedWorksheet = trim($matches[2], "'");
50775078

50785079
$this->debugLog->writeDebugLog('Evaluating Defined Name %s', $definedName);
5079-
$namedRange = DefinedName::resolveName($definedName, $pCellWorksheet);
5080+
$namedRange = DefinedName::resolveName($definedName, $pCellWorksheet, $specifiedWorksheet);
50805081
// If not Defined Name, try as Table.
50815082
if ($namedRange === null && $this->spreadsheet !== null) {
50825083
$table = $this->spreadsheet->getTableByName($definedName);
@@ -5101,7 +5102,7 @@ private function processTokenStack(mixed $tokens, ?string $cellID = null, ?Cell
51015102
return $this->raiseFormulaError("undefined name '$definedName'");
51025103
}
51035104

5104-
$result = $this->evaluateDefinedName($cell, $namedRange, $pCellWorksheet, $stack);
5105+
$result = $this->evaluateDefinedName($cell, $namedRange, $pCellWorksheet, $stack, $specifiedWorksheet !== '');
51055106
if (isset($storeKey)) {
51065107
$branchStore[$storeKey] = $result;
51075108
}
@@ -5580,10 +5581,10 @@ private function addCellReference(array $args, bool $passCellReference, array|st
55805581
return $args;
55815582
}
55825583

5583-
private function evaluateDefinedName(Cell $cell, DefinedName $namedRange, Worksheet $cellWorksheet, Stack $stack): mixed
5584+
private function evaluateDefinedName(Cell $cell, DefinedName $namedRange, Worksheet $cellWorksheet, Stack $stack, bool $ignoreScope = false): mixed
55845585
{
55855586
$definedNameScope = $namedRange->getScope();
5586-
if ($definedNameScope !== null && $definedNameScope !== $cellWorksheet) {
5587+
if ($definedNameScope !== null && $definedNameScope !== $cellWorksheet && !$ignoreScope) {
55875588
// The defined name isn't in our current scope, so #REF
55885589
$result = ExcelError::REF();
55895590
$stack->push('Error', $result, $namedRange->getName());
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpOffice\PhpSpreadsheetTests;
6+
7+
use PhpOffice\PhpSpreadsheet\NamedRange;
8+
use PhpOffice\PhpSpreadsheet\Spreadsheet;
9+
use PHPUnit\Framework\TestCase;
10+
11+
class NamedRange3Test extends TestCase
12+
{
13+
public function testSheetNamePlusDefinedName(): void
14+
{
15+
$spreadsheet = new Spreadsheet();
16+
$sheet1 = $spreadsheet->getActiveSheet();
17+
$sheet1->setTitle('sheet1');
18+
$sheet1->setCellValue('B1', 100);
19+
$sheet1->setCellValue('B2', 200);
20+
$sheet1->setCellValue('B3', 300);
21+
$sheet1->setCellValue('B4', 400);
22+
$sheet1->setCellValue('B5', 500);
23+
24+
$sheet2 = $spreadsheet->createsheet();
25+
$sheet2->setTitle('sheet2');
26+
$sheet2->setCellValue('A1', 10);
27+
$sheet2->setCellValue('A2', 20);
28+
$sheet2->setCellValue('A3', 30);
29+
$sheet2->setCellValue('A4', 40);
30+
$sheet2->setCellValue('A5', 50);
31+
32+
$spreadsheet->addNamedRange(
33+
new NamedRange('somecells', $sheet2, '$A$1:$A$5', true)
34+
);
35+
$spreadsheet->addNamedRange(
36+
new NamedRange('cellsonsheet1', $sheet1, '$B$1:$B$5')
37+
);
38+
39+
$sheet1->getCell('G1')->setValue('=SUM(cellsonsheet1)');
40+
self::assertSame(1500, $sheet1->getCell('G1')->getCalculatedValue());
41+
$sheet1->getCell('G2')->setValue('=SUM(sheet2!somecells)');
42+
self::assertSame(150, $sheet1->getCell('G2')->getCalculatedValue());
43+
$sheet1->getCell('G3')->setValue('=SUM(somecells)');
44+
self::assertSame('#NAME?', $sheet1->getCell('G3')->getCalculatedValue());
45+
$sheet1->getCell('G4')->setValue('=SUM(sheet2!cellsonsheet1)');
46+
self::assertSame(1500, $sheet1->getCell('G4')->getCalculatedValue());
47+
$sheet1->getCell('G5')->setValue('=SUM(sheet2xxx!cellsonsheet1)');
48+
self::assertSame('#NAME?', $sheet1->getCell('G5')->getCalculatedValue());
49+
50+
$spreadsheet->disconnectWorksheets();
51+
}
52+
}

0 commit comments

Comments
 (0)