-
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.
Accommodating Slash with preg_quote - Structured Reference Column Nam…
…es (#3583) PR #3513, developed by @SaidkhojaIftikhor, has been stuck for some time awaiting tests. This is the second of three PRs to replace that one. This accomodates the use of slash as a delimiter in column names in Tables and Structured References. The source changes are very simple. Additional tests exercise all the source changes. There is also a preg_quote call when a table is renamed. I have also changed it to accomodate slash, because it's the right thing to do. But ... I can't think how to test it. PhpSpreadsheet will not allow you to set a table name to a string containing a slash (a test is added to confirm), and, if I manually update the Xml in an Xlsx spreadsheet so that the name does contain a slash, Excel will, understandably, complain that the file is corrupt.
- Loading branch information
Showing
6 changed files
with
149 additions
and
7 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
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
115 changes: 115 additions & 0 deletions
115
tests/PhpSpreadsheetTests/Calculation/Engine/StructuredReferenceSlashTest.php
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,115 @@ | ||
<?php | ||
|
||
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Engine; | ||
|
||
use PhpOffice\PhpSpreadsheet\Calculation\Engine\Operands\StructuredReference; | ||
use PhpOffice\PhpSpreadsheet\Spreadsheet; | ||
use PhpOffice\PhpSpreadsheet\Worksheet\Table; | ||
use PHPUnit\Framework\TestCase; | ||
|
||
class StructuredReferenceSlashTest extends TestCase | ||
{ | ||
protected ?Spreadsheet $spreadSheet; | ||
|
||
protected const COLUMN_FORMULA = '=[@Sales Amount]*[@[% Commission]]'; | ||
|
||
// Note that column headings may contain a non-breaking space, while the formula may not; | ||
// these still need to match. | ||
// As compared to StructuredReferenceTest, the last column | ||
// "Commission/Amount" contains a slash. See PR #3513. | ||
protected array $tableData = [ | ||
["Sales\u{a0}Person", 'Region', "Sales\u{a0}Amount", "%\u{a0}Commission", 'Commission/Amount'], | ||
['Joe', 'North', 260, '10%', self::COLUMN_FORMULA], | ||
['Robert', 'South', 660, '15%', self::COLUMN_FORMULA], | ||
['Michelle', 'East', 940, '15%', self::COLUMN_FORMULA], | ||
['Erich', 'West', 410, '12%', self::COLUMN_FORMULA], | ||
['Dafna', 'North', 800, '15%', self::COLUMN_FORMULA], | ||
['Rob', 'South', 900, '15%', self::COLUMN_FORMULA], | ||
['Total'], | ||
]; | ||
|
||
protected function getSpreadsheet(): Spreadsheet | ||
{ | ||
$spreadsheet = $this->spreadSheet = new Spreadsheet(); | ||
$workSheet = $spreadsheet->getActiveSheet(); | ||
$workSheet->fromArray($this->tableData, null, 'A1'); | ||
|
||
$table = new Table('A1:E8', 'DeptSales'); | ||
$table->setShowTotalsRow(true); | ||
$table->getColumn('A')->setTotalsRowLabel('Total'); | ||
$workSheet->addTable($table); | ||
|
||
return $spreadsheet; | ||
} | ||
|
||
protected function tearDown(): void | ||
{ | ||
if ($this->spreadSheet !== null) { | ||
$this->spreadSheet->disconnectWorksheets(); | ||
$this->spreadSheet = null; | ||
} | ||
|
||
parent::tearDown(); | ||
} | ||
|
||
/** | ||
* @dataProvider structuredReferenceProviderColumnData | ||
*/ | ||
public function testStructuredReferenceColumns(string $expectedCellRange, string $structuredReference): void | ||
{ | ||
$spreadsheet = $this->getSpreadsheet(); | ||
$structuredReferenceObject = new StructuredReference($structuredReference); | ||
$cellRange = $structuredReferenceObject->parse($spreadsheet->getActiveSheet()->getCell('E5')); | ||
self::assertSame($expectedCellRange, $cellRange); | ||
} | ||
|
||
/** | ||
* @dataProvider structuredReferenceProviderRowData | ||
*/ | ||
public function testStructuredReferenceRows(string $expectedCellRange, string $structuredReference): void | ||
{ | ||
$spreadsheet = $this->getSpreadsheet(); | ||
$structuredReferenceObject = new StructuredReference($structuredReference); | ||
$cellRange = $structuredReferenceObject->parse($spreadsheet->getActiveSheet()->getCell('E5')); | ||
self::assertSame($expectedCellRange, $cellRange); | ||
} | ||
|
||
public static function structuredReferenceProviderColumnData(): array | ||
{ | ||
return [ | ||
// Full table, with no column specified, means data only, not headers or totals | ||
'Full table Unqualified' => ['A2:E7', '[]'], | ||
'Full table Qualified' => ['A2:E7', 'DeptSales[]'], | ||
// No item identifier, but with a column identifier, means data and header for the column, but no totals | ||
'Column with no Item Identifier #1' => ['A2:A7', 'DeptSales[[Sales Person]]'], | ||
'Column with no Item Identifier #2' => ['B2:B7', 'DeptSales[Region]'], | ||
// Item identifier with no column specified | ||
'Item Identifier only #1' => ['A1:E1', 'DeptSales[#Headers]'], | ||
'Item Identifier only #2' => ['A1:E1', 'DeptSales[[#Headers]]'], | ||
'Item Identifier only #3' => ['A8:E8', 'DeptSales[#Totals]'], | ||
'Item Identifier only #4' => ['A2:E7', 'DeptSales[#Data]'], | ||
// Item identifiers and column identifiers | ||
'Full column' => ['C1:C8', 'DeptSales[[#All],[Sales Amount]]'], | ||
'Column Header' => ['D1', 'DeptSales[[#Headers],[% Commission]]'], | ||
'Column Total' => ['B8', 'DeptSales[[#Totals],[Region]]'], | ||
'Column Range All' => ['C1:D8', 'DeptSales[[#All],[Sales Amount]:[% Commission]]'], | ||
'Column Range Data' => ['D2:E7', 'DeptSales[[#Data],[% Commission]:[Commission/Amount]]'], | ||
'Column Range Headers' => ['B1:E1', 'DeptSales[[#Headers],[Region]:[Commission/Amount]]'], | ||
'Column Range Totals' => ['C8:E8', 'DeptSales[[#Totals],[Sales Amount]:[Commission/Amount]]'], | ||
'Column Range Headers and Data' => ['D1:D7', 'DeptSales[[#Headers],[#Data],[% Commission]]'], | ||
'Column Range No Item Identifier' => ['A2:B7', 'DeptSales[[Sales Person]:[Region]]'], | ||
// ['C2:C7,E2:E7', 'DeptSales[Sales Amount],DeptSales[Commission Amount]'], | ||
// ['B2:C7', 'DeptSales[[Sales Person]:[Sales Amount]] DeptSales[[Region]:[% Commission]]'], | ||
]; | ||
} | ||
|
||
public static function structuredReferenceProviderRowData(): array | ||
{ | ||
return [ | ||
['E5', 'DeptSales[[#This Row], [Commission/Amount]]'], | ||
['E5', 'DeptSales[@Commission/Amount]'], | ||
['E5', 'DeptSales[@[Commission/Amount]]'], | ||
['C5:D5', 'DeptSales[@[Sales Amount]:[% Commission]]'], | ||
]; | ||
} | ||
} |
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