From 85c601f5429168987e013b2acfb101a8bb6045fc Mon Sep 17 00:00:00 2001 From: sorpigal Date: Fri, 26 Apr 2013 23:16:24 -0400 Subject: [PATCH 1/3] Write conditional formatting styles to worksheet instead of copying to each individual cell. --- Classes/PHPExcel/Reader/Excel2007.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Classes/PHPExcel/Reader/Excel2007.php b/Classes/PHPExcel/Reader/Excel2007.php index e2a677dec..cf0fdc119 100644 --- a/Classes/PHPExcel/Reader/Excel2007.php +++ b/Classes/PHPExcel/Reader/Excel2007.php @@ -938,11 +938,8 @@ public function load($pFilename) $objConditional->setStyle(clone $dxfs[intval($cfRule["dxfId"])]); $conditionalStyles[] = $objConditional; } - - // Extract all cell references in $ref - $aReferences = PHPExcel_Cell::extractAllCellReferencesInRange($ref); - foreach ($aReferences as $reference) { - $docSheet->getStyle($reference)->setConditionalStyles($conditionalStyles); + foreach(explode(' ', $ref) as $single_ref){ + docSheet->setConditionalStyles($single_ref, $conditionalStyles); } } } From 912a8655937886065485a6d6439a1e9668003751 Mon Sep 17 00:00:00 2001 From: sorpigal Date: Mon, 29 Apr 2013 21:16:43 -0400 Subject: [PATCH 2/3] On read assign conditional formatting ranges properly. On write use proper cell reference when writing blocks. Support for stopIfTrue and {notC,c}ontainsBlanks was added. --- Classes/PHPExcel/Reader/Excel2007.php | 12 +++--- Classes/PHPExcel/Style/Conditional.php | 36 +++++++++++++++++ .../PHPExcel/Writer/Excel2007/Worksheet.php | 39 +++++++++++++++---- 3 files changed, 74 insertions(+), 13 deletions(-) diff --git a/Classes/PHPExcel/Reader/Excel2007.php b/Classes/PHPExcel/Reader/Excel2007.php index cf0fdc119..7b772980a 100644 --- a/Classes/PHPExcel/Reader/Excel2007.php +++ b/Classes/PHPExcel/Reader/Excel2007.php @@ -908,7 +908,9 @@ public function load($pFilename) (string)$cfRule["type"] == PHPExcel_Style_Conditional::CONDITION_NONE || (string)$cfRule["type"] == PHPExcel_Style_Conditional::CONDITION_CELLIS || (string)$cfRule["type"] == PHPExcel_Style_Conditional::CONDITION_CONTAINSTEXT || - (string)$cfRule["type"] == PHPExcel_Style_Conditional::CONDITION_EXPRESSION + (string)$cfRule["type"] == PHPExcel_Style_Conditional::CONDITION_EXPRESSION || + (string)$cfRule["type"] == PHPExcel_Style_Conditional::CONDITION_BLANK || + (string)$cfRule["type"] == PHPExcel_Style_Conditional::CONDITION_NOTBLANK ) && isset($dxfs[intval($cfRule["dxfId"])]) ) { $conditionals[(string) $conditional["sqref"]][intval($cfRule["priority"])] = $cfRule; @@ -917,13 +919,14 @@ public function load($pFilename) } foreach ($conditionals as $ref => $cfRules) { - ksort($cfRules); $conditionalStyles = array(); foreach ($cfRules as $cfRule) { $objConditional = new PHPExcel_Style_Conditional(); $objConditional->setConditionType((string)$cfRule["type"]); $objConditional->setOperatorType((string)$cfRule["operator"]); + $objConditional->setStopIfTrue((string)$cfRule["stopIfTrue"]); + if ((string)$cfRule["text"] != '') { $objConditional->setText((string)$cfRule["text"]); } @@ -938,9 +941,8 @@ public function load($pFilename) $objConditional->setStyle(clone $dxfs[intval($cfRule["dxfId"])]); $conditionalStyles[] = $objConditional; } - foreach(explode(' ', $ref) as $single_ref){ - docSheet->setConditionalStyles($single_ref, $conditionalStyles); - } + + $docSheet->setConditionalStyles($ref, $conditionalStyles); } } diff --git a/Classes/PHPExcel/Style/Conditional.php b/Classes/PHPExcel/Style/Conditional.php index 9573f5b78..764532e53 100644 --- a/Classes/PHPExcel/Style/Conditional.php +++ b/Classes/PHPExcel/Style/Conditional.php @@ -40,6 +40,8 @@ class PHPExcel_Style_Conditional implements PHPExcel_IComparable const CONDITION_CELLIS = 'cellIs'; const CONDITION_CONTAINSTEXT = 'containsText'; const CONDITION_EXPRESSION = 'expression'; + const CONDITION_CONTAINSBLANKS = 'containsBlanks'; + const CONDITION_NOTCONTAINSBLANKS = 'notContainsBlanks'; /* Operator types */ const OPERATOR_NONE = ''; @@ -55,6 +57,8 @@ class PHPExcel_Style_Conditional implements PHPExcel_IComparable const OPERATOR_NOTCONTAINS = 'notContains'; const OPERATOR_BETWEEN = 'between'; + const STOP_IF_TRUE = '1'; + /** * Condition type * @@ -76,6 +80,13 @@ class PHPExcel_Style_Conditional implements PHPExcel_IComparable */ private $_text; + /** + * Stop If True + * + * @var string + */ + private $_stopIfTrue = ''; + /** * Condition * @@ -163,6 +174,31 @@ public function setText($value = null) { return $this; } + /** + * Get Stop If True + * + * @return string + */ + public function getStopIfTrue() { + return $this->_stopIfTrue; + } + + /** + * Set Stop If True + * + * @param string $pValue + * @return PHPExcel_Style_Conditional + */ + public function setStopIfTrue($pValue = '') { + if($pValue === PHPExcel_Style_Conditional::STOP_IF_TRUE){ + $this->_stopIfTrue = $pValue; + } else{ + // treat all unknown as "unset" + $this->_stopIfTrue = ''; + } + return $this; + } + /** * Get Condition * diff --git a/Classes/PHPExcel/Writer/Excel2007/Worksheet.php b/Classes/PHPExcel/Writer/Excel2007/Worksheet.php index cb1437d32..cf7063c01 100644 --- a/Classes/PHPExcel/Writer/Excel2007/Worksheet.php +++ b/Classes/PHPExcel/Writer/Excel2007/Worksheet.php @@ -465,15 +465,26 @@ private function _writeConditionalFormatting(PHPExcel_Shared_XMLWriter $objWrite // Loop through styles in the current worksheet foreach ($pSheet->getConditionalStylesCollection() as $cellCoordinate => $conditionalStyles) { + $cell_ref = ''; + if(count($conditionalStyles) > 0){ // write conditionalStyles only if we are going to have some cfRules + $objWriter->startElement('conditionalFormatting'); + $objWriter->writeAttribute('sqref', $cellCoordinate); + + /* inside certain conditions a single cell reference is required, + * but the conditional style may be applied to an range or a set + * of ranges. Any single one of the cells in this range seems to + * be sufficient and seems to match sheets written by Excel. */ + $cell_ref = array_shift(PHPExcel_Cell::extractAllCellReferencesInRange($cellCoordinate)); + } + foreach ($conditionalStyles as $conditional) { // WHY was this again? // if ($this->getParentWriter()->getStylesConditionalHashTable()->getIndexForHashCode( $conditional->getHashCode() ) == '') { // continue; // } + if ($conditional->getConditionType() != PHPExcel_Style_Conditional::CONDITION_NONE) { // conditionalFormatting - $objWriter->startElement('conditionalFormatting'); - $objWriter->writeAttribute('sqref', $cellCoordinate); // cfRule $objWriter->startElement('cfRule'); @@ -481,9 +492,13 @@ private function _writeConditionalFormatting(PHPExcel_Shared_XMLWriter $objWrite $objWriter->writeAttribute('dxfId', $this->getParentWriter()->getStylesConditionalHashTable()->getIndexForHashCode( $conditional->getHashCode() )); $objWriter->writeAttribute('priority', $id++); + if($conditional->getStopIfTrue() !== ''){ + $objWriter->writeAttribute('stopIfTrue', $conditional->getStopIfTrue()); + } + if (($conditional->getConditionType() == PHPExcel_Style_Conditional::CONDITION_CELLIS || - $conditional->getConditionType() == PHPExcel_Style_Conditional::CONDITION_CONTAINSTEXT) + $conditional->getConditionType() == PHPExcel_Style_Conditional::CONDITION_CONTAINSTEXT) && $conditional->getOperatorType() != PHPExcel_Style_Conditional::OPERATOR_NONE) { $objWriter->writeAttribute('operator', $conditional->getOperatorType()); } @@ -496,19 +511,19 @@ private function _writeConditionalFormatting(PHPExcel_Shared_XMLWriter $objWrite if ($conditional->getConditionType() == PHPExcel_Style_Conditional::CONDITION_CONTAINSTEXT && $conditional->getOperatorType() == PHPExcel_Style_Conditional::OPERATOR_CONTAINSTEXT && !is_null($conditional->getText())) { - $objWriter->writeElement('formula', 'NOT(ISERROR(SEARCH("' . $conditional->getText() . '",' . $cellCoordinate . ')))'); + $objWriter->writeElement('formula', 'NOT(ISERROR(SEARCH("' . $conditional->getText() . '",' . $cell_ref . ')))'); } else if ($conditional->getConditionType() == PHPExcel_Style_Conditional::CONDITION_CONTAINSTEXT && $conditional->getOperatorType() == PHPExcel_Style_Conditional::OPERATOR_BEGINSWITH && !is_null($conditional->getText())) { - $objWriter->writeElement('formula', 'LEFT(' . $cellCoordinate . ',' . strlen($conditional->getText()) . ')="' . $conditional->getText() . '"'); + $objWriter->writeElement('formula', 'LEFT(' . $cell_ref . ',' . strlen($conditional->getText()) . ')="' . $conditional->getText() . '"'); } else if ($conditional->getConditionType() == PHPExcel_Style_Conditional::CONDITION_CONTAINSTEXT && $conditional->getOperatorType() == PHPExcel_Style_Conditional::OPERATOR_ENDSWITH && !is_null($conditional->getText())) { - $objWriter->writeElement('formula', 'RIGHT(' . $cellCoordinate . ',' . strlen($conditional->getText()) . ')="' . $conditional->getText() . '"'); + $objWriter->writeElement('formula', 'RIGHT(' . $cell_ref . ',' . strlen($conditional->getText()) . ')="' . $conditional->getText() . '"'); } else if ($conditional->getConditionType() == PHPExcel_Style_Conditional::CONDITION_CONTAINSTEXT && $conditional->getOperatorType() == PHPExcel_Style_Conditional::OPERATOR_NOTCONTAINS && !is_null($conditional->getText())) { - $objWriter->writeElement('formula', 'ISERROR(SEARCH("' . $conditional->getText() . '",' . $cellCoordinate . '))'); + $objWriter->writeElement('formula', 'ISERROR(SEARCH("' . $conditional->getText() . '",' . $cell_ref . '))'); } else if ($conditional->getConditionType() == PHPExcel_Style_Conditional::CONDITION_CELLIS || $conditional->getConditionType() == PHPExcel_Style_Conditional::CONDITION_CONTAINSTEXT || $conditional->getConditionType() == PHPExcel_Style_Conditional::CONDITION_EXPRESSION) { @@ -516,13 +531,21 @@ private function _writeConditionalFormatting(PHPExcel_Shared_XMLWriter $objWrite // Formula $objWriter->writeElement('formula', $formula); } + } else if ($conditional->getConditionType() == PHPExcel_Style_Conditional::CONDITION_CONTAINSBLANKS + && $cell_ref !== '') { + $objWriter->writeElement('formula', 'LEFT(TRIM(' . $cell_ref . '))=0'); + } else if ($conditional->getConditionType() == PHPExcel_Style_Conditional::CONDITION_NOTCONTAINSBLANKS + && $cell_ref !== '') { + $objWriter->writeElement('formula', 'LEFT(TRIM(' . $cell_ref . '))>0'); } $objWriter->endElement(); - $objWriter->endElement(); } } + if(count($conditionalStyles) > 0){ + $objWriter->endElement(); + } } } From d9a9c23fea84eb8403804cce94141d074d3984c1 Mon Sep 17 00:00:00 2001 From: sorpigal Date: Wed, 29 Jan 2014 15:03:07 -0500 Subject: [PATCH 3/3] Conditional style priority support for Excel2007. Not tested. --- Classes/PHPExcel/Reader/Excel2007.php | 7 ++++++- Classes/PHPExcel/Style/Conditional.php | 24 ++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/Classes/PHPExcel/Reader/Excel2007.php b/Classes/PHPExcel/Reader/Excel2007.php index 7b772980a..c9f20744d 100644 --- a/Classes/PHPExcel/Reader/Excel2007.php +++ b/Classes/PHPExcel/Reader/Excel2007.php @@ -925,6 +925,7 @@ public function load($pFilename) $objConditional->setConditionType((string)$cfRule["type"]); $objConditional->setOperatorType((string)$cfRule["operator"]); + $objConditional->setPriority((int)$cfRule["priority"]); $objConditional->setStopIfTrue((string)$cfRule["stopIfTrue"]); if ((string)$cfRule["text"] != '') { @@ -938,7 +939,11 @@ public function load($pFilename) } else { $objConditional->addCondition((string)$cfRule->formula); } - $objConditional->setStyle(clone $dxfs[intval($cfRule["dxfId"])]); + + // the rule may unset formatting in which case dxfId will not be present + if(isset($cfRule["dxfId"]])){ + $objConditional->setStyle(clone $dxfs[(int)$cfRule["dxfId"]]); + } $conditionalStyles[] = $objConditional; } diff --git a/Classes/PHPExcel/Style/Conditional.php b/Classes/PHPExcel/Style/Conditional.php index 764532e53..7987d68ce 100644 --- a/Classes/PHPExcel/Style/Conditional.php +++ b/Classes/PHPExcel/Style/Conditional.php @@ -177,6 +177,8 @@ public function setText($value = null) { /** * Get Stop If True * + * Whether to stop processing conditional formatting rules for a given cell if this rule evaluates to true. + * * @return string */ public function getStopIfTrue() { @@ -199,6 +201,28 @@ public function setStopIfTrue($pValue = '') { return $this; } + /** + * Get Priority + * + * Priority is the order in which conditional formatting rules will apply to the affected range(s). Lower priority values run first. + * + * @return int + */ + public function getPriority() { + return $this->_priority; + } + + /** + * Set Priority + * + * @param int $pValue + * @return PHPExcel_Style_Conditional + */ + public function setStopIfTrue($pValue = 0) { + $this->_priority = $pValue; + return $this; + } + /** * Get Condition *