Merge pull request #2049 from xandros15/#984

#984 Add support notContainsText for conditional styles in xlsx
This commit is contained in:
oleibman 2021-05-11 14:56:15 -07:00 committed by GitHub
commit 6fb3d840c2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 121 additions and 13 deletions

View File

@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org).
- Implemented URLENCODE() Web Function - Implemented URLENCODE() Web Function
- Implemented the CHITEST(), CHISQ.DIST() and CHISQ.INV() and equivalent Statistical functions, for both left- and right-tailed distributions. - Implemented the CHITEST(), CHISQ.DIST() and CHISQ.INV() and equivalent Statistical functions, for both left- and right-tailed distributions.
- Support for ActiveSheet and SelectedCells in the ODS Reader and Writer. [PR #1908](https://github.com/PHPOffice/PhpSpreadsheet/pull/1908) - Support for ActiveSheet and SelectedCells in the ODS Reader and Writer. [PR #1908](https://github.com/PHPOffice/PhpSpreadsheet/pull/1908)
- Support for notContainsText Conditional Style in xlsx [Issue #984](https://github.com/PHPOffice/PhpSpreadsheet/issues/984)
### Changed ### Changed

View File

@ -2,7 +2,6 @@
namespace PhpOffice\PhpSpreadsheet\Reader\Xlsx; namespace PhpOffice\PhpSpreadsheet\Reader\Xlsx;
use PhpOffice\PhpSpreadsheet\Style\Color;
use PhpOffice\PhpSpreadsheet\Style\Conditional; use PhpOffice\PhpSpreadsheet\Style\Conditional;
use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalDataBar; use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalDataBar;
use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalFormattingRuleExtension; use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalFormattingRuleExtension;
@ -39,15 +38,7 @@ class ConditionalStyles
$conditionals = []; $conditionals = [];
foreach ($xmlSheet->conditionalFormatting as $conditional) { foreach ($xmlSheet->conditionalFormatting as $conditional) {
foreach ($conditional->cfRule as $cfRule) { foreach ($conditional->cfRule as $cfRule) {
if ( if (Conditional::isValidConditionType((string) $cfRule['type']) && isset($this->dxfs[(int) ($cfRule['dxfId'])])) {
((string) $cfRule['type'] == Conditional::CONDITION_NONE
|| (string) $cfRule['type'] == Conditional::CONDITION_CELLIS
|| (string) $cfRule['type'] == Conditional::CONDITION_CONTAINSTEXT
|| (string) $cfRule['type'] == Conditional::CONDITION_CONTAINSBLANKS
|| (string) $cfRule['type'] == Conditional::CONDITION_NOTCONTAINSBLANKS
|| (string) $cfRule['type'] == Conditional::CONDITION_EXPRESSION)
&& isset($this->dxfs[(int) ($cfRule['dxfId'])])
) {
$conditionals[(string) $conditional['sqref']][(int) ($cfRule['priority'])] = $cfRule; $conditionals[(string) $conditional['sqref']][(int) ($cfRule['priority'])] = $cfRule;
} elseif ((string) $cfRule['type'] == Conditional::CONDITION_DATABAR) { } elseif ((string) $cfRule['type'] == Conditional::CONDITION_DATABAR) {
$conditionals[(string) $conditional['sqref']][(int) ($cfRule['priority'])] = $cfRule; $conditionals[(string) $conditional['sqref']][(int) ($cfRule['priority'])] = $cfRule;

View File

@ -15,6 +15,18 @@ class Conditional implements IComparable
const CONDITION_CONTAINSBLANKS = 'containsBlanks'; const CONDITION_CONTAINSBLANKS = 'containsBlanks';
const CONDITION_NOTCONTAINSBLANKS = 'notContainsBlanks'; const CONDITION_NOTCONTAINSBLANKS = 'notContainsBlanks';
const CONDITION_DATABAR = 'dataBar'; const CONDITION_DATABAR = 'dataBar';
const CONDITION_NOTCONTAINSTEXT = 'notContainsText';
private const CONDITION_TYPES = [
self::CONDITION_CELLIS,
self::CONDITION_CONTAINSBLANKS,
self::CONDITION_CONTAINSTEXT,
self::CONDITION_DATABAR,
self::CONDITION_EXPRESSION,
self::CONDITION_NONE,
self::CONDITION_NOTCONTAINSBLANKS,
self::CONDITION_NOTCONTAINSTEXT,
];
// Operator types // Operator types
const OPERATOR_NONE = ''; const OPERATOR_NONE = '';
@ -300,4 +312,12 @@ class Conditional implements IComparable
} }
} }
} }
/**
* Verify if param is valid condition type.
*/
public static function isValidConditionType(string $type): bool
{
return in_array($type, self::CONDITION_TYPES);
}
} }

