Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Apply Column and Row Styles to Existing Cells #1721

Merged
merged 7 commits into from
Dec 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions docs/topics/accessing-cells.md
Original file line number Diff line number Diff line change
Expand Up @@ -422,8 +422,10 @@ foreach ($worksheet->getRowIterator() as $row) {
$cellIterator = $row->getCellIterator();
$cellIterator->setIterateOnlyExistingCells(FALSE); // This loops through all cells,
// even if a cell value is not set.
// By default, only cells that have a value
// set will be iterated.
// For 'TRUE', we loop through cells
// only when their value is set.
// If this method is not called,
// the default value is 'false'.
foreach ($cellIterator as $cell) {
echo '<td>' .
$cell->getValue() .
Expand Down
30 changes: 16 additions & 14 deletions src/PhpSpreadsheet/Style/Style.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,6 @@ class Style extends Supervisor
*/
protected $numberFormat;

/**
* Conditional styles.
*
* @var Conditional[]
*/
protected $conditionalStyles;

/**
* Protection.
*
Expand Down Expand Up @@ -85,7 +78,6 @@ public function __construct($isSupervisor = false, $isConditional = false)
parent::__construct($isSupervisor);

// Initialise values
$this->conditionalStyles = [];
$this->font = new Font($isSupervisor, $isConditional);
$this->fill = new Fill($isSupervisor, $isConditional);
$this->borders = new Borders($isSupervisor, $isConditional);
Expand Down Expand Up @@ -212,6 +204,8 @@ public function applyFromArray(array $pStyles, $pAdvanced = true)
$rangeEnd = Coordinate::coordinateFromString($rangeB);

// Translate column into index
$rangeStart0 = $rangeStart[0];
$rangeEnd0 = $rangeEnd[0];
$rangeStart[0] = Coordinate::columnIndexFromString($rangeStart[0]);
$rangeEnd[0] = Coordinate::columnIndexFromString($rangeEnd[0]);

Expand Down Expand Up @@ -361,6 +355,13 @@ public function applyFromArray(array $pStyles, $pAdvanced = true)
for ($col = $rangeStart[0]; $col <= $rangeEnd[0]; ++$col) {
$oldXfIndexes[$this->getActiveSheet()->getColumnDimensionByColumn($col)->getXfIndex()] = true;
}
foreach ($this->getActiveSheet()->getColumnIterator($rangeStart0, $rangeEnd0) as $columnIterator) {
$cellIterator = $columnIterator->getCellIterator();
$cellIterator->setIterateOnlyExistingCells(true);
foreach ($cellIterator as $columnCell) {
$columnCell->getStyle()->applyFromArray($pStyles);
}
}

break;
case 'ROW':
Expand All @@ -372,6 +373,13 @@ public function applyFromArray(array $pStyles, $pAdvanced = true)
$oldXfIndexes[$this->getActiveSheet()->getRowDimension($row)->getXfIndex()] = true;
}
}
foreach ($this->getActiveSheet()->getRowIterator((int) $rangeStart[1], (int) $rangeEnd[1]) as $rowIterator) {
$cellIterator = $rowIterator->getCellIterator();
$cellIterator->setIterateOnlyExistingCells(true);
foreach ($cellIterator as $rowCell) {
$rowCell->getStyle()->applyFromArray($pStyles);
}
}

break;
case 'CELL':
Expand Down Expand Up @@ -599,18 +607,12 @@ public function setQuotePrefix($pValue)
*/
public function getHashCode()
{
$hashConditionals = '';
foreach ($this->conditionalStyles as $conditional) {
$hashConditionals .= $conditional->getHashCode();
}

return md5(
$this->fill->getHashCode() .
$this->font->getHashCode() .
$this->borders->getHashCode() .
$this->alignment->getHashCode() .
$this->numberFormat->getHashCode() .
$hashConditionals .
$this->protection->getHashCode() .
($this->quotePrefix ? 't' : 'f') .
__CLASS__
Expand Down
13 changes: 4 additions & 9 deletions src/PhpSpreadsheet/Worksheet/ColumnCellIterator.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,11 @@ public function resetEnd($endRow = null)
*/
public function seek($row = 1)
{
if ($this->onlyExistingCells && !($this->worksheet->cellExistsByColumnAndRow($this->columnIndex, $row))) {
throw new PhpSpreadsheetException('In "IterateOnlyExistingCells" mode and Cell does not exist');
}
if (($row < $this->startRow) || ($row > $this->endRow)) {
throw new PhpSpreadsheetException("Row $row is out of range ({$this->startRow} - {$this->endRow})");
} elseif ($this->onlyExistingCells && !($this->worksheet->cellExistsByColumnAndRow($this->columnIndex, $row))) {
throw new PhpSpreadsheetException('In "IterateOnlyExistingCells" mode and Cell does not exist');
}
$this->currentRow = $row;

Expand All @@ -113,7 +114,7 @@ public function rewind(): void
/**
* Return the current cell in this worksheet column.
*
* @return null|\PhpOffice\PhpSpreadsheet\Cell\Cell
* @return \PhpOffice\PhpSpreadsheet\Cell\Cell
*/
public function current()
{
Expand Down Expand Up @@ -180,18 +181,12 @@ protected function adjustForExistingOnlyRange(): void
) {
++$this->startRow;
}
if ($this->startRow > $this->endRow) {
throw new PhpSpreadsheetException('No cells exist within the specified range');
}
while (
(!$this->worksheet->cellExistsByColumnAndRow($this->columnIndex, $this->endRow)) &&
($this->endRow >= $this->startRow)
) {
--$this->endRow;
}
if ($this->endRow < $this->startRow) {
throw new PhpSpreadsheetException('No cells exist within the specified range');
}
}
}
}
14 changes: 5 additions & 9 deletions src/PhpSpreadsheet/Worksheet/RowCellIterator.php
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,14 @@ public function resetEnd($endColumn = null)
*/
public function seek($column = 'A')
{
$columnx = $column;
$column = Coordinate::columnIndexFromString($column);
if (($column < $this->startColumnIndex) || ($column > $this->endColumnIndex)) {
throw new PhpSpreadsheetException("Column $column is out of range ({$this->startColumnIndex} - {$this->endColumnIndex})");
} elseif ($this->onlyExistingCells && !($this->worksheet->cellExistsByColumnAndRow($column, $this->rowIndex))) {
if ($this->onlyExistingCells && !($this->worksheet->cellExistsByColumnAndRow($column, $this->rowIndex))) {
throw new PhpSpreadsheetException('In "IterateOnlyExistingCells" mode and Cell does not exist');
}
if (($column < $this->startColumnIndex) || ($column > $this->endColumnIndex)) {
throw new PhpSpreadsheetException("Column $columnx is out of range ({$this->startColumnIndex} - {$this->endColumnIndex})");
}
$this->currentColumnIndex = $column;

return $this;
Expand Down Expand Up @@ -181,15 +183,9 @@ protected function adjustForExistingOnlyRange(): void
while ((!$this->worksheet->cellExistsByColumnAndRow($this->startColumnIndex, $this->rowIndex)) && ($this->startColumnIndex <= $this->endColumnIndex)) {
++$this->startColumnIndex;
}
if ($this->startColumnIndex > $this->endColumnIndex) {
throw new PhpSpreadsheetException('No cells exist within the specified range');
}
while ((!$this->worksheet->cellExistsByColumnAndRow($this->endColumnIndex, $this->rowIndex)) && ($this->endColumnIndex >= $this->startColumnIndex)) {
--$this->endColumnIndex;
}
if ($this->endColumnIndex < $this->startColumnIndex) {
throw new PhpSpreadsheetException('No cells exist within the specified range');
}
}
}
}
138 changes: 138 additions & 0 deletions tests/PhpSpreadsheetTests/Style/StyleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Style;

use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Style\Fill;
use PHPUnit\Framework\TestCase;

class StyleTest extends TestCase
Expand All @@ -19,4 +20,141 @@ public function testStyleOddMethods(): void
$outArray = $cell1style->getStyleArray($styleArray);
self::assertEquals($styleArray, $outArray['quotePrefix']);
}

