setName($name); self::assertInstanceOf(Table::class, $result); self::assertEquals($expected, $table->getName()); } public function validTableNamesProvider(): array { return [ ['', ''], ['Table_1', 'Table_1'], ['_table_2', '_table_2'], ['\table_3', '\table_3'], [" Table_4 \n", 'Table_4'], ['table.5', 'table.5'], ['தமிழ்', 'தமிழ்'], // UTF-8 letters with combined character ]; } /** * @dataProvider invalidTableNamesProvider */ public function testInvalidTableNames(string $name): void { $table = new Table(self::INITIAL_RANGE); $this->expectException(PhpSpreadsheetException::class); $table->setName($name); } public function invalidTableNamesProvider(): array { return [ ['C'], ['c'], ['R'], ['r'], ['Z100'], ['Z$100'], ['R1C1'], ['R1C'], ['R11C11'], ['123'], ['=Table'], ['ிக'], // starting with UTF-8 combined character [bin2hex(random_bytes(255))], // random string with length greater than 255 ]; } public function testUniqueTableName(): void { $this->expectException(PhpSpreadsheetException::class); $sheet = $this->getSheet(); $table1 = new Table(); $table1->setName('Table_1'); $sheet->addTable($table1); $table2 = new Table(); $table2->setName('table_1'); // case insensitive $sheet->addTable($table2); } public function testVariousSets(): void { $table = new Table(self::INITIAL_RANGE); $result = $table->setShowHeaderRow(false); self::assertInstanceOf(Table::class, $result); self::assertFalse($table->getShowHeaderRow()); $result = $table->setShowTotalsRow(true); self::assertInstanceOf(Table::class, $result); self::assertTrue($table->getShowTotalsRow()); } public function testGetWorksheet(): void { $sheet = $this->getSheet(); $table = new Table(self::INITIAL_RANGE); $sheet->addTable($table); $result = $table->getWorksheet(); self::assertSame($sheet, $result); } public function testSetWorksheet(): void { $table = new Table(self::INITIAL_RANGE); $spreadsheet = $this->getSpreadsheet(); $sheet2 = $spreadsheet->createSheet(); // Setters return the instance to implement the fluent interface $result = $table->setWorksheet($sheet2); self::assertInstanceOf(Table::class, $result); } public function testGetRange(): void { $expectedResult = self::INITIAL_RANGE; $table = new Table(self::INITIAL_RANGE); // Result should be the active table range $result = $table->getRange(); self::assertEquals($expectedResult, $result); } /** * @dataProvider validTableRangeProvider * * @param AddressRange|array|string $fullRange * @param string $fullRange */ public function testSetRangeValidRange($fullRange, string $actualRange): void { $table = new Table(self::INITIAL_RANGE); $result = $table->setRange($fullRange); self::assertInstanceOf(Table::class, $result); self::assertEquals($actualRange, $table->getRange()); } public function validTableRangeProvider(): array { $sheet = $this->getSheet(); $title = $sheet->getTitle(); return [ ["$title!G1:J512", 'G1:J512'], ['K1:N20', 'K1:N20'], [[3, 5, 6, 8], 'C5:F8'], [new CellRange(new CellAddress('C5', $sheet), new CellAddress('F8', $sheet)), 'C5:F8'], ]; } public function testClearRange(): void { $expectedResult = ''; $table = new Table(self::INITIAL_RANGE); // Setters return the instance to implement the fluent interface $result = $table->setRange(''); self::assertInstanceOf(Table::class, $result); // Result should be a clear range $result = $table->getRange(); self::assertEquals($expectedResult, $result); } /** * @dataProvider invalidTableRangeProvider */ public function testSetRangeInvalidRange(string $range): void { $this->expectException(PhpSpreadsheetException::class); new Table($range); } public function invalidTableRangeProvider(): array { return [ ['A1'], ['A1:A1'], ['B1:A4'], ['A1:D1'], ['D1:A1'], ]; } public function testGetColumnsEmpty(): void { // There should be no columns yet defined $table = new Table(self::INITIAL_RANGE); $result = $table->getColumns(); self::assertIsArray($result); self::assertCount(0, $result); } public function testGetColumnOffset(): void { $columnIndexes = [ 'H' => 0, 'K' => 3, 'M' => 5, ]; $table = new Table(self::INITIAL_RANGE); // If we request a specific column by its column ID, we should get an // integer returned representing the column offset within the range foreach ($columnIndexes as $columnIndex => $columnOffset) { $result = $table->getColumnOffset($columnIndex); self::assertEquals($columnOffset, $result); } } public function testRemoveColumns(): void { $sheet = $this->getSheet(); $sheet->fromArray(range('H', 'O'), null, 'H2'); $table = new Table(self::INITIAL_RANGE); $table->getColumn('L')->setShowFilterButton(false); $sheet->addTable($table); $sheet->removeColumn('K', 2); $result = $table->getRange(); self::assertEquals('H2:M256', $result); // Check that the prop that was set for column L is no longer set self::assertTrue($table->getColumn('L')->getShowFilterButton()); } public function testRemoveRows(): void { $sheet = $this->getSheet(); $sheet->fromArray(range('H', 'O'), null, 'H2'); $table = new Table(self::INITIAL_RANGE); $sheet->addTable($table); $sheet->removeRow(42, 128); $result = $table->getRange(); self::assertEquals('H2:O128', $result); } public function testInsertColumns(): void { $sheet = $this->getSheet(); $sheet->fromArray(range('H', 'O'), null, 'H2'); $table = new Table(self::INITIAL_RANGE); $table->getColumn('N')->setShowFilterButton(false); $sheet->addTable($table); $sheet->insertNewColumnBefore('N', 3); $result = $table->getRange(); self::assertEquals('H2:R256', $result); // Check that column N no longer has a prop self::assertTrue($table->getColumn('N')->getShowFilterButton()); // Check that the prop originally set in column N has been moved to column Q self::assertFalse($table->getColumn('Q')->getShowFilterButton()); } public function testInsertRows(): void { $sheet = $this->getSheet(); $sheet->fromArray(range('H', 'O'), null, 'H2'); $table = new Table(self::INITIAL_RANGE); $sheet->addTable($table); $sheet->insertNewRowBefore(3, 4); $result = $table->getRange(); self::assertEquals('H2:O260', $result); } public function testGetInvalidColumnOffset(): void { $this->expectException(PhpSpreadsheetException::class); $invalidColumn = 'G'; $sheet = $this->getSheet(); $table = new Table(); $table->setWorksheet($sheet); $table->getColumnOffset($invalidColumn); } public function testSetColumnWithString(): void { $expectedResult = 'L'; $table = new Table(self::INITIAL_RANGE); // Setters return the instance to implement the fluent interface $result = $table->setColumn($expectedResult); self::assertInstanceOf(Table::class, $result); $result = $table->getColumns(); // Result should be an array of \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet\Table\Column // objects for each column we set indexed by the column ID self::assertIsArray($result); self::assertCount(1, $result); self::assertArrayHasKey($expectedResult, $result); self::assertInstanceOf(Column::class, $result[$expectedResult]); } public function testSetInvalidColumnWithString(): void { $this->expectException(PhpSpreadsheetException::class); $table = new Table(self::INITIAL_RANGE); $invalidColumn = 'A'; $table->setColumn($invalidColumn); } public function testSetColumnWithColumnObject(): void { $expectedResult = 'M'; $columnObject = new Column($expectedResult); $table = new Table(self::INITIAL_RANGE); // Setters return the instance to implement the fluent interface $result = $table->setColumn($columnObject); self::assertInstanceOf(Table::class, $result); $result = $table->getColumns(); // Result should be an array of \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet\Table\Column // objects for each column we set indexed by the column ID self::assertIsArray($result); self::assertCount(1, $result); self::assertArrayHasKey($expectedResult, $result); self::assertInstanceOf(Column::class, $result[$expectedResult]); } public function testSetInvalidColumnWithObject(): void { $this->expectException(PhpSpreadsheetException::class); $invalidColumn = 'E'; $table = new Table(self::INITIAL_RANGE); $table->setColumn($invalidColumn); } public function testSetColumnWithInvalidDataType(): void { $this->expectException(PhpSpreadsheetException::class); $table = new Table(self::INITIAL_RANGE); $invalidColumn = 123.456; // @phpstan-ignore-next-line $table->setColumn($invalidColumn); } public function testGetColumns(): void { $table = new Table(self::INITIAL_RANGE); $columnIndexes = ['L', 'M']; foreach ($columnIndexes as $columnIndex) { $table->setColumn($columnIndex); } $result = $table->getColumns(); // Result should be an array of \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet\Table\Column // objects for each column we set indexed by the column ID self::assertIsArray($result); self::assertCount(count($columnIndexes), $result); foreach ($columnIndexes as $columnIndex) { self::assertArrayHasKey($columnIndex, $result); self::assertInstanceOf(Column::class, $result[$columnIndex]); } $table->setRange(''); self::assertCount(0, $table->getColumns()); self::assertSame('', $table->getRange()); } public function testGetColumn(): void { $table = new Table(self::INITIAL_RANGE); $columnIndexes = ['L', 'M']; foreach ($columnIndexes as $columnIndex) { $table->setColumn($columnIndex); } // If we request a specific column by its column ID, we should // get a \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet\Table\Column object returned foreach ($columnIndexes as $columnIndex) { $result = $table->getColumn($columnIndex); self::assertInstanceOf(Column::class, $result); } } public function testGetColumnByOffset(): void { $table = new Table(self::INITIAL_RANGE); $columnIndexes = [ 0 => 'H', 3 => 'K', 5 => 'M', ]; // If we request a specific column by its offset, we should // get a \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet\Table\Column object returned foreach ($columnIndexes as $columnIndex => $columnID) { $result = $table->getColumnByOffset($columnIndex); self::assertInstanceOf(Column::class, $result); self::assertEquals($result->getColumnIndex(), $columnID); } } public function testGetColumnIfNotSet(): void { $table = new Table(self::INITIAL_RANGE); // If we request a specific column by its column ID, we should // get a \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet\Table\Column object returned $result = $table->getColumn('K'); self::assertInstanceOf(Column::class, $result); } public function testGetColumnWithoutRangeSet(): void { $this->expectException(\PhpOffice\PhpSpreadsheet\Exception::class); $table = new Table(self::INITIAL_RANGE); // Clear the range $table->setRange(''); $table->getColumn('A'); } public function testClearRangeWithExistingColumns(): void { $table = new Table(self::INITIAL_RANGE); $expectedResult = ''; $columnIndexes = ['L', 'M', 'N']; foreach ($columnIndexes as $columnIndex) { $table->setColumn($columnIndex); } // Setters return the instance to implement the fluent interface $result = $table->setRange(''); self::assertInstanceOf(Table::class, $result); // Range should be cleared $result = $table->getRange(); self::assertEquals($expectedResult, $result); // Column array should be cleared $result = $table->getColumns(); self::assertIsArray($result); self::assertCount(0, $result); } public function testSetRangeWithExistingColumns(): void { $table = new Table(self::INITIAL_RANGE); $expectedResult = 'G1:J512'; // These columns should be retained $columnIndexes1 = ['I', 'J']; foreach ($columnIndexes1 as $columnIndex) { $table->setColumn($columnIndex); } // These columns should be discarded $columnIndexes2 = ['K', 'L', 'M']; foreach ($columnIndexes2 as $columnIndex) { $table->setColumn($columnIndex); } // Setters return the instance to implement the fluent interface $result = $table->setRange($expectedResult); self::assertInstanceOf(Table::class, $result); // Range should be correctly set $result = $table->getRange(); self::assertEquals($expectedResult, $result); // Only columns that existed in the original range and that // still fall within the new range should be retained $result = $table->getColumns(); self::assertIsArray($result); self::assertCount(count($columnIndexes1), $result); } public function testClone(): void { $sheet = $this->getSheet(); $table = new Table(self::INITIAL_RANGE); $sheet->addTable($table); $columnIndexes = ['L', 'M']; foreach ($columnIndexes as $columnIndex) { $table->setColumn($columnIndex); } $result = clone $table; self::assertInstanceOf(Table::class, $result); self::assertSame($table->getRange(), $result->getRange()); self::assertNull($result->getWorksheet()); self::assertNotNull($table->getWorksheet()); self::assertInstanceOf(Worksheet::class, $table->getWorksheet()); $tableColumns = $table->getColumns(); $resultColumns = $result->getColumns(); self::assertIsArray($tableColumns); self::assertIsArray($resultColumns); self::assertCount(2, $tableColumns); self::assertCount(2, $resultColumns); self::assertArrayHasKey('L', $tableColumns); self::assertArrayHasKey('L', $resultColumns); self::assertArrayHasKey('M', $tableColumns); self::assertArrayHasKey('M', $resultColumns); self::assertInstanceOf(Column::class, $tableColumns['L']); self::assertInstanceOf(Column::class, $resultColumns['L']); self::assertInstanceOf(Column::class, $tableColumns['M']); self::assertInstanceOf(Column::class, $resultColumns['M']); } public function testNoWorksheet(): void { $table = new Table(); self::assertNull($table->getWorksheet()); } public function testClearColumn(): void { $table = new Table(self::INITIAL_RANGE); $columnIndexes = ['J', 'K', 'L', 'M']; foreach ($columnIndexes as $columnIndex) { $table->setColumn($columnIndex); } $columns = $table->getColumns(); self::assertCount(4, $columns); self::assertArrayHasKey('J', $columns); self::assertArrayHasKey('K', $columns); self::assertArrayHasKey('L', $columns); self::assertArrayHasKey('M', $columns); $table->clearColumn('K'); $columns = $table->getColumns(); self::assertCount(3, $columns); self::assertArrayHasKey('J', $columns); 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); } } }