diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 3d6ede90..583ad66e 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1334,12 +1334,12 @@ parameters: message: "#^Unreachable statement \\- code above always terminates\\.$#" count: 8 path: src/PhpSpreadsheet/Reader/Xls.php - + - message: "#^Cannot access property \\$r on SimpleXMLElement\\|null\\.$#" count: 2 path: src/PhpSpreadsheet/Reader/Xlsx.php - + - message: "#^Parameter \\#1 \\$haystack of function strpos expects string, string\\|false given\\.$#" count: 1 @@ -2684,3 +2684,4 @@ parameters: message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Xf\\:\\:\\$diag is never read, only written\\.$#" count: 1 path: src/PhpSpreadsheet/Writer/Xls/Xf.php + diff --git a/samples/Table/01_Table.php b/samples/Table/01_Table.php index 476f187c..eebd60d1 100644 --- a/samples/Table/01_Table.php +++ b/samples/Table/01_Table.php @@ -1,6 +1,7 @@ getActiveSheet()->fromArray($dataArray, null, 'A2'); // Create Table $helper->log('Create Table'); -$table = new Table('A1:D17', 'Sales_Data'); +$table = new Table('A1:D33', 'Sales_Data'); // Create Columns $table->getColumn('D')->setShowFilterButton(false); +$table->getAutoFilter()->getColumn('A') + ->setFilterType(AutoFilter\Column::AUTOFILTER_FILTERTYPE_CUSTOMFILTER) + ->createRule() + ->setRule(AutoFilter\Column\Rule::AUTOFILTER_COLUMN_RULE_GREATERTHANOREQUAL, 2011) + ->setRuleType(AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_CUSTOMFILTER); // Create Table Style $helper->log('Create Table Style'); diff --git a/src/PhpSpreadsheet/Reader/Xlsx.php b/src/PhpSpreadsheet/Reader/Xlsx.php index e248a623..8ae68503 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx.php +++ b/src/PhpSpreadsheet/Reader/Xlsx.php @@ -19,6 +19,7 @@ use PhpOffice\PhpSpreadsheet\Reader\Xlsx\Properties as PropertyReader; use PhpOffice\PhpSpreadsheet\Reader\Xlsx\SheetViewOptions; use PhpOffice\PhpSpreadsheet\Reader\Xlsx\SheetViews; use PhpOffice\PhpSpreadsheet\Reader\Xlsx\Styles; +use PhpOffice\PhpSpreadsheet\Reader\Xlsx\TableReader; use PhpOffice\PhpSpreadsheet\Reader\Xlsx\Theme; use PhpOffice\PhpSpreadsheet\Reader\Xlsx\WorkbookView; use PhpOffice\PhpSpreadsheet\ReferenceHelper; @@ -908,7 +909,8 @@ class Xlsx extends BaseReader } if ($this->readDataOnly === false) { - $this->readAutoFilterTables($xmlSheet, $docSheet, $dir, $fileWorksheet, $zip); + $this->readAutoFilter($xmlSheet, $docSheet); + $this->readTables($xmlSheet, $docSheet, $dir, $fileWorksheet, $zip); } if ($xmlSheet && $xmlSheet->mergeCells && $xmlSheet->mergeCells->mergeCell && !$this->readDataOnly) { @@ -2088,23 +2090,28 @@ class Xlsx extends BaseReader } } - private function readAutoFilterTables( + private function readAutoFilter( + SimpleXMLElement $xmlSheet, + Worksheet $docSheet + ): void { + if ($xmlSheet && $xmlSheet->autoFilter) { + (new AutoFilter($docSheet, $xmlSheet))->load(); + } + } + + private function readTables( SimpleXMLElement $xmlSheet, Worksheet $docSheet, string $dir, string $fileWorksheet, ZipArchive $zip ): void { - if ($xmlSheet && $xmlSheet->autoFilter) { - // In older files, autofilter structure is defined in the worksheet file - (new AutoFilter($docSheet, $xmlSheet))->load(); - } elseif ($xmlSheet && $xmlSheet->tableParts && (int) $xmlSheet->tableParts['count'] > 0) { - // But for Office365, MS decided to make it all just a bit more complicated - $this->readAutoFilterTablesInTablesFile($xmlSheet, $dir, $fileWorksheet, $zip, $docSheet); + if ($xmlSheet && $xmlSheet->tableParts && (int) $xmlSheet->tableParts['count'] > 0) { + $this->readTablesInTablesFile($xmlSheet, $dir, $fileWorksheet, $zip, $docSheet); } } - private function readAutoFilterTablesInTablesFile( + private function readTablesInTablesFile( SimpleXMLElement $xmlSheet, string $dir, string $fileWorksheet, @@ -2127,8 +2134,8 @@ class Xlsx extends BaseReader $relationshipFilePath = File::realpath($relationshipFilePath); if ($this->fileExistsInArchive($this->zip, $relationshipFilePath)) { - $autoFilter = $this->loadZip($relationshipFilePath); - (new AutoFilter($docSheet, $autoFilter))->load(); + $tableXml = $this->loadZip($relationshipFilePath); + (new TableReader($docSheet, $tableXml))->load(); } } } diff --git a/src/PhpSpreadsheet/Reader/Xlsx/AutoFilter.php b/src/PhpSpreadsheet/Reader/Xlsx/AutoFilter.php index 39328adb..a6ab4d89 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx/AutoFilter.php +++ b/src/PhpSpreadsheet/Reader/Xlsx/AutoFilter.php @@ -4,20 +4,28 @@ namespace PhpOffice\PhpSpreadsheet\Reader\Xlsx; use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column; use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule; +use PhpOffice\PhpSpreadsheet\Worksheet\Table; use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; use SimpleXMLElement; class AutoFilter { - /** @var Worksheet */ - private $worksheet; + /** + * @var Table|Worksheet + */ + private $parent; - /** @var SimpleXMLElement */ + /** + * @var SimpleXMLElement + */ private $worksheetXml; - public function __construct(Worksheet $workSheet, SimpleXMLElement $worksheetXml) + /** + * @param Table|Worksheet $parent + */ + public function __construct($parent, SimpleXMLElement $worksheetXml) { - $this->worksheet = $workSheet; + $this->parent = $parent; $this->worksheetXml = $worksheetXml; } @@ -32,7 +40,7 @@ class AutoFilter private function readAutoFilter(string $autoFilterRange, SimpleXMLElement $xmlSheet): void { - $autoFilter = $this->worksheet->getAutoFilter(); + $autoFilter = $this->parent->getAutoFilter(); $autoFilter->setRange($autoFilterRange); foreach ($xmlSheet->autoFilter->filterColumn as $filterColumn) { diff --git a/src/PhpSpreadsheet/Reader/Xlsx/TableReader.php b/src/PhpSpreadsheet/Reader/Xlsx/TableReader.php new file mode 100644 index 00000000..13df1c25 --- /dev/null +++ b/src/PhpSpreadsheet/Reader/Xlsx/TableReader.php @@ -0,0 +1,107 @@ +worksheet = $workSheet; + $this->tableXml = $tableXml; + } + + /** + * Loads Table into the Worksheet. + */ + public function load(): void + { + // Remove all "$" in the table range + $tableRange = (string) preg_replace('/\$/', '', $this->tableXml['ref'] ?? ''); + if (strpos($tableRange, ':') !== false) { + $this->readTable($tableRange, $this->tableXml); + } + } + + /** + * Read Table from xml. + */ + private function readTable(string $tableRange, SimpleXMLElement $tableXml): void + { + $table = new Table($tableRange); + $table->setName((string) $tableXml['displayName']); + $table->setShowHeaderRow((string) $tableXml['headerRowCount'] !== '0'); + $table->setShowTotalsRow((string) $tableXml['totalsRowCount'] === '1'); + + $this->readTableAutoFilter($table, $tableXml->autoFilter); + $this->readTableColumns($table, $tableXml->tableColumns); + $this->readTableStyle($table, $tableXml->tableStyleInfo); + + (new AutoFilter($table, $tableXml))->load(); + $this->worksheet->addTable($table); + } + + /** + * Reads TableAutoFilter from xml. + */ + private function readTableAutoFilter(Table $table, SimpleXMLElement $autoFilterXml): void + { + foreach ($autoFilterXml->filterColumn as $filterColumn) { + $column = $table->getColumnByOffset((int) $filterColumn['colId']); + $column->setShowFilterButton((string) $filterColumn['hiddenButton'] !== '1'); + } + } + + /** + * Reads TableColumns from xml. + */ + private function readTableColumns(Table $table, SimpleXMLElement $tableColumnsXml): void + { + $offset = 0; + foreach ($tableColumnsXml->tableColumn as $tableColumn) { + $column = $table->getColumnByOffset($offset++); + + if ($table->getShowTotalsRow()) { + if ($tableColumn['totalsRowLabel']) { + $column->setTotalsRowLabel((string) $tableColumn['totalsRowLabel']); + } + + if ($tableColumn['totalsRowFunction']) { + $column->setTotalsRowFunction((string) $tableColumn['totalsRowFunction']); + } + } + + if ($tableColumn->calculatedColumnFormula) { + $column->setColumnFormula((string) $tableColumn->calculatedColumnFormula); + } + } + } + + /** + * Reads TableStyle from xml. + */ + private function readTableStyle(Table $table, SimpleXMLElement $tableStyleInfoXml): void + { + $tableStyle = new TableStyle(); + $tableStyle->setTheme((string) $tableStyleInfoXml['name']); + $tableStyle->setShowRowStripes((string) $tableStyleInfoXml['showRowStripes'] === '1'); + $tableStyle->setShowColumnStripes((string) $tableStyleInfoXml['showColumnStripes'] === '1'); + $tableStyle->setShowFirstColumn((string) $tableStyleInfoXml['showFirstColumn'] === '1'); + $tableStyle->setShowLastColumn((string) $tableStyleInfoXml['showLastColumn'] === '1'); + $table->setStyle($tableStyle); + } +} diff --git a/src/PhpSpreadsheet/Worksheet/Table.php b/src/PhpSpreadsheet/Worksheet/Table.php index ffdbf9a7..e2da5c4f 100644 --- a/src/PhpSpreadsheet/Worksheet/Table.php +++ b/src/PhpSpreadsheet/Worksheet/Table.php @@ -59,6 +59,13 @@ class Table */ private $style; + /** + * Table AutoFilter. + * + * @var AutoFilter + */ + private $autoFilter; + /** * Create a new Table. * @@ -70,9 +77,10 @@ class Table */ public function __construct($range = '', string $name = '') { + $this->style = new TableStyle(); + $this->autoFilter = new AutoFilter($range); $this->setRange($range); $this->setName($name); - $this->style = new TableStyle(); } /** @@ -193,6 +201,8 @@ class Table } $this->range = $range; + $this->autoFilter->setRange($range); + // Discard any column ruless that are no longer valid within this range [$rangeStart, $rangeEnd] = Coordinate::rangeBoundaries($this->range); foreach ($this->columns as $key => $value) { @@ -248,6 +258,7 @@ class Table } $this->workSheet = $worksheet; + $this->autoFilter->setParent($worksheet); return $this; } @@ -415,6 +426,24 @@ class Table return $this; } + /** + * Get AutoFilter. + */ + public function getAutoFilter(): AutoFilter + { + return $this->autoFilter; + } + + /** + * Set AutoFilter. + */ + public function setAutoFilter(AutoFilter $autoFilter): self + { + $this->autoFilter = $autoFilter; + + return $this; + } + /** * Implement PHP __clone to create a deep clone, not just a shallow copy. */ diff --git a/src/PhpSpreadsheet/Writer/Xlsx/AutoFilter.php b/src/PhpSpreadsheet/Writer/Xlsx/AutoFilter.php new file mode 100644 index 00000000..87e96f08 --- /dev/null +++ b/src/PhpSpreadsheet/Writer/Xlsx/AutoFilter.php @@ -0,0 +1,125 @@ +getAutoFilter()->getRange(); + if (!empty($autoFilterRange)) { + // autoFilter + $objWriter->startElement('autoFilter'); + + // Strip any worksheet reference from the filter coordinates + $range = Coordinate::splitRange($autoFilterRange); + $range = $range[0]; + // Strip any worksheet ref + [$ws, $range[0]] = Worksheet::extractSheetTitle($range[0], true); + $range = implode(':', $range); + + $objWriter->writeAttribute('ref', str_replace('$', '', $range)); + + $columns = $worksheet->getAutoFilter()->getColumns(); + if (count($columns) > 0) { + foreach ($columns as $columnID => $column) { + $colId = $worksheet->getAutoFilter()->getColumnOffset($columnID); + self::writeAutoFilterColumn($objWriter, $column, $colId); + } + } + $objWriter->endElement(); + } + } + + /** + * Write AutoFilter's filterColumn. + */ + public static function writeAutoFilterColumn(XMLWriter $objWriter, Column $column, int $colId): void + { + $rules = $column->getRules(); + if (count($rules) > 0) { + $objWriter->startElement('filterColumn'); + $objWriter->writeAttribute('colId', "$colId"); + + $objWriter->startElement($column->getFilterType()); + if ($column->getJoin() == Column::AUTOFILTER_COLUMN_JOIN_AND) { + $objWriter->writeAttribute('and', '1'); + } + + foreach ($rules as $rule) { + self::writeAutoFilterColumnRule($column, $rule, $objWriter); + } + + $objWriter->endElement(); + + $objWriter->endElement(); + } + } + + /** + * Write AutoFilter's filterColumn Rule. + */ + private static function writeAutoFilterColumnRule(Column $column, Rule $rule, XMLWriter $objWriter): void + { + if ( + ($column->getFilterType() === Column::AUTOFILTER_FILTERTYPE_FILTER) && + ($rule->getOperator() === Rule::AUTOFILTER_COLUMN_RULE_EQUAL) && + ($rule->getValue() === '') + ) { + // Filter rule for Blanks + $objWriter->writeAttribute('blank', '1'); + } elseif ($rule->getRuleType() === Rule::AUTOFILTER_RULETYPE_DYNAMICFILTER) { + // Dynamic Filter Rule + $objWriter->writeAttribute('type', $rule->getGrouping()); + $val = $column->getAttribute('val'); + if ($val !== null) { + $objWriter->writeAttribute('val', "$val"); + } + $maxVal = $column->getAttribute('maxVal'); + if ($maxVal !== null) { + $objWriter->writeAttribute('maxVal', "$maxVal"); + } + } elseif ($rule->getRuleType() === Rule::AUTOFILTER_RULETYPE_TOPTENFILTER) { + // Top 10 Filter Rule + $ruleValue = $rule->getValue(); + if (!is_array($ruleValue)) { + $objWriter->writeAttribute('val', "$ruleValue"); + } + $objWriter->writeAttribute('percent', (($rule->getOperator() === Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_PERCENT) ? '1' : '0')); + $objWriter->writeAttribute('top', (($rule->getGrouping() === Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_TOP) ? '1' : '0')); + } else { + // Filter, DateGroupItem or CustomFilter + $objWriter->startElement($rule->getRuleType()); + + if ($rule->getOperator() !== Rule::AUTOFILTER_COLUMN_RULE_EQUAL) { + $objWriter->writeAttribute('operator', $rule->getOperator()); + } + if ($rule->getRuleType() === Rule::AUTOFILTER_RULETYPE_DATEGROUP) { + // Date Group filters + $ruleValue = $rule->getValue(); + if (is_array($ruleValue)) { + foreach ($ruleValue as $key => $value) { + $objWriter->writeAttribute($key, "$value"); + } + } + $objWriter->writeAttribute('dateTimeGrouping', $rule->getGrouping()); + } else { + $ruleValue = $rule->getValue(); + if (!is_array($ruleValue)) { + $objWriter->writeAttribute('val', "$ruleValue"); + } + } + + $objWriter->endElement(); + } + } +} diff --git a/src/PhpSpreadsheet/Writer/Xlsx/Table.php b/src/PhpSpreadsheet/Writer/Xlsx/Table.php index 67dbd19b..a974c6cb 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx/Table.php +++ b/src/PhpSpreadsheet/Writer/Xlsx/Table.php @@ -57,6 +57,9 @@ class Table extends WriterPart $objWriter->writeAttribute('colId', (string) $offset); $objWriter->writeAttribute('hiddenButton', '1'); $objWriter->endElement(); + } else { + $column = $table->getAutoFilter()->getColumnByOffset($offset); + AutoFilter::writeAutoFilterColumn($objWriter, $column, $offset); } } $objWriter->endElement(); diff --git a/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php b/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php index 1aa4f1ca..75b44706 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php +++ b/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php @@ -3,7 +3,6 @@ namespace PhpOffice\PhpSpreadsheet\Writer\Xlsx; use PhpOffice\PhpSpreadsheet\Calculation\Information\ErrorValue; -use PhpOffice\PhpSpreadsheet\Calculation\Information\Value; use PhpOffice\PhpSpreadsheet\Cell\Cell; use PhpOffice\PhpSpreadsheet\Cell\Coordinate; use PhpOffice\PhpSpreadsheet\RichText\RichText; @@ -13,8 +12,6 @@ use PhpOffice\PhpSpreadsheet\Shared\XMLWriter; use PhpOffice\PhpSpreadsheet\Style\Conditional; use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalDataBar; use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalFormattingRuleExtension; -use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column; -use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule; use PhpOffice\PhpSpreadsheet\Worksheet\SheetView; use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet as PhpspreadsheetWorksheet; @@ -154,6 +151,14 @@ class Worksheet extends WriterPart $worksheet->getAutoFilter()->showHideRows(); } } + $tables = $worksheet->getTableCollection(); + if (count($tables)) { + foreach ($tables as $table) { + if (!$table->getAutoFilter()->getEvaluated()) { + $table->getAutoFilter()->showHideRows(); + } + } + } // tabColor if ($worksheet->isTabColorSet()) { @@ -901,95 +906,7 @@ class Worksheet extends WriterPart */ private function writeAutoFilter(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void { - $autoFilterRange = $worksheet->getAutoFilter()->getRange(); - if (!empty($autoFilterRange)) { - // autoFilter - $objWriter->startElement('autoFilter'); - - // Strip any worksheet reference from the filter coordinates - $range = Coordinate::splitRange($autoFilterRange); - $range = $range[0]; - // Strip any worksheet ref - [$ws, $range[0]] = PhpspreadsheetWorksheet::extractSheetTitle($range[0], true); - $range = implode(':', $range); - - $objWriter->writeAttribute('ref', str_replace('$', '', $range)); - - $columns = $worksheet->getAutoFilter()->getColumns(); - if (count($columns) > 0) { - foreach ($columns as $columnID => $column) { - $rules = $column->getRules(); - if (count($rules) > 0) { - $objWriter->startElement('filterColumn'); - $objWriter->writeAttribute('colId', (string) $worksheet->getAutoFilter()->getColumnOffset($columnID)); - - $objWriter->startElement($column->getFilterType()); - if ($column->getJoin() == Column::AUTOFILTER_COLUMN_JOIN_AND) { - $objWriter->writeAttribute('and', '1'); - } - - foreach ($rules as $rule) { - if ( - ($column->getFilterType() === Column::AUTOFILTER_FILTERTYPE_FILTER) && - ($rule->getOperator() === Rule::AUTOFILTER_COLUMN_RULE_EQUAL) && - ($rule->getValue() === '') - ) { - // Filter rule for Blanks - $objWriter->writeAttribute('blank', '1'); - } elseif ($rule->getRuleType() === Rule::AUTOFILTER_RULETYPE_DYNAMICFILTER) { - // Dynamic Filter Rule - $objWriter->writeAttribute('type', $rule->getGrouping()); - $val = $column->getAttribute('val'); - if ($val !== null) { - $objWriter->writeAttribute('val', "$val"); - } - $maxVal = $column->getAttribute('maxVal'); - if ($maxVal !== null) { - $objWriter->writeAttribute('maxVal', "$maxVal"); - } - } elseif ($rule->getRuleType() === Rule::AUTOFILTER_RULETYPE_TOPTENFILTER) { - // Top 10 Filter Rule - $ruleValue = $rule->getValue(); - if (!is_array($ruleValue)) { - $objWriter->writeAttribute('val', "$ruleValue"); - } - $objWriter->writeAttribute('percent', (($rule->getOperator() === Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_PERCENT) ? '1' : '0')); - $objWriter->writeAttribute('top', (($rule->getGrouping() === Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_TOP) ? '1' : '0')); - } else { - // Filter, DateGroupItem or CustomFilter - $objWriter->startElement($rule->getRuleType()); - - if ($rule->getOperator() !== Rule::AUTOFILTER_COLUMN_RULE_EQUAL) { - $objWriter->writeAttribute('operator', $rule->getOperator()); - } - if ($rule->getRuleType() === Rule::AUTOFILTER_RULETYPE_DATEGROUP) { - // Date Group filters - $ruleValue = $rule->getValue(); - if (is_array($ruleValue)) { - foreach ($ruleValue as $key => $value) { - $objWriter->writeAttribute($key, "$value"); - } - } - $objWriter->writeAttribute('dateTimeGrouping', $rule->getGrouping()); - } else { - $ruleValue = $rule->getValue(); - if (!is_array($ruleValue)) { - $objWriter->writeAttribute('val', "$ruleValue"); - } - } - - $objWriter->endElement(); - } - } - - $objWriter->endElement(); - - $objWriter->endElement(); - } - } - } - $objWriter->endElement(); - } + AutoFilter::writeAutoFilter($objWriter, $worksheet); } /** diff --git a/tests/PhpSpreadsheetTests/Features/AutoFilter/Xlsx/BasicLoadTest.php b/tests/PhpSpreadsheetTests/Features/AutoFilter/Xlsx/BasicLoadTest.php index c36e6741..63c3c6fd 100644 --- a/tests/PhpSpreadsheetTests/Features/AutoFilter/Xlsx/BasicLoadTest.php +++ b/tests/PhpSpreadsheetTests/Features/AutoFilter/Xlsx/BasicLoadTest.php @@ -4,6 +4,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Features\AutoFilter\Xlsx; use PhpOffice\PhpSpreadsheet\Reader\Xlsx; use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule; +use PhpOffice\PhpSpreadsheet\Worksheet\Table; use PHPUnit\Framework\TestCase; class BasicLoadTest extends TestCase @@ -47,28 +48,34 @@ class BasicLoadTest extends TestCase $spreadsheet = $reader->load($filename); $worksheet = $spreadsheet->getActiveSheet(); - self::assertSame('A1:D57', $worksheet->getAutoFilter()->getRange()); - self::assertSame(2, $worksheet->getAutoFilter()->getColumn('C')->ruleCount()); + $tables = $worksheet->getTableCollection(); + self::assertCount(1, $tables); + + $table = $tables->offsetGet(0); + self::assertInstanceOf(Table::class, $table); + + self::assertSame('A1:D57', $table->getAutoFilter()->getRange()); + self::assertSame(2, $table->getAutoFilter()->getColumn('C')->ruleCount()); self::assertSame( Rule::AUTOFILTER_COLUMN_RULE_EQUAL, - $worksheet->getAutoFilter()->getColumn('C')->getRules()[0]->getOperator() + $table->getAutoFilter()->getColumn('C')->getRules()[0]->getOperator() ); - self::assertSame('UK', $worksheet->getAutoFilter()->getColumn('C')->getRules()[0]->getValue()); + self::assertSame('UK', $table->getAutoFilter()->getColumn('C')->getRules()[0]->getValue()); self::assertSame( Rule::AUTOFILTER_COLUMN_RULE_EQUAL, - $worksheet->getAutoFilter()->getColumn('C')->getRules()[1]->getOperator() + $table->getAutoFilter()->getColumn('C')->getRules()[1]->getOperator() ); - self::assertSame('United States', $worksheet->getAutoFilter()->getColumn('C')->getRules()[1]->getValue()); - self::assertSame(2, $worksheet->getAutoFilter()->getColumn('D')->ruleCount()); + self::assertSame('United States', $table->getAutoFilter()->getColumn('C')->getRules()[1]->getValue()); + self::assertSame(2, $table->getAutoFilter()->getColumn('D')->ruleCount()); self::assertSame( Rule::AUTOFILTER_COLUMN_RULE_GREATERTHAN, - $worksheet->getAutoFilter()->getColumn('D')->getRules()[0]->getOperator() + $table->getAutoFilter()->getColumn('D')->getRules()[0]->getOperator() ); - self::assertSame('650', $worksheet->getAutoFilter()->getColumn('D')->getRules()[0]->getValue()); + self::assertSame('650', $table->getAutoFilter()->getColumn('D')->getRules()[0]->getValue()); self::assertSame( Rule::AUTOFILTER_COLUMN_RULE_LESSTHAN, - $worksheet->getAutoFilter()->getColumn('D')->getRules()[1]->getOperator() + $table->getAutoFilter()->getColumn('D')->getRules()[1]->getOperator() ); - self::assertSame('800', $worksheet->getAutoFilter()->getColumn('D')->getRules()[1]->getValue()); + self::assertSame('800', $table->getAutoFilter()->getColumn('D')->getRules()[1]->getValue()); } } diff --git a/tests/PhpSpreadsheetTests/Reader/Xlsx/TableTest.php b/tests/PhpSpreadsheetTests/Reader/Xlsx/TableTest.php new file mode 100644 index 00000000..73e8d111 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Reader/Xlsx/TableTest.php @@ -0,0 +1,41 @@ +load($filename); + + $worksheet = $spreadsheet->getActiveSheet(); + + $tables = $worksheet->getTableCollection(); + self::assertCount(1, $tables); + + $table = $tables->offsetGet(0); + self::assertInstanceOf(Table::class, $table); + self::assertEquals('SalesData', $table->getName()); + self::assertEquals('A1:G16', $table->getRange()); + self::assertTrue($table->getShowHeaderRow(), 'ShowHeaderRow'); + self::assertTrue($table->getShowTotalsRow(), 'ShowTotalsRow'); + + self::assertEquals('Total', $table->getColumn('B')->getTotalsRowLabel()); + self::assertEquals('sum', $table->getColumn('G')->getTotalsRowFunction()); + self::assertEquals('SUM(SalesData[[#This Row],[Q1]:[Q4]])', $table->getColumn('G')->getColumnFormula()); + + $tableStyle = $table->getStyle(); + self::assertEquals(TableStyle::TABLE_STYLE_MEDIUM4, $tableStyle->getTheme()); + self::assertTrue($tableStyle->getShowRowStripes(), 'ShowRowStripes'); + self::assertFalse($tableStyle->getShowColumnStripes(), 'ShowColumnStripes'); + self::assertFalse($tableStyle->getShowFirstColumn(), 'ShowFirstColumn'); + self::assertTrue($tableStyle->getShowLastColumn(), 'ShowLastColumn'); + } +} diff --git a/tests/PhpSpreadsheetTests/Worksheet/Table/TableTest.php b/tests/PhpSpreadsheetTests/Worksheet/Table/TableTest.php index c7cbee25..028816a7 100644 --- a/tests/PhpSpreadsheetTests/Worksheet/Table/TableTest.php +++ b/tests/PhpSpreadsheetTests/Worksheet/Table/TableTest.php @@ -5,6 +5,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Worksheet\Table; use PhpOffice\PhpSpreadsheet\Cell\CellAddress; use PhpOffice\PhpSpreadsheet\Cell\CellRange; use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException; +use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter; use PhpOffice\PhpSpreadsheet\Worksheet\Table; use PhpOffice\PhpSpreadsheet\Worksheet\Table\Column; use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; @@ -555,4 +556,25 @@ class TableTest extends SetupTeardown self::assertArrayHasKey('L', $columns); self::assertArrayHasKey('M', $columns); } + + public function testAutoFilterRule(): void + { + $table = new Table(self::INITIAL_RANGE); + $columnFilter = $table->getAutoFilter()->getColumn('H'); + $columnFilter->setFilterType(AutoFilter\Column::AUTOFILTER_FILTERTYPE_FILTER); + $columnFilter->createRule() + ->setRule( + AutoFilter\Column\Rule::AUTOFILTER_COLUMN_RULE_EQUAL, + 3 + ); + $autoFilterRuleObject = new AutoFilter\Column\Rule($columnFilter); + self::assertEquals(AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_FILTER, $autoFilterRuleObject->getRuleType()); + $ruleParent = $autoFilterRuleObject->getParent(); + if ($ruleParent === null) { + self::fail('Unexpected null parent'); + } else { + self::assertEquals('H', $ruleParent->getColumnIndex()); + self::assertSame($columnFilter, $ruleParent); + } + } } diff --git a/tests/data/Reader/XLSX/tableTest.xlsx b/tests/data/Reader/XLSX/tableTest.xlsx new file mode 100644 index 00000000..c707c9e7 Binary files /dev/null and b/tests/data/Reader/XLSX/tableTest.xlsx differ