public function testStyleColumn(): void
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$cellCoordinates = 'A:B';
$styleArray = [
'font' => [
'bold' => true,
],
];
$sheet->getStyle($cellCoordinates)->applyFromArray($styleArray);
$sheet->setCellValue('A1', 'xxxa1');
$sheet->setCellValue('A2', 'xxxa2');
$sheet->setCellValue('A3', 'xxxa3');
$sheet->setCellValue('B1', 'xxxa1');
$sheet->setCellValue('B2', 'xxxa2');
$sheet->setCellValue('B3', 'xxxa3');
$sheet->setCellValue('C1', 'xxxc1');
$sheet->setCellValue('C2', 'xxxc2');
$sheet->setCellValue('C3', 'xxxc3');
$styleArray = [
'font' => [
'italic' => true,
],
];
$sheet->getStyle($cellCoordinates)->applyFromArray($styleArray);
self::assertTrue($sheet->getStyle('A1')->getFont()->getBold());
self::assertTrue($sheet->getStyle('B2')->getFont()->getBold());
self::assertFalse($sheet->getStyle('C3')->getFont()->getBold());
self::assertTrue($sheet->getStyle('A1')->getFont()->getItalic());
self::assertTrue($sheet->getStyle('B2')->getFont()->getItalic());
self::assertFalse($sheet->getStyle('C3')->getFont()->getItalic());
}

public function testStyleRow(): void
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$cellCoordinates = '2:3';
$styleArray = [
'font' => [
'bold' => true,
],
];
$sheet->getStyle($cellCoordinates)->applyFromArray($styleArray);
$sheet->setCellValue('A1', 'xxxa1');
$sheet->setCellValue('A2', 'xxxa2');
$sheet->setCellValue('A3', 'xxxa3');
$sheet->setCellValue('B1', 'xxxa1');
$sheet->setCellValue('B2', 'xxxa2');
$sheet->setCellValue('B3', 'xxxa3');
$sheet->setCellValue('C1', 'xxxc1');
$sheet->setCellValue('C2', 'xxxc2');
$sheet->setCellValue('C3', 'xxxc3');
$styleArray = [
'font' => [
'italic' => true,
],
];
$sheet->getStyle($cellCoordinates)->applyFromArray($styleArray);
self::assertFalse($sheet->getStyle('A1')->getFont()->getBold());
self::assertTrue($sheet->getStyle('B2')->getFont()->getBold());
self::assertTrue($sheet->getStyle('C3')->getFont()->getBold());
self::assertFalse($sheet->getStyle('A1')->getFont()->getItalic());
self::assertTrue($sheet->getStyle('B2')->getFont()->getItalic());
self::assertTrue($sheet->getStyle('C3')->getFont()->getItalic());
}

