Skip to content

Commit

Permalink
Support DataBar of conditional formatting rule
Browse files Browse the repository at this point in the history
Implemented the databar of Conditional Type.
- DataBar can be read, written, and added for basic use.
- Supports reading, writing and adding using "extLst".

About "extLst"
- https://docs.microsoft.com/en-us/openspecs/office_standards/ms-xlsx/07d607af-5618-4ca2-b683-6a78dc0d9627

The following setting items on the Excel setting screen can be read, written, and added.
- (minimum, maximum)type: Automatic, LowestValue, Number, Percent, Formula, Percentile
- Direction: context, leftToRight, rightToLeft (show data bar only)
- Fills Solid, Gradient
- FillColor: PositiveValues, NegativeValues
- Borders: Solid, None
- BorderColor: PositiveValues, NegativeValues
- Axis position: Automatic, Midpoint, None
- Axis color
  • Loading branch information
tera911 committed Dec 13, 2020
1 parent 40abd18 commit a863926
Show file tree
Hide file tree
Showing 9 changed files with 1,189 additions and 12 deletions.
66 changes: 56 additions & 10 deletions src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php
Expand Up @@ -2,7 +2,10 @@

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\Worksheet\Worksheet;
use SimpleXMLElement;

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

Expand All @@ -36,26 +40,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 +71,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 +95,49 @@ 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((int) $cfRule->dataBar['showValue']);
}

//dataBar children
//conditionalFormatValueObjects
$cfvoXml = $cfRule->dataBar->cfvo;
foreach ((count($cfvoXml) > 1 ? $cfvoXml : [$cfvoXml]) as $cfvo) {
$dataBar->addConditionalFormatValueObject((string) $cfvo['type'], (string) $cfvo['val']);
}

//color
if (isset($cfRule->dataBar->color)) {
$dataBar->setColor(new Color((string) $cfRule->dataBar->color['rgb']));
}
//extLst
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->addConditionalFormattingRuleExtList($conditionalFormattingRuleExtensions[$extId]);
}
}
}

return $dataBar;
}
}
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
112 changes: 112 additions & 0 deletions src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalDataBar.php
@@ -0,0 +1,112 @@
<?php

namespace PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting;

use PhpOffice\PhpSpreadsheet\Style\Color;

class ConditionalDataBar
{
/** <dataBar> attribute */
private $showValue;

/** <dataBar> children */

/** @var ConditionalFormatValueObject[] */
private $conditionalFormatValueObjects = [];

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

/** @var ConditionalFormattingRuleExtension[] */
private $conditionalFormattingRuleExtList = [];

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

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

return $this;
}

/**
* @return ConditionalFormatValueObject[]
*/
public function getConditionalFormatValueObjects(): array
{
return $this->conditionalFormatValueObjects;
}

/**
* @param ConditionalFormatValueObject[] $conditionalFormatValueObjects
*/
public function setConditionalFormatValueObjects(array $conditionalFormatValueObjects)
{
$this->conditionalFormatValueObjects = $conditionalFormatValueObjects;

return $this;
}

/**
* @param mixed $type
* @param null|mixed $value
* @param null|mixed $cellFomula
*
* @return $this
*/
public function addConditionalFormatValueObject($type, $value = null, $cellFomula = null): self
{
$this->conditionalFormatValueObjects[] = new ConditionalFormatValueObject($type, $value, $cellFomula);

return $this;
}

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

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

return $this;
}

/**
* @return ConditionalFormattingRuleExtension[]
*/
public function getConditionalFormattingRuleExtList(): array
{
return $this->conditionalFormattingRuleExtList;
}

/**
* @param ConditionalFormattingRuleExtension[] $conditionalFormattingRuleExtList
*/
public function setConditionalFormattingRuleExtList(array $conditionalFormattingRuleExtList): self
{
$this->conditionalFormattingRuleExtList = $conditionalFormattingRuleExtList;

return $this;
}

/**
* @return $this
*/
public function addConditionalFormattingRuleExtList(ConditionalFormattingRuleExtension $conditionalFormattingRuleExt): self
{
$this->conditionalFormattingRuleExtList[] = $conditionalFormattingRuleExt;

return $this;
}
}

0 comments on commit a863926

Please sign in to comment.