-
Notifications
You must be signed in to change notification settings - Fork 3.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
First step extracting INDIRECT() and OFFSET() to their own classes (#…
…1921) * First step extracting INDIRECT() and OFFSET() to their own classes * Start building unit tests for OFFSET() and INDEX() * Named ranges should be handled by the Calculation Engine, not by the implementation of the Excel INDIRECT() function * When calling the calculation engine to get the range of cells to return, INDIRECT() and OFFSET() should use the instance of the calculation engine for the current workbook to benefit from cached results in that range There's a couple of minor bugfixes in here; but it's basically just refactoring of the INDIRECT() and OFFSET() Excel functions into their own classes - still needs a lot of work on unit testing; and there's a lot more that could be improved in the code itself (including handling of the a1 flag for R1C1 format in INDIRECT()
- Loading branch information
Mark Baker
authored
Mar 14, 2021
1 parent
af9253d
commit ed62526
Showing
10 changed files
with
426 additions
and
121 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
<?php | ||
|
||
use PhpOffice\PhpSpreadsheet\NamedRange; | ||
use PhpOffice\PhpSpreadsheet\Spreadsheet; | ||
|
||
require __DIR__ . '/../../Header.php'; | ||
|
||
$helper->log('Returns the cell specified by a text string.'); | ||
|
||
// Create new PhpSpreadsheet object | ||
$spreadsheet = new Spreadsheet(); | ||
$worksheet = $spreadsheet->getActiveSheet(); | ||
|
||
$data = [ | ||
[8, 9, 0], | ||
[3, 4, 5], | ||
[9, 1, 3], | ||
[4, 6, 2], | ||
]; | ||
$worksheet->fromArray($data, null, 'C1'); | ||
|
||
$spreadsheet->addNamedRange(new NamedRange('NAMED_RANGE_FOR_CELL_D4', $worksheet, '="$D$4"')); | ||
|
||
$worksheet->getCell('A1')->setValue('=INDIRECT("C1")'); | ||
$worksheet->getCell('A2')->setValue('=INDIRECT("D"&4)'); | ||
$worksheet->getCell('A3')->setValue('=INDIRECT("E"&ROW())'); | ||
$worksheet->getCell('A4')->setValue('=SUM(INDIRECT("$C$4:$E$4"))'); | ||
$worksheet->getCell('A5')->setValue('=INDIRECT(NAMED_RANGE_FOR_CELL_D4)'); | ||
|
||
for ($row = 1; $row <= 5; ++$row) { | ||
$cell = $worksheet->getCell("A{$row}"); | ||
$helper->log("A{$row}: {$cell->getValue()} => {$cell->getCalculatedValue()}"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
<?php | ||
|
||
use PhpOffice\PhpSpreadsheet\Spreadsheet; | ||
|
||
require __DIR__ . '/../../Header.php'; | ||
|
||
$helper->log('Returns a cell range that is a specified number of rows and columns from a cell or range of cells.'); | ||
|
||
// Create new PhpSpreadsheet object | ||
$spreadsheet = new Spreadsheet(); | ||
$worksheet = $spreadsheet->getActiveSheet(); | ||
|
||
$data = [ | ||
[null, 'Week 1', 'Week 2', 'Week 3', 'Week 4'], | ||
['Sunday', 4500, 2200, 3800, 1500], | ||
['Monday', 5500, 6100, 5200, 4800], | ||
['Tuesday', 7000, 6200, 5000, 7100], | ||
['Wednesday', 8000, 4000, 3900, 7600], | ||
['Thursday', 5900, 5500, 6900, 7100], | ||
['Friday', 4900, 6300, 6900, 5200], | ||
['Saturday', 3500, 3900, 5100, 4100], | ||
]; | ||
$worksheet->fromArray($data, null, 'A3'); | ||
|
||
$worksheet->getCell('H1')->setValue('=OFFSET(A3, 3, 1)'); | ||
$worksheet->getCell('H2')->setValue('=SUM(OFFSET(A3, 3, 1, 1, 4))'); | ||
$worksheet->getCell('H3')->setValue('=SUM(OFFSET(B3:E3, 3, 0))'); | ||
$worksheet->getCell('H4')->setValue('=SUM(OFFSET(E3, 1, -3, 7))'); | ||
|
||
for ($row = 1; $row <= 4; ++$row) { | ||
$cell = $worksheet->getCell("H{$row}"); | ||
$helper->log("H{$row}: {$cell->getValue()} => {$cell->getCalculatedValue()}"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
<?php | ||
|
||
namespace PhpOffice\PhpSpreadsheet\Calculation\LookupRef; | ||
|
||
use PhpOffice\PhpSpreadsheet\Calculation\Calculation; | ||
use PhpOffice\PhpSpreadsheet\Calculation\Functions; | ||
use PhpOffice\PhpSpreadsheet\Cell\Cell; | ||
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; | ||
|
||
class Indirect | ||
{ | ||
/** | ||
* INDIRECT. | ||
* | ||
* Returns the reference specified by a text string. | ||
* References are immediately evaluated to display their contents. | ||
* | ||
* Excel Function: | ||
* =INDIRECT(cellAddress) | ||
* | ||
* NOTE - INDIRECT() does not yet support the optional a1 parameter introduced in Excel 2010 | ||
* | ||
* @param null|array|string $cellAddress $cellAddress The cell address of the current cell (containing this formula) | ||
* @param Cell $pCell The current cell (containing this formula) | ||
* | ||
* @return array|string An array containing a cell or range of cells, or a string on error | ||
* | ||
* @TODO Support for the optional a1 parameter introduced in Excel 2010 | ||
*/ | ||
public static function INDIRECT($cellAddress = null, ?Cell $pCell = null) | ||
{ | ||
$cellAddress = Functions::flattenSingleValue($cellAddress); | ||
if ($cellAddress === null || $cellAddress === '' || !is_object($pCell)) { | ||
return Functions::REF(); | ||
} | ||
|
||
[$cellAddress, $pSheet] = self::extractWorksheet($cellAddress, $pCell); | ||
|
||
$cellAddress1 = $cellAddress; | ||
$cellAddress2 = null; | ||
if (strpos($cellAddress, ':') !== false) { | ||
[$cellAddress1, $cellAddress2] = explode(':', $cellAddress); | ||
} | ||
|
||
if ( | ||
(!preg_match('/^' . Calculation::CALCULATION_REGEXP_CELLREF . '$/i', $cellAddress1, $matches)) || | ||
(($cellAddress2 !== null) && (!preg_match('/^' . Calculation::CALCULATION_REGEXP_CELLREF . '$/i', $cellAddress2, $matches))) | ||
) { | ||
return Functions::REF(); | ||
} | ||
|
||
return self::extractRequiredCells($pSheet, $cellAddress); | ||
} | ||
|
||
private static function extractRequiredCells(?Worksheet $pSheet, string $cellAddress) | ||
{ | ||
return Calculation::getInstance($pSheet !== null ? $pSheet->getParent() : null) | ||
->extractCellRange($cellAddress, $pSheet, false); | ||
} | ||
|
||
private static function extractWorksheet($cellAddress, Cell $pCell): array | ||
{ | ||
$sheetName = ''; | ||
if (strpos($cellAddress, '!') !== false) { | ||
[$sheetName, $cellAddress] = Worksheet::extractSheetTitle($cellAddress, true); | ||
$sheetName = trim($sheetName, "'"); | ||
} | ||
|
||
$pSheet = ($sheetName !== '') | ||
? $pCell->getWorksheet()->getParent()->getSheetByName($sheetName) | ||
: $pCell->getWorksheet(); | ||
|
||
return [$cellAddress, $pSheet]; | ||
} | ||
} |
Oops, something went wrong.