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

Support DataBar of conditional formatting rule #1754

Merged
merged 1 commit into from Jan 29, 2021
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Expand Up @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org).

### Added

- Nothing.
- Implemented DataBar for conditional formatting in Xlsx, providing read/write and creation of (type, value, direction, fills, border, axis position, color settings) as DataBar options in Excel. [#1754](https://github.com/PHPOffice/PhpSpreadsheet/pull/1754)

### Changed

Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
38 changes: 38 additions & 0 deletions docs/topics/recipes.md
Expand Up @@ -884,6 +884,44 @@ $spreadsheet->getActiveSheet()
);
```

### DataBar of Conditional formatting
The basics are the same as conditional formatting.
Additional DataBar object to conditional formatting.

For example, the following code will result in the conditional formatting shown in the image.
```php
$conditional = new Conditional();
$conditional->setConditionType(Conditional::CONDITION_DATABAR);
$conditional->setDataBar(new ConditionalDataBar());
$conditional->getDataBar()
->setMinimumConditionalFormatValueObject(new ConditionalFormatValueObject('num', '2'))
->setMaximumConditionalFormatValueObject(new ConditionalFormatValueObject('max'))
->setColor('FFFF555A');
$ext = $conditional
->getDataBar()
->setConditionalFormattingRuleExt(new ConditionalFormattingRuleExtension())
->getConditionalFormattingRuleExt();

$ext->setCfRule('dataBar');
$ext->setSqref('A1:A5'); // target CellCoordinates
$ext->setDataBarExt(new ConditionalDataBarExtension());
$ext->getDataBarExt()
->setMinimumConditionalFormatValueObject(new ConditionalFormatValueObject('num', '2'))
->setMaximumConditionalFormatValueObject(new ConditionalFormatValueObject('autoMax'))
->setMinLength(0)
->setMaxLength(100)
->setBorder(true)
->setDirection('rightToLeft')
->setNegativeBarBorderColorSameAsPositive(false)
->setBorderColor('FFFF555A')
->setNegativeFillColor('FFFF0000')
->setNegativeBorderColor('FFFF0000')
->setAxisColor('FF000000');

