5
5
use PhpOffice \PhpSpreadsheet \Calculation \Calculation ;
6
6
use PhpOffice \PhpSpreadsheet \Cell \Coordinate ;
7
7
use PhpOffice \PhpSpreadsheet \Cell \DataType ;
8
+ use PhpOffice \PhpSpreadsheet \Worksheet \AutoFilter ;
8
9
use PhpOffice \PhpSpreadsheet \Worksheet \Worksheet ;
9
10
10
11
class ReferenceHelper
@@ -358,8 +359,12 @@ protected function adjustRowDimensions(Worksheet $worksheet, $beforeCellAddress,
358
359
* @param int $numberOfRows Number of rows to insert/delete (negative values indicate deletion)
359
360
* @param Worksheet $worksheet The worksheet that we're editing
360
361
*/
361
- public function insertNewBefore ($ beforeCellAddress , $ numberOfColumns , $ numberOfRows , Worksheet $ worksheet ): void
362
- {
362
+ public function insertNewBefore (
363
+ string $ beforeCellAddress ,
364
+ int $ numberOfColumns ,
365
+ int $ numberOfRows ,
366
+ Worksheet $ worksheet
367
+ ): void {
363
368
$ remove = ($ numberOfColumns < 0 || $ numberOfRows < 0 );
364
369
$ allCoordinates = $ worksheet ->getCoordinates ();
365
370
@@ -372,30 +377,12 @@ public function insertNewBefore($beforeCellAddress, $numberOfColumns, $numberOfR
372
377
373
378
// 1. Clear column strips if we are removing columns
374
379
if ($ numberOfColumns < 0 && $ beforeColumn - 2 + $ numberOfColumns > 0 ) {
375
- for ($ i = 1 ; $ i <= $ highestRow - 1 ; ++$ i ) {
376
- for ($ j = $ beforeColumn - 1 + $ numberOfColumns ; $ j <= $ beforeColumn - 2 ; ++$ j ) {
377
- $ coordinate = Coordinate::stringFromColumnIndex ($ j + 1 ) . $ i ;
378
- $ worksheet ->removeConditionalStyles ($ coordinate );
379
- if ($ worksheet ->cellExists ($ coordinate )) {
380
- $ worksheet ->getCell ($ coordinate )->setValueExplicit ('' , DataType::TYPE_NULL );
381
- $ worksheet ->getCell ($ coordinate )->setXfIndex (0 );
382
- }
383
- }
384
- }
380
+ $ this ->clearColumnStrips ($ highestRow , $ beforeColumn , $ numberOfColumns , $ worksheet );
385
381
}
386
382
387
383
// 2. Clear row strips if we are removing rows
388
384
if ($ numberOfRows < 0 && $ beforeRow - 1 + $ numberOfRows > 0 ) {
389
- for ($ i = $ beforeColumn - 1 ; $ i <= Coordinate::columnIndexFromString ($ highestColumn ) - 1 ; ++$ i ) {
390
- for ($ j = $ beforeRow + $ numberOfRows ; $ j <= $ beforeRow - 1 ; ++$ j ) {
391
- $ coordinate = Coordinate::stringFromColumnIndex ($ i + 1 ) . $ j ;
392
- $ worksheet ->removeConditionalStyles ($ coordinate );
393
- if ($ worksheet ->cellExists ($ coordinate )) {
394
- $ worksheet ->getCell ($ coordinate )->setValueExplicit ('' , DataType::TYPE_NULL );
395
- $ worksheet ->getCell ($ coordinate )->setXfIndex (0 );
396
- }
397
- }
398
- }
385
+ $ this ->clearRowStrips ($ highestColumn , $ beforeColumn , $ beforeRow , $ numberOfRows , $ worksheet );
399
386
}
400
387
401
388
// Find missing coordinates. This is important when inserting column before the last column
@@ -476,47 +463,11 @@ function ($coordinate) use ($allCoordinates) {
476
463
$ highestRow = $ worksheet ->getHighestRow ();
477
464
478
465
if ($ numberOfColumns > 0 && $ beforeColumn - 2 > 0 ) {
479
- for ($ i = $ beforeRow ; $ i <= $ highestRow - 1 ; ++$ i ) {
480
- // Style
481
- $ coordinate = Coordinate::stringFromColumnIndex ($ beforeColumn - 1 ) . $ i ;
482
- if ($ worksheet ->cellExists ($ coordinate )) {
483
- $ xfIndex = $ worksheet ->getCell ($ coordinate )->getXfIndex ();
484
- $ conditionalStyles = $ worksheet ->conditionalStylesExists ($ coordinate ) ?
485
- $ worksheet ->getConditionalStyles ($ coordinate ) : false ;
486
- for ($ j = $ beforeColumn ; $ j <= $ beforeColumn - 1 + $ numberOfColumns ; ++$ j ) {
487
- $ worksheet ->getCellByColumnAndRow ($ j , $ i )->setXfIndex ($ xfIndex );
488
- if ($ conditionalStyles ) {
489
- $ cloned = [];
490
- foreach ($ conditionalStyles as $ conditionalStyle ) {
491
- $ cloned [] = clone $ conditionalStyle ;
492
- }
493
- $ worksheet ->setConditionalStyles (Coordinate::stringFromColumnIndex ($ j ) . $ i , $ cloned );
494
- }
495
- }
496
- }
497
- }
466
+ $ this ->duplicateStylesByColumn ($ worksheet , $ beforeColumn , $ beforeRow , $ highestRow , $ numberOfColumns );
498
467
}
499
468
500
469
if ($ numberOfRows > 0 && $ beforeRow - 1 > 0 ) {
501
- for ($ i = $ beforeColumn ; $ i <= Coordinate::columnIndexFromString ($ highestColumn ); ++$ i ) {
502
- // Style
503
- $ coordinate = Coordinate::stringFromColumnIndex ($ i ) . ($ beforeRow - 1 );
504
- if ($ worksheet ->cellExists ($ coordinate )) {
505
- $ xfIndex = $ worksheet ->getCell ($ coordinate )->getXfIndex ();
506
- $ conditionalStyles = $ worksheet ->conditionalStylesExists ($ coordinate ) ?
507
- $ worksheet ->getConditionalStyles ($ coordinate ) : false ;
508
- for ($ j = $ beforeRow ; $ j <= $ beforeRow - 1 + $ numberOfRows ; ++$ j ) {
509
- $ worksheet ->getCell (Coordinate::stringFromColumnIndex ($ i ) . $ j )->setXfIndex ($ xfIndex );
510
- if ($ conditionalStyles ) {
511
- $ cloned = [];
512
- foreach ($ conditionalStyles as $ conditionalStyle ) {
513
- $ cloned [] = clone $ conditionalStyle ;
514
- }
515
- $ worksheet ->setConditionalStyles (Coordinate::stringFromColumnIndex ($ i ) . $ j , $ cloned );
516
- }
517
- }
518
- }
519
- }
470
+ $ this ->duplicateStylesByRow ($ worksheet , $ beforeColumn , $ beforeRow , $ highestColumn , $ numberOfRows );
520
471
}
521
472
522
473
// Update worksheet: column dimensions
@@ -544,59 +495,7 @@ function ($coordinate) use ($allCoordinates) {
544
495
$ this ->adjustProtectedCells ($ worksheet , $ beforeCellAddress , $ numberOfColumns , $ numberOfRows );
545
496
546
497
// Update worksheet: autofilter
547
- $ autoFilter = $ worksheet ->getAutoFilter ();
548
- $ autoFilterRange = $ autoFilter ->getRange ();
549
- if (!empty ($ autoFilterRange )) {
550
- if ($ numberOfColumns != 0 ) {
551
- $ autoFilterColumns = $ autoFilter ->getColumns ();
552
- if (count ($ autoFilterColumns ) > 0 ) {
553
- $ column = '' ;
554
- $ row = 0 ;
555
- sscanf ($ beforeCellAddress , '%[A-Z]%d ' , $ column , $ row );
556
- $ columnIndex = Coordinate::columnIndexFromString ($ column );
557
- [$ rangeStart , $ rangeEnd ] = Coordinate::rangeBoundaries ($ autoFilterRange );
558
- if ($ columnIndex <= $ rangeEnd [0 ]) {
559
- if ($ numberOfColumns < 0 ) {
560
- // If we're actually deleting any columns that fall within the autofilter range,
561
- // then we delete any rules for those columns
562
- $ deleteColumn = $ columnIndex + $ numberOfColumns - 1 ;
563
- $ deleteCount = abs ($ numberOfColumns );
564
- for ($ i = 1 ; $ i <= $ deleteCount ; ++$ i ) {
565
- if (isset ($ autoFilterColumns [Coordinate::stringFromColumnIndex ($ deleteColumn + 1 )])) {
566
- $ autoFilter ->clearColumn (Coordinate::stringFromColumnIndex ($ deleteColumn + 1 ));
567
- }
568
- ++$ deleteColumn ;
569
- }
570
- }
571
- $ startCol = ($ columnIndex > $ rangeStart [0 ]) ? $ columnIndex : $ rangeStart [0 ];
572
-
573
- // Shuffle columns in autofilter range
574
- if ($ numberOfColumns > 0 ) {
575
- $ startColRef = $ startCol ;
576
- $ endColRef = $ rangeEnd [0 ];
577
- $ toColRef = $ rangeEnd [0 ] + $ numberOfColumns ;
578
-
579
- do {
580
- $ autoFilter ->shiftColumn (Coordinate::stringFromColumnIndex ($ endColRef ), Coordinate::stringFromColumnIndex ($ toColRef ));
581
- --$ endColRef ;
582
- --$ toColRef ;
583
- } while ($ startColRef <= $ endColRef );
584
- } else {
585
- // For delete, we shuffle from beginning to end to avoid overwriting
586
- $ startColID = Coordinate::stringFromColumnIndex ($ startCol );
587
- $ toColID = Coordinate::stringFromColumnIndex ($ startCol + $ numberOfColumns );
588
- $ endColID = Coordinate::stringFromColumnIndex ($ rangeEnd [0 ] + 1 );
589
- do {
590
- $ autoFilter ->shiftColumn ($ startColID , $ toColID );
591
- ++$ startColID ;
592
- ++$ toColID ;
593
- } while ($ startColID != $ endColID );
594
- }
595
- }
596
- }
597
- }
598
- $ worksheet ->setAutoFilter ($ this ->updateCellReference ($ autoFilterRange , $ beforeCellAddress , $ numberOfColumns , $ numberOfRows ));
599
- }
498
+ $ this ->adjustAutoFilter ($ worksheet , $ beforeCellAddress , $ numberOfColumns , $ numberOfRows );
600
499
601
500
// Update worksheet: freeze pane
602
501
if ($ worksheet ->getFreezePane ()) {
@@ -611,7 +510,9 @@ function ($coordinate) use ($allCoordinates) {
611
510
612
511
// Page setup
613
512
if ($ worksheet ->getPageSetup ()->isPrintAreaSet ()) {
614
- $ worksheet ->getPageSetup ()->setPrintArea ($ this ->updateCellReference ($ worksheet ->getPageSetup ()->getPrintArea (), $ beforeCellAddress , $ numberOfColumns , $ numberOfRows ));
513
+ $ worksheet ->getPageSetup ()->setPrintArea (
514
+ $ this ->updateCellReference ($ worksheet ->getPageSetup ()->getPrintArea (), $ beforeCellAddress , $ numberOfColumns , $ numberOfRows )
515
+ );
615
516
}
616
517
617
518
// Update worksheet: drawings
@@ -958,7 +859,7 @@ public function updateNamedFormulas(Spreadsheet $spreadsheet, $oldName = '', $ne
958
859
foreach ($ spreadsheet ->getWorksheetIterator () as $ sheet ) {
959
860
foreach ($ sheet ->getCoordinates (false ) as $ coordinate ) {
960
861
$ cell = $ sheet ->getCell ($ coordinate );
961
- if (($ cell !== null ) && ($ cell ->getDataType () == DataType::TYPE_FORMULA )) {
862
+ if (($ cell !== null ) && ($ cell ->getDataType () === DataType::TYPE_FORMULA )) {
962
863
$ formula = $ cell ->getValue ();
963
864
if (strpos ($ formula , $ oldName ) !== false ) {
964
865
$ formula = str_replace ("' " . $ oldName . "'! " , "' " . $ newName . "'! " , $ formula );
@@ -1048,6 +949,162 @@ private function updateSingleCellReference($cellReference = 'A1', $beforeCellAdd
1048
949
return $ newColumn . $ newRow ;
1049
950
}
1050
951
952
+ private function clearColumnStrips (int $ highestRow , int $ beforeColumn , int $ numberOfColumns , Worksheet $ worksheet ): void
953
+ {
954
+ for ($ i = 1 ; $ i <= $ highestRow - 1 ; ++$ i ) {
955
+ for ($ j = $ beforeColumn - 1 + $ numberOfColumns ; $ j <= $ beforeColumn - 2 ; ++$ j ) {
956
+ $ coordinate = Coordinate::stringFromColumnIndex ($ j + 1 ) . $ i ;
957
+ $ worksheet ->removeConditionalStyles ($ coordinate );
958
+ if ($ worksheet ->cellExists ($ coordinate )) {
959
+ $ worksheet ->getCell ($ coordinate )->setValueExplicit ('' , DataType::TYPE_NULL );
960
+ $ worksheet ->getCell ($ coordinate )->setXfIndex (0 );
961
+ }
962
+ }
963
+ }
964
+ }
965
+
966
+ private function clearRowStrips (string $ highestColumn , int $ beforeColumn , int $ beforeRow , int $ numberOfRows , Worksheet $ worksheet ): void
967
+ {
968
+ $ lastColumnIndex = Coordinate::columnIndexFromString ($ highestColumn ) - 1 ;
969
+
970
+ for ($ i = $ beforeColumn - 1 ; $ i <= $ lastColumnIndex ; ++$ i ) {
971
+ for ($ j = $ beforeRow + $ numberOfRows ; $ j <= $ beforeRow - 1 ; ++$ j ) {
972
+ $ coordinate = Coordinate::stringFromColumnIndex ($ i + 1 ) . $ j ;
973
+ $ worksheet ->removeConditionalStyles ($ coordinate );
974
+ if ($ worksheet ->cellExists ($ coordinate )) {
975
+ $ worksheet ->getCell ($ coordinate )->setValueExplicit ('' , DataType::TYPE_NULL );
976
+ $ worksheet ->getCell ($ coordinate )->setXfIndex (0 );
977
+ }
978
+ }
979
+ }
980
+ }
981
+
982
+ private function adjustAutoFilter (Worksheet $ worksheet , string $ beforeCellAddress , int $ numberOfColumns , int $ numberOfRows ): void
983
+ {
984
+ $ autoFilter = $ worksheet ->getAutoFilter ();
985
+ $ autoFilterRange = $ autoFilter ->getRange ();
986
+ if (!empty ($ autoFilterRange )) {
987
+ if ($ numberOfColumns !== 0 ) {
988
+ $ autoFilterColumns = $ autoFilter ->getColumns ();
989
+ if (count ($ autoFilterColumns ) > 0 ) {
990
+ $ column = '' ;
991
+ $ row = 0 ;
992
+ sscanf ($ beforeCellAddress , '%[A-Z]%d ' , $ column , $ row );
993
+ $ columnIndex = Coordinate::columnIndexFromString ($ column );
994
+ [$ rangeStart , $ rangeEnd ] = Coordinate::rangeBoundaries ($ autoFilterRange );
995
+ if ($ columnIndex <= $ rangeEnd [0 ]) {
996
+ if ($ numberOfColumns < 0 ) {
997
+ $ this ->adjustAutoFilterDeleteRules ($ columnIndex , $ numberOfColumns , $ autoFilterColumns , $ autoFilter );
998
+ }
999
+ $ startCol = ($ columnIndex > $ rangeStart [0 ]) ? $ columnIndex : $ rangeStart [0 ];
1000
+
1001
+ // Shuffle columns in autofilter range
1002
+ if ($ numberOfColumns > 0 ) {
1003
+ $ this ->adjustAutoFilterInsert ($ startCol , $ numberOfColumns , $ rangeEnd [0 ], $ autoFilter );
1004
+ } else {
1005
+ $ this ->adjustAutoFilterDelete ($ startCol , $ numberOfColumns , $ rangeEnd [0 ], $ autoFilter );
1006
+ }
1007
+ }
1008
+ }
1009
+ }
1010
+
1011
+ $ worksheet ->setAutoFilter (
1012
+ $ this ->updateCellReference ($ autoFilterRange , $ beforeCellAddress , $ numberOfColumns , $ numberOfRows )
1013
+ );
1014
+ }
1015
+ }
1016
+
1017
+ private function adjustAutoFilterDeleteRules (int $ columnIndex , int $ numberOfColumns , array $ autoFilterColumns , AutoFilter $ autoFilter ): void
1018
+ {
1019
+ // If we're actually deleting any columns that fall within the autofilter range,
1020
+ // then we delete any rules for those columns
1021
+ $ deleteColumn = $ columnIndex + $ numberOfColumns - 1 ;
1022
+ $ deleteCount = abs ($ numberOfColumns );
1023
+
1024
+ for ($ i = 1 ; $ i <= $ deleteCount ; ++$ i ) {
1025
+ $ columnName = Coordinate::stringFromColumnIndex ($ deleteColumn + 1 );
1026
+ if (isset ($ autoFilterColumns [$ columnName ])) {
1027
+ $ autoFilter ->clearColumn ($ columnName );
1028
+ }
1029
+ ++$ deleteColumn ;
1030
+ }
1031
+ }
1032
+
1033
+ private function adjustAutoFilterInsert (int $ startCol , int $ numberOfColumns , int $ rangeEnd , AutoFilter $ autoFilter ): void
1034
+ {
1035
+ $ startColRef = $ startCol ;
1036
+ $ endColRef = $ rangeEnd ;
1037
+ $ toColRef = $ rangeEnd + $ numberOfColumns ;
1038
+
1039
+ do {
1040
+ $ autoFilter ->shiftColumn (Coordinate::stringFromColumnIndex ($ endColRef ), Coordinate::stringFromColumnIndex ($ toColRef ));
1041
+ --$ endColRef ;
1042
+ --$ toColRef ;
1043
+ } while ($ startColRef <= $ endColRef );
1044
+ }
1045
+
1046
+ private function adjustAutoFilterDelete (int $ startCol , int $ numberOfColumns , int $ rangeEnd , AutoFilter $ autoFilter ): void
1047
+ {
1048
+ // For delete, we shuffle from beginning to end to avoid overwriting
1049
+ $ startColID = Coordinate::stringFromColumnIndex ($ startCol );
1050
+ $ toColID = Coordinate::stringFromColumnIndex ($ startCol + $ numberOfColumns );
1051
+ $ endColID = Coordinate::stringFromColumnIndex ($ rangeEnd + 1 );
1052
+
1053
+ do {
1054
+ $ autoFilter ->shiftColumn ($ startColID , $ toColID );
1055
+ ++$ startColID ;
1056
+ ++$ toColID ;
1057
+ } while ($ startColID !== $ endColID );
1058
+ }
1059
+
1060
+ private function duplicateStylesByColumn (Worksheet $ worksheet , int $ beforeColumn , int $ beforeRow , int $ highestRow , int $ numberOfColumns ): void
1061
+ {
1062
+ $ beforeColumnName = Coordinate::stringFromColumnIndex ($ beforeColumn - 1 );
1063
+ for ($ i = $ beforeRow ; $ i <= $ highestRow - 1 ; ++$ i ) {
1064
+ // Style
1065
+ $ coordinate = $ beforeColumnName . $ i ;
1066
+ if ($ worksheet ->cellExists ($ coordinate )) {
1067
+ $ xfIndex = $ worksheet ->getCell ($ coordinate )->getXfIndex ();
1068
+ $ conditionalStyles = $ worksheet ->conditionalStylesExists ($ coordinate ) ?
1069
+ $ worksheet ->getConditionalStyles ($ coordinate ) : false ;
1070
+ for ($ j = $ beforeColumn ; $ j <= $ beforeColumn - 1 + $ numberOfColumns ; ++$ j ) {
1071
+ $ worksheet ->getCellByColumnAndRow ($ j , $ i )->setXfIndex ($ xfIndex );
1072
+ if ($ conditionalStyles ) {
1073
+ $ cloned = [];
1074
+ foreach ($ conditionalStyles as $ conditionalStyle ) {
1075
+ $ cloned [] = clone $ conditionalStyle ;
1076
+ }
1077
+ $ worksheet ->setConditionalStyles (Coordinate::stringFromColumnIndex ($ j ) . $ i , $ cloned );
1078
+ }
1079
+ }
1080
+ }
1081
+ }
1082
+ }
1083
+
1084
+ private function duplicateStylesByRow (Worksheet $ worksheet , int $ beforeColumn , int $ beforeRow , string $ highestColumn , int $ numberOfRows ): void
1085
+ {
1086
+ $ highestColumnIndex = Coordinate::columnIndexFromString ($ highestColumn );
1087
+ for ($ i = $ beforeColumn ; $ i <= $ highestColumnIndex ; ++$ i ) {
1088
+ // Style
1089
+ $ coordinate = Coordinate::stringFromColumnIndex ($ i ) . ($ beforeRow - 1 );
1090
+ if ($ worksheet ->cellExists ($ coordinate )) {
1091
+ $ xfIndex = $ worksheet ->getCell ($ coordinate )->getXfIndex ();
1092
+ $ conditionalStyles = $ worksheet ->conditionalStylesExists ($ coordinate ) ?
1093
+ $ worksheet ->getConditionalStyles ($ coordinate ) : false ;
1094
+ for ($ j = $ beforeRow ; $ j <= $ beforeRow - 1 + $ numberOfRows ; ++$ j ) {
1095
+ $ worksheet ->getCell (Coordinate::stringFromColumnIndex ($ i ) . $ j )->setXfIndex ($ xfIndex );
1096
+ if ($ conditionalStyles ) {
1097
+ $ cloned = [];
1098
+ foreach ($ conditionalStyles as $ conditionalStyle ) {
1099
+ $ cloned [] = clone $ conditionalStyle ;
1100
+ }
1101
+ $ worksheet ->setConditionalStyles (Coordinate::stringFromColumnIndex ($ i ) . $ j , $ cloned );
1102
+ }
1103
+ }
1104
+ }
1105
+ }
1106
+ }
1107
+
1051
1108
/**
1052
1109
* __clone implementation. Cloning should not be allowed in a Singleton!
1053
1110
*/
0 commit comments