View File

@ -634,15 +634,21 @@ class Worksheet extends WriterPart
self::writeAttributeif( self::writeAttributeif(
$objWriter, $objWriter,
($conditional->getConditionType() == Conditional::CONDITION_CELLIS || $conditional->getConditionType() == Conditional::CONDITION_CONTAINSTEXT) (
&& $conditional->getOperatorType() != Conditional::OPERATOR_NONE, $conditional->getConditionType() === Conditional::CONDITION_CELLIS
|| $conditional->getConditionType() === Conditional::CONDITION_CONTAINSTEXT
|| $conditional->getConditionType() === Conditional::CONDITION_NOTCONTAINSTEXT
) && $conditional->getOperatorType() !== Conditional::OPERATOR_NONE,
'operator', 'operator',
$conditional->getOperatorType() $conditional->getOperatorType()
); );
self::writeAttributeIf($objWriter, $conditional->getStopIfTrue(), 'stopIfTrue', '1'); self::writeAttributeIf($objWriter, $conditional->getStopIfTrue(), 'stopIfTrue', '1');
if ($conditional->getConditionType() == Conditional::CONDITION_CONTAINSTEXT) { if (
$conditional->getConditionType() === Conditional::CONDITION_CONTAINSTEXT
|| $conditional->getConditionType() === Conditional::CONDITION_NOTCONTAINSTEXT
) {
self::writeTextCondElements($objWriter, $conditional, $cellCoordinate); self::writeTextCondElements($objWriter, $conditional, $cellCoordinate);
} else { } else {
self::writeOtherCondElements($objWriter, $conditional, $cellCoordinate); self::writeOtherCondElements($objWriter, $conditional, $cellCoordinate);

View File

@ -0,0 +1,30 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Reader\Xlsx;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Style\Conditional;
use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional;
class ConditionalTest extends AbstractFunctional
{
/**
* Test check if conditional style with type 'notContainsText' works on xlsx.
*/
public function testConditionalNotContainsText(): void
{
$filename = 'tests/data/Reader/XLSX/conditionalFormatting3Test.xlsx';
$reader = IOFactory::createReader('Xlsx');
$spreadsheet = $reader->load($filename);
$worksheet = $spreadsheet->getActiveSheet();
$styles = $worksheet->getConditionalStyles('A1:A5');
self::assertCount(1, $styles);
/** @var Conditional $notContainsTextStyle */
$notContainsTextStyle = $styles[0];
self::assertEquals('A', $notContainsTextStyle->getText());
self::assertEquals(Conditional::CONDITION_NOTCONTAINSTEXT, $notContainsTextStyle->getConditionType());
self::assertEquals(Conditional::OPERATOR_NOTCONTAINS, $notContainsTextStyle->getOperatorType());
}
}

View File

@ -0,0 +1,60 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\Settings;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Style\Conditional;
use PhpOffice\PhpSpreadsheet\Style\Fill;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional;
class ConditionalTest extends AbstractFunctional
{
/**
* @var int
*/
private $prevValue;
protected function setUp(): void
{
$this->prevValue = Settings::getLibXmlLoaderOptions();
// Disable validating XML with the DTD
Settings::setLibXmlLoaderOptions($this->prevValue & ~LIBXML_DTDVALID & ~LIBXML_DTDATTR & ~LIBXML_DTDLOAD);
}
protected function tearDown(): void
{
Settings::setLibXmlLoaderOptions($this->prevValue);
}
/**
* Test check if conditional style with type 'notContainsText' works on xlsx.
*/
public function testConditionalNotContainsText(): void
{
$spreadsheet = new Spreadsheet();
$worksheet = $spreadsheet->getActiveSheet();
$condition = new Conditional();
$condition->setConditionType(Conditional::CONDITION_NOTCONTAINSTEXT);
$condition->setOperatorType(Conditional::OPERATOR_NOTCONTAINS);
$condition->setText('C');
$condition->getStyle()->applyFromArray([
'fill' => [
'color' => ['argb' => 'FFFFC000'],
'fillType' => Fill::FILL_SOLID,
],
]);
$worksheet->setConditionalStyles('A1:A5', [$condition]);
$writer = new Xlsx($spreadsheet);
$writerWorksheet = new Xlsx\Worksheet($writer);
$data = $writerWorksheet->writeWorksheet($worksheet, []);
$needle = <<<xml
<conditionalFormatting sqref="A1:A5"><cfRule type="notContainsText" dxfId="" priority="1" operator="notContains" text="C"><formula>ISERROR(SEARCH(&quot;C&quot;,A1:A5))</formula></cfRule></conditionalFormatting>
xml;
self::assertStringContainsString($needle, $data);
}
}

Binary file not shown.