```

![10-databar-of-conditional-formatting.png](./images/10-databar-of-conditional-formatting.png)

## Add a comment to a cell

To add a comment to a cell, use the following code. The example below
Expand Down
79 changes: 69 additions & 10 deletions src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php
Expand Up @@ -2,7 +2,11 @@

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;
use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalFormatValueObject;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use SimpleXMLElement;

Expand All @@ -25,7 +29,8 @@ public function load(): void
{
$this->setConditionalStyles(
$this->worksheet,
$this->readConditionalStyles($this->worksheetXml)
$this->readConditionalStyles($this->worksheetXml),
$this->worksheetXml->extLst
);
}

Expand All @@ -36,26 +41,28 @@ private function readConditionalStyles($xmlSheet)
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)
|| (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;
} elseif ((string) $cfRule['type'] == Conditional::CONDITION_DATABAR) {
$conditionals[(string) $conditional['sqref']][(int) ($cfRule['priority'])] = $cfRule;
}
}
}

return $conditionals;
}

private function setConditionalStyles(Worksheet $worksheet, array $conditionals): void
private function setConditionalStyles(Worksheet $worksheet, array $conditionals, $xmlExtLst): void
{
foreach ($conditionals as $ref => $cfRules) {
ksort($cfRules);
$conditionalStyles = $this->readStyleRules($cfRules);
$conditionalStyles = $this->readStyleRules($cfRules, $xmlExtLst);

// Extract all cell references in $ref
$cellBlocks = explode(' ', str_replace('$', '', strtoupper($ref)));
Expand All @@ -65,8 +72,9 @@ private function setConditionalStyles(Worksheet $worksheet, array $conditionals)
}
}

private function readStyleRules($cfRules)
private function readStyleRules($cfRules, $extLst)
{
$conditionalFormattingRuleExtensions = ConditionalFormattingRuleExtension::parseExtLstXml($extLst);
$conditionalStyles = [];
foreach ($cfRules as $cfRule) {
$objConditional = new Conditional();
Expand All @@ -88,10 +96,61 @@ private function readStyleRules($cfRules)
} else {
$objConditional->addCondition((string) $cfRule->formula);
}
$objConditional->setStyle(clone $this->dxfs[(int) ($cfRule['dxfId'])]);

if (isset($cfRule->dataBar)) {
$objConditional->setDataBar($this->readDataBarOfConditionalRule($cfRule, $conditionalFormattingRuleExtensions));
} else {
$objConditional->setStyle(clone $this->dxfs[(int) ($cfRule['dxfId'])]);
}

$conditionalStyles[] = $objConditional;
}

return $conditionalStyles;
}

private function readDataBarOfConditionalRule($cfRule, $conditionalFormattingRuleExtensions): ConditionalDataBar
{
$dataBar = new ConditionalDataBar();
//dataBar attribute
if (isset($cfRule->dataBar['showValue'])) {
$dataBar->setShowValue((bool) $cfRule->dataBar['showValue']);
}

//dataBar children
//conditionalFormatValueObjects
$cfvoXml = $cfRule->dataBar->cfvo;
$cfvoIndex = 0;
foreach ((count($cfvoXml) > 1 ? $cfvoXml : [$cfvoXml]) as $cfvo) {
if ($cfvoIndex === 0) {
$dataBar->setMinimumConditionalFormatValueObject(new ConditionalFormatValueObject((string) $cfvo['type'], (string) $cfvo['val']));
}
if ($cfvoIndex === 1) {
$dataBar->setMaximumConditionalFormatValueObject(new ConditionalFormatValueObject((string) $cfvo['type'], (string) $cfvo['val']));
}
++$cfvoIndex;
}

//color
if (isset($cfRule->dataBar->color)) {
$dataBar->setColor((string) $cfRule->dataBar->color['rgb']);
}
//extLst
$this->readDataBarExtLstOfConditionalRule($dataBar, $cfRule, $conditionalFormattingRuleExtensions);

return $dataBar;
}

private function readDataBarExtLstOfConditionalRule(ConditionalDataBar $dataBar, $cfRule, $conditionalFormattingRuleExtensions): void
{
if (isset($cfRule->extLst)) {
$ns = $cfRule->extLst->getNamespaces(true);
foreach ((count($cfRule->extLst) > 0 ? $cfRule->extLst->ext : [$cfRule->extLst->ext]) as $ext) {
$extId = (string) $ext->children($ns['x14'])->id;
if (isset($conditionalFormattingRuleExtensions[$extId]) && (string) $ext['uri'] === '{B025F937-C7B1-47D3-B67F-A62EFF666E3E}') {
$dataBar->setConditionalFormattingRuleExt($conditionalFormattingRuleExtensions[$extId]);
}
}
}
}
}
29 changes: 29 additions & 0 deletions src/PhpSpreadsheet/Style/Conditional.php
Expand Up @@ -3,6 +3,7 @@
namespace PhpOffice\PhpSpreadsheet\Style;

use PhpOffice\PhpSpreadsheet\IComparable;
use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalDataBar;

class Conditional implements IComparable
{
Expand All @@ -13,6 +14,7 @@ class Conditional implements IComparable
const CONDITION_EXPRESSION = 'expression';
const CONDITION_CONTAINSBLANKS = 'containsBlanks';
const CONDITION_NOTCONTAINSBLANKS = 'notContainsBlanks';
const CONDITION_DATABAR = 'dataBar';

// Operator types
const OPERATOR_NONE = '';
Expand Down Expand Up @@ -64,6 +66,11 @@ class Conditional implements IComparable
*/
private $condition = [];

/**
* @var ConditionalDataBar
*/
private $dataBar;

/**
* Style.
*
Expand Down Expand Up @@ -241,6 +248,28 @@ public function setStyle(?Style $pValue = null)
return $this;
}

/**
* get DataBar.
*
* @return ConditionalDataBar | null
*/
public function getDataBar()
{
return $this->dataBar;
}

/**
* set DataBar.
*
* @return $this
*/
public function setDataBar(ConditionalDataBar $dataBar)
{
$this->dataBar = $dataBar;

return $this;
}

/**
* Get hash code.
*
Expand Down
102 changes: 102 additions & 0 deletions src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalDataBar.php
@@ -0,0 +1,102 @@
<?php

namespace PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting;

class ConditionalDataBar
{
/** <dataBar> attribute */

/** @var null|bool */
private $showValue;

/** <dataBar> children */

/** @var ConditionalFormatValueObject */
private $minimumConditionalFormatValueObject;

/** @var ConditionalFormatValueObject */
private $maximumConditionalFormatValueObject;

/** @var string */
private $color;

/** <extLst> */

/** @var ConditionalFormattingRuleExtension */
private $conditionalFormattingRuleExt;

/**
* @return null|bool
*/
public function getShowValue()
{
return $this->showValue;
}

/**
* @param bool $showValue
*/
public function setShowValue($showValue)
{
$this->showValue = $showValue;

return $this;
}

/**
* @return ConditionalFormatValueObject
*/
public function getMinimumConditionalFormatValueObject()
{
return $this->minimumConditionalFormatValueObject;
}

public function setMinimumConditionalFormatValueObject(ConditionalFormatValueObject $minimumConditionalFormatValueObject)
{
$this->minimumConditionalFormatValueObject = $minimumConditionalFormatValueObject;

return $this;
}

/**
* @return ConditionalFormatValueObject
*/
public function getMaximumConditionalFormatValueObject()
{
return $this->maximumConditionalFormatValueObject;
}

public function setMaximumConditionalFormatValueObject(ConditionalFormatValueObject $maximumConditionalFormatValueObject)
{
$this->maximumConditionalFormatValueObject = $maximumConditionalFormatValueObject;

return $this;
}

public function getColor(): string
{
return $this->color;
}

public function setColor(string $color): self
{
$this->color = $color;

return $this;
}

/**
* @return ConditionalFormattingRuleExtension
*/
public function getConditionalFormattingRuleExt()
{
return $this->conditionalFormattingRuleExt;
}

public function setConditionalFormattingRuleExt(ConditionalFormattingRuleExtension $conditionalFormattingRuleExt)
{
$this->conditionalFormattingRuleExt = $conditionalFormattingRuleExt;

return $this;
}
}