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

#984 Add support notContainsText for conditional styles in xlsx #2049

Merged
merged 8 commits into from
May 11, 2021
Merged
Show file tree
Hide file tree
Changes from 5 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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org).
- Improved support for Row and Column ranges in formulae [Issue #1755](https://github.com/PHPOffice/PhpSpreadsheet/issues/1755) [PR #2028](https://github.com/PHPOffice/PhpSpreadsheet/pull/2028)
- 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 notContainsText Conditional Style in xlsx [Issue #984](https://github.com/PHPOffice/PhpSpreadsheet/issues/984)

### Changed

Expand Down
11 changes: 1 addition & 10 deletions src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

namespace PhpOffice\PhpSpreadsheet\Reader\Xlsx;

use PhpOffice\PhpSpreadsheet\Style\Color;
use PhpOffice\PhpSpreadsheet\Style\Conditional;
use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalDataBar;
use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalFormattingRuleExtension;
Expand Down Expand Up @@ -39,15 +38,7 @@ private function readConditionalStyles($xmlSheet)
$conditionals = [];
foreach ($xmlSheet->conditionalFormatting as $conditional) {
foreach ($conditional->cfRule as $cfRule) {
if (
((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'])])
) {
if (Conditional::isValidConditionType((string) $cfRule['type']) && isset($this->dxfs[(int) ($cfRule['dxfId'])])) {
$conditionals[(string) $conditional['sqref']][(int) ($cfRule['priority'])] = $cfRule;
} elseif ((string) $cfRule['type'] == Conditional::CONDITION_DATABAR) {
$conditionals[(string) $conditional['sqref']][(int) ($cfRule['priority'])] = $cfRule;
Expand Down
24 changes: 24 additions & 0 deletions src/PhpSpreadsheet/Style/Conditional.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,18 @@ class Conditional implements IComparable
const CONDITION_CONTAINSBLANKS = 'containsBlanks';
const CONDITION_NOTCONTAINSBLANKS = 'notContainsBlanks';
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
const OPERATOR_NONE = '';
Expand Down Expand Up @@ -300,4 +312,16 @@ public function __clone()
}
}
}

/**
* Verify if param is valid condition type
*
* @param string $type
*
* @return bool
*/
public static function isValidConditionType(string $type): bool
{
return in_array($type, self::CONDITION_TYPES);
}
}
12 changes: 9 additions & 3 deletions src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php
Original file line number Diff line number Diff line change
Expand Up @@ -634,15 +634,21 @@ private function writeConditionalFormatting(XMLWriter $objWriter, Phpspreadsheet

self::writeAttributeif(
$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,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use === and !== where possible.

'operator',
$conditional->getOperatorType()
);

self::writeAttributeIf($objWriter, $conditional->getStopIfTrue(), 'stopIfTrue', '1');

if ($conditional->getConditionType() == Conditional::CONDITION_CONTAINSTEXT) {
if (
$conditional->getConditionType() == Conditional::CONDITION_CONTAINSTEXT
|| $conditional->getConditionType() == Conditional::CONDITION_NOTCONTAINSTEXT
) {
oleibman marked this conversation as resolved.
Show resolved Hide resolved
self::writeTextCondElements($objWriter, $conditional, $cellCoordinate);
} else {
self::writeOtherCondElements($objWriter, $conditional, $cellCoordinate);
Expand Down
31 changes: 31 additions & 0 deletions tests/PhpSpreadsheetTests/Reader/Xlsx/ConditionalTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?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');

$this->assertCount(1, $styles);

/** @var $notContainsTextStyle Conditional */
$notContainsTextStyle = $styles[0];
$this->assertEquals('A', $notContainsTextStyle->getText());
$this->assertEquals(Conditional::CONDITION_NOTCONTAINSTEXT, $notContainsTextStyle->getConditionType());
$this->assertEquals(Conditional::OPERATOR_NOTCONTAINS, $notContainsTextStyle->getOperatorType());
}
}
60 changes: 60 additions & 0 deletions tests/PhpSpreadsheetTests/Writer/Xlsx/ConditionalTest.php
Original file line number Diff line number Diff line change
@@ -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;
$this->assertStringContainsString($needle, $data);
}
}
Binary file not shown.