55use PhpOffice \PhpSpreadsheet \Calculation \Calculation ;
66use PhpOffice \PhpSpreadsheet \Cell \Coordinate ;
77use PhpOffice \PhpSpreadsheet \Cell \DataType ;
8+ use PhpOffice \PhpSpreadsheet \Style \Conditional ;
89use PhpOffice \PhpSpreadsheet \Worksheet \AutoFilter ;
910use PhpOffice \PhpSpreadsheet \Worksheet \Worksheet ;
1011
@@ -198,6 +199,45 @@ protected function adjustHyperlinks($worksheet, $numberOfColumns, $numberOfRows)
198199 }
199200 }
200201
202+ /**
203+ * Update conditional formatting styles when inserting/deleting rows/columns.
204+ *
205+ * @param Worksheet $worksheet The worksheet that we're editing
206+ * @param int $numberOfColumns Number of columns to insert/delete (negative values indicate deletion)
207+ * @param int $numberOfRows Number of rows to insert/delete (negative values indicate deletion)
208+ */
209+ protected function adjustConditionalFormatting ($ worksheet , $ numberOfColumns , $ numberOfRows ): void
210+ {
211+ $ aStyles = $ worksheet ->getConditionalStylesCollection ();
212+ ($ numberOfColumns > 0 || $ numberOfRows > 0 )
213+ ? uksort ($ aStyles , [self ::class, 'cellReverseSort ' ])
214+ : uksort ($ aStyles , [self ::class, 'cellSort ' ]);
215+
216+ foreach ($ aStyles as $ cellAddress => $ cfRules ) {
217+ $ worksheet ->removeConditionalStyles ($ cellAddress );
218+ $ newReference = $ this ->updateCellReference ($ cellAddress );
219+
220+ foreach ($ cfRules as &$ cfRule ) {
221+ /** @var Conditional $cfRule */
222+ $ conditions = $ cfRule ->getConditions ();
223+ foreach ($ conditions as &$ condition ) {
224+ if (is_string ($ condition )) {
225+ $ condition = $ this ->updateFormulaReferences (
226+ $ condition ,
227+ $ this ->cellReferenceHelper ->beforeCellAddress (),
228+ $ numberOfColumns ,
229+ $ numberOfRows ,
230+ $ worksheet ->getTitle (),
231+ true
232+ );
233+ }
234+ }
235+ $ cfRule ->setConditions ($ conditions );
236+ }
237+ $ worksheet ->setConditionalStyles ($ newReference , $ cfRules );
238+ }
239+ }
240+
201241 /**
202242 * Update data validations when inserting/deleting rows/columns.
203243 *
@@ -442,6 +482,9 @@ function ($coordinate) use ($allCoordinates) {
442482 // Update worksheet: hyperlinks
443483 $ this ->adjustHyperlinks ($ worksheet , $ numberOfColumns , $ numberOfRows );
444484
485+ // Update worksheet: conditional formatting styles
486+ $ this ->adjustConditionalFormatting ($ worksheet , $ numberOfColumns , $ numberOfRows );
487+
445488 // Update worksheet: data validations
446489 $ this ->adjustDataValidations ($ worksheet , $ numberOfColumns , $ numberOfRows );
447490
@@ -505,8 +548,14 @@ function ($coordinate) use ($allCoordinates) {
505548 *
506549 * @return string Updated formula
507550 */
508- public function updateFormulaReferences ($ formula = '' , $ beforeCellAddress = 'A1 ' , $ numberOfColumns = 0 , $ numberOfRows = 0 , $ worksheetName = '' )
509- {
551+ public function updateFormulaReferences (
552+ $ formula = '' ,
553+ $ beforeCellAddress = 'A1 ' ,
554+ $ numberOfColumns = 0 ,
555+ $ numberOfRows = 0 ,
556+ $ worksheetName = '' ,
557+ bool $ includeAbsoluteReferences = false
558+ ) {
510559 if (
511560 $ this ->cellReferenceHelper === null ||
512561 $ this ->cellReferenceHelper ->refreshRequired ($ beforeCellAddress , $ numberOfColumns , $ numberOfRows )
@@ -528,8 +577,8 @@ public function updateFormulaReferences($formula = '', $beforeCellAddress = 'A1'
528577 foreach ($ matches as $ match ) {
529578 $ fromString = ($ match [2 ] > '' ) ? $ match [2 ] . '! ' : '' ;
530579 $ fromString .= $ match [3 ] . ': ' . $ match [4 ];
531- $ modified3 = substr ($ this ->updateCellReference ('$A ' . $ match [3 ]), 2 );
532- $ modified4 = substr ($ this ->updateCellReference ('$A ' . $ match [4 ]), 2 );
580+ $ modified3 = substr ($ this ->updateCellReference ('$A ' . $ match [3 ], $ includeAbsoluteReferences ), 2 );
581+ $ modified4 = substr ($ this ->updateCellReference ('$A ' . $ match [4 ], $ includeAbsoluteReferences ), 2 );
533582
534583 if ($ match [3 ] . ': ' . $ match [4 ] !== $ modified3 . ': ' . $ modified4 ) {
535584 if (($ match [2 ] == '' ) || (trim ($ match [2 ], "' " ) == $ worksheetName )) {
@@ -553,8 +602,8 @@ public function updateFormulaReferences($formula = '', $beforeCellAddress = 'A1'
553602 foreach ($ matches as $ match ) {
554603 $ fromString = ($ match [2 ] > '' ) ? $ match [2 ] . '! ' : '' ;
555604 $ fromString .= $ match [3 ] . ': ' . $ match [4 ];
556- $ modified3 = substr ($ this ->updateCellReference ($ match [3 ] . '$1 ' ), 0 , -2 );
557- $ modified4 = substr ($ this ->updateCellReference ($ match [4 ] . '$1 ' ), 0 , -2 );
605+ $ modified3 = substr ($ this ->updateCellReference ($ match [3 ] . '$1 ' , $ includeAbsoluteReferences ), 0 , -2 );
606+ $ modified4 = substr ($ this ->updateCellReference ($ match [4 ] . '$1 ' , $ includeAbsoluteReferences ), 0 , -2 );
558607
559608 if ($ match [3 ] . ': ' . $ match [4 ] !== $ modified3 . ': ' . $ modified4 ) {
560609 if (($ match [2 ] == '' ) || (trim ($ match [2 ], "' " ) == $ worksheetName )) {
@@ -578,8 +627,8 @@ public function updateFormulaReferences($formula = '', $beforeCellAddress = 'A1'
578627 foreach ($ matches as $ match ) {
579628 $ fromString = ($ match [2 ] > '' ) ? $ match [2 ] . '! ' : '' ;
580629 $ fromString .= $ match [3 ] . ': ' . $ match [4 ];
581- $ modified3 = $ this ->updateCellReference ($ match [3 ]);
582- $ modified4 = $ this ->updateCellReference ($ match [4 ]);
630+ $ modified3 = $ this ->updateCellReference ($ match [3 ], $ includeAbsoluteReferences );
631+ $ modified4 = $ this ->updateCellReference ($ match [4 ], $ includeAbsoluteReferences );
583632
584633 if ($ match [3 ] . $ match [4 ] !== $ modified3 . $ modified4 ) {
585634 if (($ match [2 ] == '' ) || (trim ($ match [2 ], "' " ) == $ worksheetName )) {
@@ -606,7 +655,7 @@ public function updateFormulaReferences($formula = '', $beforeCellAddress = 'A1'
606655 $ fromString = ($ match [2 ] > '' ) ? $ match [2 ] . '! ' : '' ;
607656 $ fromString .= $ match [3 ];
608657
609- $ modified3 = $ this ->updateCellReference ($ match [3 ]);
658+ $ modified3 = $ this ->updateCellReference ($ match [3 ], $ includeAbsoluteReferences );
610659 if ($ match [3 ] !== $ modified3 ) {
611660 if (($ match [2 ] == '' ) || (trim ($ match [2 ], "' " ) == $ worksheetName )) {
612661 $ toString = ($ match [2 ] > '' ) ? $ match [2 ] . '! ' : '' ;
@@ -786,18 +835,18 @@ private function updateRowRangesAllWorksheets(string $formula, int $numberOfRows
786835 *
787836 * @return string Updated cell range
788837 */
789- private function updateCellReference ($ cellReference = 'A1 ' )
838+ private function updateCellReference ($ cellReference = 'A1 ' , bool $ includeAbsoluteReferences = false )
790839 {
791840 // Is it in another worksheet? Will not have to update anything.
792841 if (strpos ($ cellReference , '! ' ) !== false ) {
793842 return $ cellReference ;
794843 // Is it a range or a single cell?
795844 } elseif (!Coordinate::coordinateIsRange ($ cellReference )) {
796845 // Single cell
797- return $ this ->cellReferenceHelper ->updateCellReference ($ cellReference );
846+ return $ this ->cellReferenceHelper ->updateCellReference ($ cellReference, $ includeAbsoluteReferences );
798847 } elseif (Coordinate::coordinateIsRange ($ cellReference )) {
799848 // Range
800- return $ this ->updateCellRange ($ cellReference );
849+ return $ this ->updateCellRange ($ cellReference, $ includeAbsoluteReferences );
801850 }
802851
803852 // Return original
@@ -839,7 +888,7 @@ public function updateNamedFormulas(Spreadsheet $spreadsheet, $oldName = '', $ne
839888 *
840889 * @return string Updated cell range
841890 */
842- private function updateCellRange (string $ cellRange = 'A1:A1 ' ): string
891+ private function updateCellRange (string $ cellRange = 'A1:A1 ' , bool $ includeAbsoluteReferences = false ): string
843892 {
844893 if (!Coordinate::coordinateIsRange ($ cellRange )) {
845894 throw new Exception ('Only cell ranges may be passed to this method. ' );
@@ -853,14 +902,14 @@ private function updateCellRange(string $cellRange = 'A1:A1'): string
853902 for ($ j = 0 ; $ j < $ jc ; ++$ j ) {
854903 if (ctype_alpha ($ range [$ i ][$ j ])) {
855904 $ range [$ i ][$ j ] = Coordinate::coordinateFromString (
856- $ this ->cellReferenceHelper ->updateCellReference ($ range [$ i ][$ j ] . '1 ' )
905+ $ this ->cellReferenceHelper ->updateCellReference ($ range [$ i ][$ j ] . '1 ' , $ includeAbsoluteReferences )
857906 )[0 ];
858907 } elseif (ctype_digit ($ range [$ i ][$ j ])) {
859908 $ range [$ i ][$ j ] = Coordinate::coordinateFromString (
860- $ this ->cellReferenceHelper ->updateCellReference ('A ' . $ range [$ i ][$ j ])
909+ $ this ->cellReferenceHelper ->updateCellReference ('A ' . $ range [$ i ][$ j ], $ includeAbsoluteReferences )
861910 )[1 ];
862911 } else {
863- $ range [$ i ][$ j ] = $ this ->cellReferenceHelper ->updateCellReference ($ range [$ i ][$ j ]);
912+ $ range [$ i ][$ j ] = $ this ->cellReferenceHelper ->updateCellReference ($ range [$ i ][$ j ], $ includeAbsoluteReferences );
864913 }
865914 }
866915 }
@@ -985,17 +1034,8 @@ private function duplicateStylesByColumn(Worksheet $worksheet, int $beforeColumn
9851034 $ coordinate = $ beforeColumnName . $ i ;
9861035 if ($ worksheet ->cellExists ($ coordinate )) {
9871036 $ xfIndex = $ worksheet ->getCell ($ coordinate )->getXfIndex ();
988- $ conditionalStyles = $ worksheet ->conditionalStylesExists ($ coordinate ) ?
989- $ worksheet ->getConditionalStyles ($ coordinate ) : false ;
9901037 for ($ j = $ beforeColumn ; $ j <= $ beforeColumn - 1 + $ numberOfColumns ; ++$ j ) {
9911038 $ worksheet ->getCellByColumnAndRow ($ j , $ i )->setXfIndex ($ xfIndex );
992- if ($ conditionalStyles ) {
993- $ cloned = [];
994- foreach ($ conditionalStyles as $ conditionalStyle ) {
995- $ cloned [] = clone $ conditionalStyle ;
996- }
997- $ worksheet ->setConditionalStyles (Coordinate::stringFromColumnIndex ($ j ) . $ i , $ cloned );
998- }
9991039 }
10001040 }
10011041 }
@@ -1009,17 +1049,8 @@ private function duplicateStylesByRow(Worksheet $worksheet, int $beforeColumn, i
10091049 $ coordinate = Coordinate::stringFromColumnIndex ($ i ) . ($ beforeRow - 1 );
10101050 if ($ worksheet ->cellExists ($ coordinate )) {
10111051 $ xfIndex = $ worksheet ->getCell ($ coordinate )->getXfIndex ();
1012- $ conditionalStyles = $ worksheet ->conditionalStylesExists ($ coordinate ) ?
1013- $ worksheet ->getConditionalStyles ($ coordinate ) : false ;
10141052 for ($ j = $ beforeRow ; $ j <= $ beforeRow - 1 + $ numberOfRows ; ++$ j ) {
10151053 $ worksheet ->getCell (Coordinate::stringFromColumnIndex ($ i ) . $ j )->setXfIndex ($ xfIndex );
1016- if ($ conditionalStyles ) {
1017- $ cloned = [];
1018- foreach ($ conditionalStyles as $ conditionalStyle ) {
1019- $ cloned [] = clone $ conditionalStyle ;
1020- }
1021- $ worksheet ->setConditionalStyles (Coordinate::stringFromColumnIndex ($ i ) . $ j , $ cloned );
1022- }
10231054 }
10241055 }
10251056 }
0 commit comments