public function testIssue1712A(): void
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$rgb = '4467b8';
$sheet->fromArray(['OK', 'KO']);
$spreadsheet->getActiveSheet()
->getStyle('A1')
->getFill()
->setFillType(Fill::FILL_SOLID)
->getStartColor()
->setRGB($rgb);
$spreadsheet->getActiveSheet()
->getStyle('B')
->getFill()
->setFillType(Fill::FILL_SOLID)
->getStartColor()
->setRGB($rgb);
self::assertEquals($rgb, $sheet->getCell('A1')->getStyle()->getFill()->getStartColor()->getRGB());
self::assertEquals($rgb, $sheet->getCell('B1')->getStyle()->getFill()->getStartColor()->getRGB());
}

public function testIssue1712B(): void
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$rgb = '4467b8';
$spreadsheet->getActiveSheet()
->getStyle('A1')
->getFill()
->setFillType(Fill::FILL_SOLID)
->getStartColor()
->setRGB($rgb);
$spreadsheet->getActiveSheet()
->getStyle('B')
->getFill()
->setFillType(Fill::FILL_SOLID)
->getStartColor()
->setRGB($rgb);
$sheet->fromArray(['OK', 'KO']);
self::assertEquals($rgb, $sheet->getCell('A1')->getStyle()->getFill()->getStartColor()->getRGB());
self::assertEquals($rgb, $sheet->getCell('B1')->getStyle()->getFill()->getStartColor()->getRGB());
}

public function testStyleLoopUpwards(): void
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$cellCoordinates = 'C5:A3';
$styleArray = [
'font' => [
'bold' => true,
],
];
$sheet->getStyle($cellCoordinates)->applyFromArray($styleArray);
$sheet->setCellValue('A1', 'xxxa1');
$sheet->setCellValue('A2', 'xxxa2');
$sheet->setCellValue('A3', 'xxxa3');
$sheet->setCellValue('B1', 'xxxa1');
$sheet->setCellValue('B2', 'xxxa2');
$sheet->setCellValue('B3', 'xxxa3');
$sheet->setCellValue('C1', 'xxxc1');
$sheet->setCellValue('C2', 'xxxc2');
$sheet->setCellValue('C3', 'xxxc3');
self::assertFalse($sheet->getStyle('A1')->getFont()->getBold());
self::assertFalse($sheet->getStyle('B2')->getFont()->getBold());
self::assertTrue($sheet->getStyle('C3')->getFont()->getBold());
}
}
75 changes: 75 additions & 0 deletions tests/PhpSpreadsheetTests/Worksheet/ColumnCellIterator2Test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?php

namespace PhpOffice\PhpSpreadsheetTests\Worksheet;

use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Worksheet\ColumnCellIterator;
use PHPUnit\Framework\TestCase;

class ColumnCellIterator2Test extends TestCase
{
/**
* @dataProvider providerExistingCell
*/
public function testEndRange(?bool $existing, string $expectedResultFirst, string $expectedResultLast): void
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->getCell('B2')->setValue('cellb2');
$sheet->getCell('B6')->setValue('cellb6');

$iterator = new ColumnCellIterator($sheet, 'B', 1, 8);
if (isset($existing)) {
$iterator->setIterateOnlyExistingCells($existing);
}
$lastCoordinate = '';
$firstCoordinate = '';
foreach ($iterator as $cell) {
$lastCoordinate = $cell->getCoordinate();
if (!$firstCoordinate) {
$firstCoordinate = $lastCoordinate;
}
}
self::assertEquals($expectedResultFirst, $firstCoordinate);
self::assertEquals($expectedResultLast, $lastCoordinate);
}

public function providerExistingCell(): array
{
return [
[null, 'B1', 'B8'],
[false, 'B1', 'B8'],
[true, 'B2', 'B6'],
];
}

/**
* @dataProvider providerEmptyColumn
*/
public function testEmptyColumn(?bool $existing, int $expectedResult): void
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->getCell('B2')->setValue('cellb2');
$sheet->getCell('B6')->setValue('cellb6');

$iterator = new ColumnCellIterator($sheet, 'C');
if (isset($existing)) {
$iterator->setIterateOnlyExistingCells($existing);
}
$numCells = 0;
foreach ($iterator as $cell) {
++$numCells;
}
self::assertEquals($expectedResult, $numCells);
}

public function providerEmptyColumn(): array
{
return [
[null, 6],
[false, 6],
[true, 0],
];
}
}
Loading