mirror of
https://github.com/PHPOffice/PhpSpreadsheet.git
synced 2026-08-30 12:07:56 +00:00
Don't Interfere with SelectedCells And Other Changes
Xls Reader processing Conditionals interferes with the previously established SelectedCells. Make sure that value is restored. StopIfTrue should always be set for Xls spreadsheet. Set NoFormatSet to true unless any of Font, Fill, or Borders is specified in Conditional Style. In my notes for PR #3372, I mentioned that I could not include some Xls tests because of errors in the software at that time. This PR fixes those errors, so I am adding the missing test, and making the equivalent Xlsx test more comprehensive.
This commit is contained in:
@@ -703,6 +703,7 @@ class Xls extends BaseReader
|
||||
// Parse the individual sheets
|
||||
$this->activeSheetSet = false;
|
||||
foreach ($this->sheets as $sheet) {
|
||||
$selectedCells = '';
|
||||
if ($sheet['sheetType'] != 0x00) {
|
||||
// 0x00: Worksheet, 0x02: Chart, 0x06: Visual Basic module
|
||||
continue;
|
||||
@@ -910,7 +911,7 @@ class Xls extends BaseReader
|
||||
|
||||
break;
|
||||
case self::XLS_TYPE_SELECTION:
|
||||
$this->readSelection();
|
||||
$selectedCells = $this->readSelection();
|
||||
|
||||
break;
|
||||
case self::XLS_TYPE_MERGEDCELLS:
|
||||
@@ -1112,6 +1113,9 @@ class Xls extends BaseReader
|
||||
$this->phpSheet->getComment($cellAddress)->setAuthor($noteDetails['author'])->setText($this->parseRichText($noteDetails['objTextData']['text']));
|
||||
}
|
||||
}
|
||||
if ($selectedCells !== '') {
|
||||
$this->phpSheet->setSelectedCells($selectedCells);
|
||||
}
|
||||
}
|
||||
if ($this->activeSheetSet === false) {
|
||||
$this->spreadsheet->setActiveSheetIndex(0);
|
||||
@@ -4376,10 +4380,11 @@ class Xls extends BaseReader
|
||||
/**
|
||||
* Read SELECTION record. There is one such record for each pane in the sheet.
|
||||
*/
|
||||
private function readSelection(): void
|
||||
private function readSelection(): string
|
||||
{
|
||||
$length = self::getUInt2d($this->data, $this->pos + 2);
|
||||
$recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
|
||||
$selectedCells = '';
|
||||
|
||||
// move stream pointer to next record
|
||||
$this->pos += 4 + $length;
|
||||
@@ -4421,6 +4426,8 @@ class Xls extends BaseReader
|
||||
|
||||
$this->phpSheet->setSelectedCells($selectedCells);
|
||||
}
|
||||
|
||||
return $selectedCells;
|
||||
}
|
||||
|
||||
private function includeCellRangeFiltered(string $cellRangeAddress): bool
|
||||
@@ -7410,6 +7417,7 @@ class Xls extends BaseReader
|
||||
$options = self::getInt4d($recordData, 6);
|
||||
|
||||
$style = new Style(false, true); // non-supervisor, conditional
|
||||
$noFormatSet = true;
|
||||
//$this->getCFStyleOptions($options, $style);
|
||||
|
||||
$hasFontRecord = (bool) ((0x04000000 & $options) >> 26);
|
||||
@@ -7429,6 +7437,7 @@ class Xls extends BaseReader
|
||||
$fontStyle = substr($recordData, $offset, 118);
|
||||
$this->getCFFontStyle($fontStyle, $style);
|
||||
$offset += 118;
|
||||
$noFormatSet = false;
|
||||
}
|
||||
|
||||
if ($hasAlignmentRecord === true) {
|
||||
@@ -7441,12 +7450,14 @@ class Xls extends BaseReader
|
||||
$borderStyle = substr($recordData, $offset, 8);
|
||||
$this->getCFBorderStyle($borderStyle, $style, $hasBorderLeft, $hasBorderRight, $hasBorderTop, $hasBorderBottom);
|
||||
$offset += 8;
|
||||
$noFormatSet = false;
|
||||
}
|
||||
|
||||
if ($hasFillRecord === true) {
|
||||
$fillStyle = substr($recordData, $offset, 4);
|
||||
$this->getCFFillStyle($fillStyle, $style);
|
||||
$offset += 4;
|
||||
$noFormatSet = false;
|
||||
}
|
||||
|
||||
if ($hasProtectionRecord === true) {
|
||||
@@ -7474,7 +7485,7 @@ class Xls extends BaseReader
|
||||
$offset += $size2;
|
||||
}
|
||||
|
||||
$this->setCFRules($cellRangeAddresses, $type, $operator, $formula1, $formula2, $style);
|
||||
$this->setCFRules($cellRangeAddresses, $type, $operator, $formula1, $formula2, $style, $noFormatSet);
|
||||
}
|
||||
|
||||
/*private function getCFStyleOptions(int $options, Style $style): void
|
||||
@@ -7604,12 +7615,14 @@ class Xls extends BaseReader
|
||||
}
|
||||
}
|
||||
|
||||
private function setCFRules(array $cellRanges, string $type, string $operator, null|float|int|string $formula1, null|float|int|string $formula2, Style $style): void
|
||||
private function setCFRules(array $cellRanges, string $type, string $operator, null|float|int|string $formula1, null|float|int|string $formula2, Style $style, bool $noFormatSet): void
|
||||
{
|
||||
foreach ($cellRanges as $cellRange) {
|
||||
$conditional = new Conditional();
|
||||
$conditional->setNoFormatSet($noFormatSet);
|
||||
$conditional->setConditionType($type);
|
||||
$conditional->setOperatorType($operator);
|
||||
$conditional->setStopIfTrue(true);
|
||||
if ($formula1 !== null) {
|
||||
$conditional->addCondition($formula1);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Reader\Xls;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Reader\Xls as XlsReader;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class Issue3202Test extends TestCase
|
||||
{
|
||||
public function testSelectedCellWithConditionals(): void
|
||||
{
|
||||
// Unknown index notice when loading
|
||||
$filename = 'tests/data/Reader/XLS/issue.3202.xls';
|
||||
$reader = new XlsReader();
|
||||
$spreadsheet = $reader->load($filename);
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
self::assertSame('A2', $sheet->getSelectedCells());
|
||||
|
||||
$collection = $sheet->getConditionalStylesCollection();
|
||||
self::assertCount(1, $collection);
|
||||
$conditionalArray = $collection['A1:A5'];
|
||||
self::assertCount(3, $conditionalArray);
|
||||
|
||||
$conditions = $conditionalArray[0]->getConditions();
|
||||
self::assertCount(1, $conditions);
|
||||
self::assertSame('$A1=3', $conditions[0]);
|
||||
self::assertTrue($conditionalArray[0]->getNoFormatSet());
|
||||
self::assertTrue($conditionalArray[0]->getStopIfTrue());
|
||||
|
||||
$conditions = $conditionalArray[1]->getConditions();
|
||||
self::assertCount(1, $conditions);
|
||||
self::assertSame('$A1>5', $conditions[0]);
|
||||
self::assertFalse($conditionalArray[1]->getNoFormatSet());
|
||||
self::assertTrue($conditionalArray[1]->getStopIfTrue());
|
||||
|
||||
$conditions = $conditionalArray[2]->getConditions();
|
||||
self::assertCount(1, $conditions);
|
||||
self::assertSame('$A1>1', $conditions[0]);
|
||||
self::assertFalse($conditionalArray[2]->getNoFormatSet());
|
||||
self::assertTrue($conditionalArray[2]->getStopIfTrue());
|
||||
|
||||
$spreadsheet->disconnectWorksheets();
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,31 @@ class ConditionalNoFormatSetTest extends TestCase
|
||||
|
||||
$reader = new XlsxReader();
|
||||
$spreadsheet = $reader->load($testfile);
|
||||
$sheet = $spreadsheet->getactiveSheet();
|
||||
|
||||
$collection = $sheet->getConditionalStylesCollection();
|
||||
self::assertCount(1, $collection);
|
||||
$conditionalArray = $collection['A1:A5'];
|
||||
self::assertCount(3, $conditionalArray);
|
||||
|
||||
$conditions = $conditionalArray[0]->getConditions();
|
||||
self::assertCount(1, $conditions);
|
||||
self::assertSame('$A1=3', $conditions[0]);
|
||||
self::assertTrue($conditionalArray[0]->getNoFormatSet());
|
||||
self::assertTrue($conditionalArray[0]->getStopIfTrue());
|
||||
|
||||
$conditions = $conditionalArray[1]->getConditions();
|
||||
self::assertCount(1, $conditions);
|
||||
self::assertSame('$A1>5', $conditions[0]);
|
||||
self::assertFalse($conditionalArray[1]->getNoFormatSet());
|
||||
self::assertTrue($conditionalArray[1]->getStopIfTrue());
|
||||
|
||||
$conditions = $conditionalArray[2]->getConditions();
|
||||
self::assertCount(1, $conditions);
|
||||
self::assertSame('$A1>1', $conditions[0]);
|
||||
self::assertFalse($conditionalArray[2]->getNoFormatSet());
|
||||
self::assertFalse($conditionalArray[2]->getStopIfTrue());
|
||||
|
||||
$outfile = File::temporaryFilename();
|
||||
$writer = new XlsxWriter($spreadsheet);
|
||||
$writer->save($outfile);
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user