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
@@ -466,47 +453,11 @@ function ($coordinate) use ($allCoordinates) {
466
453
$ highestRow = $ worksheet ->getHighestRow ();
467
454
468
455
if ($ numberOfColumns > 0 && $ beforeColumn - 2 > 0 ) {
469
- for ($ i = $ beforeRow ; $ i <= $ highestRow - 1 ; ++$ i ) {
470
- // Style
471
- $ coordinate = Coordinate::stringFromColumnIndex ($ beforeColumn - 1 ) . $ i ;
472
- if ($ worksheet ->cellExists ($ coordinate )) {
473
- $ xfIndex = $ worksheet ->getCell ($ coordinate )->getXfIndex ();
474
- $ conditionalStyles = $ worksheet ->conditionalStylesExists ($ coordinate ) ?
475
- $ worksheet ->getConditionalStyles ($ coordinate ) : false ;
476
- for ($ j = $ beforeColumn ; $ j <= $ beforeColumn - 1 + $ numberOfColumns ; ++$ j ) {
477
- $ worksheet ->getCellByColumnAndRow ($ j , $ i )->setXfIndex ($ xfIndex );
478
- if ($ conditionalStyles ) {
479
- $ cloned = [];
480
- foreach ($ conditionalStyles as $ conditionalStyle ) {
481
- $ cloned [] = clone $ conditionalStyle ;
482
- }
483
- $ worksheet ->setConditionalStyles (Coordinate::stringFromColumnIndex ($ j ) . $ i , $ cloned );
484
- }
485
- }
486
- }
487
- }
456
+ $ this ->duplicateStylesByColumn ($ worksheet , $ beforeColumn , $ beforeRow , $ highestRow , $ numberOfColumns );
488
457
}
489
458
490
459
if ($ numberOfRows > 0 && $ beforeRow - 1 > 0 ) {
491
- for ($ i = $ beforeColumn ; $ i <= Coordinate::columnIndexFromString ($ highestColumn ); ++$ i ) {
492
- // Style
493
- $ coordinate = Coordinate::stringFromColumnIndex ($ i ) . ($ beforeRow - 1 );
494
- if ($ worksheet ->cellExists ($ coordinate )) {
495
- $ xfIndex = $ worksheet ->getCell ($ coordinate )->getXfIndex ();
496
- $ conditionalStyles = $ worksheet ->conditionalStylesExists ($ coordinate ) ?
497
- $ worksheet ->getConditionalStyles ($ coordinate ) : false ;
498
- for ($ j = $ beforeRow ; $ j <= $ beforeRow - 1 + $ numberOfRows ; ++$ j ) {
499
- $ worksheet ->getCell (Coordinate::stringFromColumnIndex ($ i ) . $ j )->setXfIndex ($ xfIndex );
500
- if ($ conditionalStyles ) {
501
- $ cloned = [];
502
- foreach ($ conditionalStyles as $ conditionalStyle ) {
503
- $ cloned [] = clone $ conditionalStyle ;
504
- }
505
- $ worksheet ->setConditionalStyles (Coordinate::stringFromColumnIndex ($ i ) . $ j , $ cloned );
506
- }
507
- }
508
- }
509
- }
460
+ $ this ->duplicateStylesByRow ($ worksheet , $ beforeColumn , $ beforeRow , $ highestColumn , $ numberOfRows );
510
461
}
511
462
512
463
// Update worksheet: column dimensions
@@ -534,59 +485,7 @@ function ($coordinate) use ($allCoordinates) {
534
485
$ this ->adjustProtectedCells ($ worksheet , $ beforeCellAddress , $ numberOfColumns , $ numberOfRows );
535
486
536
487
// Update worksheet: autofilter
537
- $ autoFilter = $ worksheet ->getAutoFilter ();
538
- $ autoFilterRange = $ autoFilter ->getRange ();
539
- if (!empty ($ autoFilterRange )) {
540
- if ($ numberOfColumns != 0 ) {
541
- $ autoFilterColumns = $ autoFilter ->getColumns ();
542
- if (count ($ autoFilterColumns ) > 0 ) {
543
- $ column = '' ;
544
- $ row = 0 ;
545
- sscanf ($ beforeCellAddress , '%[A-Z]%d ' , $ column , $ row );
546
- $ columnIndex = Coordinate::columnIndexFromString ($ column );
547
- [$ rangeStart , $ rangeEnd ] = Coordinate::rangeBoundaries ($ autoFilterRange );
548
- if ($ columnIndex <= $ rangeEnd [0 ]) {
549
- if ($ numberOfColumns < 0 ) {
550
- // If we're actually deleting any columns that fall within the autofilter range,
551
- // then we delete any rules for those columns
552
- $ deleteColumn = $ columnIndex + $ numberOfColumns - 1 ;
553
- $ deleteCount = abs ($ numberOfColumns );
554
- for ($ i = 1 ; $ i <= $ deleteCount ; ++$ i ) {
555
- if (isset ($ autoFilterColumns [Coordinate::stringFromColumnIndex ($ deleteColumn + 1 )])) {
556
- $ autoFilter ->clearColumn (Coordinate::stringFromColumnIndex ($ deleteColumn + 1 ));
557
- }
558
- ++$ deleteColumn ;
559
- }
560
- }
561
- $ startCol = ($ columnIndex > $ rangeStart [0 ]) ? $ columnIndex : $ rangeStart [0 ];
562
-
563
- // Shuffle columns in autofilter range
564
- if ($ numberOfColumns > 0 ) {
565
- $ startColRef = $ startCol ;
566
- $ endColRef = $ rangeEnd [0 ];
567
- $ toColRef = $ rangeEnd [0 ] + $ numberOfColumns ;
568
-
569
- do {
570
- $ autoFilter ->shiftColumn (Coordinate::stringFromColumnIndex ($ endColRef ), Coordinate::stringFromColumnIndex ($ toColRef ));
571
- --$ endColRef ;
572
- --$ toColRef ;
573
- } while ($ startColRef <= $ endColRef );
574
- } else {
575
- // For delete, we shuffle from beginning to end to avoid overwriting
576
- $ startColID = Coordinate::stringFromColumnIndex ($ startCol );
577
- $ toColID = Coordinate::stringFromColumnIndex ($ startCol + $ numberOfColumns );
578
- $ endColID = Coordinate::stringFromColumnIndex ($ rangeEnd [0 ] + 1 );
579
- do {
580
- $ autoFilter ->shiftColumn ($ startColID , $ toColID );
581
- ++$ startColID ;
582
- ++$ toColID ;
583
- } while ($ startColID != $ endColID );
584
- }
585
- }
586
- }
587
- }
588
- $ worksheet ->setAutoFilter ($ this ->updateCellReference ($ autoFilterRange , $ beforeCellAddress , $ numberOfColumns , $ numberOfRows ));
589
- }
488
+ $ this ->adjustAutoFilter ($ worksheet , $ beforeCellAddress , $ numberOfColumns , $ numberOfRows );
590
489
591
490
// Update worksheet: freeze pane
592
491
if ($ worksheet ->getFreezePane ()) {
@@ -601,7 +500,9 @@ function ($coordinate) use ($allCoordinates) {
601
500
602
501
// Page setup
603
502
if ($ worksheet ->getPageSetup ()->isPrintAreaSet ()) {
604
- $ worksheet ->getPageSetup ()->setPrintArea ($ this ->updateCellReference ($ worksheet ->getPageSetup ()->getPrintArea (), $ beforeCellAddress , $ numberOfColumns , $ numberOfRows ));
503
+ $ worksheet ->getPageSetup ()->setPrintArea (
504
+ $ this ->updateCellReference ($ worksheet ->getPageSetup ()->getPrintArea (), $ beforeCellAddress , $ numberOfColumns , $ numberOfRows )
505
+ );
605
506
}
606
507
607
508
// Update worksheet: drawings
@@ -948,7 +849,7 @@ public function updateNamedFormulas(Spreadsheet $spreadsheet, $oldName = '', $ne
948
849
foreach ($ spreadsheet ->getWorksheetIterator () as $ sheet ) {
949
850
foreach ($ sheet ->getCoordinates (false ) as $ coordinate ) {
950
851
$ cell = $ sheet ->getCell ($ coordinate );
951
- if (($ cell !== null ) && ($ cell ->getDataType () == DataType::TYPE_FORMULA )) {
852
+ if (($ cell !== null ) && ($ cell ->getDataType () === DataType::TYPE_FORMULA )) {
952
853
$ formula = $ cell ->getValue ();
953
854
if (strpos ($ formula , $ oldName ) !== false ) {
954
855
$ formula = str_replace ("' " . $ oldName . "'! " , "' " . $ newName . "'! " , $ formula );
@@ -1038,6 +939,162 @@ private function updateSingleCellReference($cellReference = 'A1', $beforeCellAdd
1038
939
return $ newColumn . $ newRow ;
1039
940
}
1040
941
942
+ private function clearColumnStrips (int $ highestRow , int $ beforeColumn , int $ numberOfColumns , Worksheet $ worksheet ): void
943
+ {
944
+ for ($ i = 1 ; $ i <= $ highestRow - 1 ; ++$ i ) {
945
+ for ($ j = $ beforeColumn - 1 + $ numberOfColumns ; $ j <= $ beforeColumn - 2 ; ++$ j ) {
946
+ $ coordinate = Coordinate::stringFromColumnIndex ($ j + 1 ) . $ i ;
947
+ $ worksheet ->removeConditionalStyles ($ coordinate );
948
+ if ($ worksheet ->cellExists ($ coordinate )) {
949
+ $ worksheet ->getCell ($ coordinate )->setValueExplicit ('' , DataType::TYPE_NULL );
950
+ $ worksheet ->getCell ($ coordinate )->setXfIndex (0 );
951
+ }
952
+ }
953
+ }
954
+ }
955
+
956
+ private function clearRowStrips (string $ highestColumn , int $ beforeColumn , int $ beforeRow , int $ numberOfRows , Worksheet $ worksheet ): void
957
+ {
958
+ $ lastColumnIndex = Coordinate::columnIndexFromString ($ highestColumn ) - 1 ;
959
+
960
+ for ($ i = $ beforeColumn - 1 ; $ i <= $ lastColumnIndex ; ++$ i ) {
961
+ for ($ j = $ beforeRow + $ numberOfRows ; $ j <= $ beforeRow - 1 ; ++$ j ) {
962
+ $ coordinate = Coordinate::stringFromColumnIndex ($ i + 1 ) . $ j ;
963
+ $ worksheet ->removeConditionalStyles ($ coordinate );
964
+ if ($ worksheet ->cellExists ($ coordinate )) {
965
+ $ worksheet ->getCell ($ coordinate )->setValueExplicit ('' , DataType::TYPE_NULL );
966
+ $ worksheet ->getCell ($ coordinate )->setXfIndex (0 );
967
+ }
968
+ }
969
+ }
970
+ }
971
+
972
+ private function adjustAutoFilter (Worksheet $ worksheet , string $ beforeCellAddress , int $ numberOfColumns , int $ numberOfRows ): void
973
+ {
974
+ $ autoFilter = $ worksheet ->getAutoFilter ();
975
+ $ autoFilterRange = $ autoFilter ->getRange ();
976
+ if (!empty ($ autoFilterRange )) {
977
+ if ($ numberOfColumns !== 0 ) {
978
+ $ autoFilterColumns = $ autoFilter ->getColumns ();
979
+ if (count ($ autoFilterColumns ) > 0 ) {
980
+ $ column = '' ;
981
+ $ row = 0 ;
982
+ sscanf ($ beforeCellAddress , '%[A-Z]%d ' , $ column , $ row );
983
+ $ columnIndex = Coordinate::columnIndexFromString ($ column );
984
+ [$ rangeStart , $ rangeEnd ] = Coordinate::rangeBoundaries ($ autoFilterRange );
985
+ if ($ columnIndex <= $ rangeEnd [0 ]) {
986
+ if ($ numberOfColumns < 0 ) {
987
+ $ this ->adjustAutoFilterDeleteRules ($ columnIndex , $ numberOfColumns , $ autoFilterColumns , $ autoFilter );
988
+ }
989
+ $ startCol = ($ columnIndex > $ rangeStart [0 ]) ? $ columnIndex : $ rangeStart [0 ];
990
+
991
+ // Shuffle columns in autofilter range
992
+ if ($ numberOfColumns > 0 ) {
993
+ $ this ->adjustAutoFilterInsert ($ startCol , $ numberOfColumns , $ rangeEnd [0 ], $ autoFilter );
994
+ } else {
995
+ $ this ->adjustAutoFilterDelete ($ startCol , $ numberOfColumns , $ rangeEnd [0 ], $ autoFilter );
996
+ }
997
+ }
998
+ }
999
+ }
1000
+
1001
+ $ worksheet ->setAutoFilter (
1002
+ $ this ->updateCellReference ($ autoFilterRange , $ beforeCellAddress , $ numberOfColumns , $ numberOfRows )
1003
+ );
1004
+ }
1005
+ }
1006
+
1007
+ private function adjustAutoFilterDeleteRules (int $ columnIndex , int $ numberOfColumns , array $ autoFilterColumns , AutoFilter $ autoFilter ): void
1008
+ {
1009
+ // If we're actually deleting any columns that fall within the autofilter range,
1010
+ // then we delete any rules for those columns
1011
+ $ deleteColumn = $ columnIndex + $ numberOfColumns - 1 ;
1012
+ $ deleteCount = abs ($ numberOfColumns );
1013
+
1014
+ for ($ i = 1 ; $ i <= $ deleteCount ; ++$ i ) {
1015
+ $ columnName = Coordinate::stringFromColumnIndex ($ deleteColumn + 1 );
1016
+ if (isset ($ autoFilterColumns [$ columnName ])) {
1017
+ $ autoFilter ->clearColumn ($ columnName );
1018
+ }
1019
+ ++$ deleteColumn ;
1020
+ }
1021
+ }
1022
+
1023
+ private function adjustAutoFilterInsert (int $ startCol , int $ numberOfColumns , int $ rangeEnd , AutoFilter $ autoFilter ): void
1024
+ {
1025
+ $ startColRef = $ startCol ;
1026
+ $ endColRef = $ rangeEnd ;
1027
+ $ toColRef = $ rangeEnd + $ numberOfColumns ;
1028
+
1029
+ do {
1030
+ $ autoFilter ->shiftColumn (Coordinate::stringFromColumnIndex ($ endColRef ), Coordinate::stringFromColumnIndex ($ toColRef ));
1031
+ --$ endColRef ;
1032
+ --$ toColRef ;
1033
+ } while ($ startColRef <= $ endColRef );
1034
+ }
1035
+
1036
+ private function adjustAutoFilterDelete (int $ startCol , int $ numberOfColumns , int $ rangeEnd , AutoFilter $ autoFilter ): void
1037
+ {
1038
+ // For delete, we shuffle from beginning to end to avoid overwriting
1039
+ $ startColID = Coordinate::stringFromColumnIndex ($ startCol );
1040
+ $ toColID = Coordinate::stringFromColumnIndex ($ startCol + $ numberOfColumns );
1041
+ $ endColID = Coordinate::stringFromColumnIndex ($ rangeEnd + 1 );
1042
+
1043
+ do {
1044
+ $ autoFilter ->shiftColumn ($ startColID , $ toColID );
1045
+ ++$ startColID ;
1046
+ ++$ toColID ;
1047
+ } while ($ startColID !== $ endColID );
1048
+ }
1049
+
1050
+ private function duplicateStylesByColumn (Worksheet $ worksheet , int $ beforeColumn , int $ beforeRow , int $ highestRow , int $ numberOfColumns ): void
1051
+ {
1052
+ $ beforeColumnName = Coordinate::stringFromColumnIndex ($ beforeColumn - 1 );
1053
+ for ($ i = $ beforeRow ; $ i <= $ highestRow - 1 ; ++$ i ) {
1054
+ // Style
1055
+ $ coordinate = $ beforeColumnName . $ i ;
1056
+ if ($ worksheet ->cellExists ($ coordinate )) {
1057
+ $ xfIndex = $ worksheet ->getCell ($ coordinate )->getXfIndex ();
1058
+ $ conditionalStyles = $ worksheet ->conditionalStylesExists ($ coordinate ) ?
1059
+ $ worksheet ->getConditionalStyles ($ coordinate ) : false ;
1060
+ for ($ j = $ beforeColumn ; $ j <= $ beforeColumn - 1 + $ numberOfColumns ; ++$ j ) {
1061
+ $ worksheet ->getCellByColumnAndRow ($ j , $ i )->setXfIndex ($ xfIndex );
1062
+ if ($ conditionalStyles ) {
1063
+ $ cloned = [];
1064
+ foreach ($ conditionalStyles as $ conditionalStyle ) {
1065
+ $ cloned [] = clone $ conditionalStyle ;
1066
+ }
1067
+ $ worksheet ->setConditionalStyles (Coordinate::stringFromColumnIndex ($ j ) . $ i , $ cloned );
1068
+ }
1069
+ }
1070
+ }
1071
+ }
1072
+ }
1073
+
1074
+ private function duplicateStylesByRow (Worksheet $ worksheet , int $ beforeColumn , int $ beforeRow , string $ highestColumn , int $ numberOfRows ): void
1075
+ {
1076
+ $ highestColumnIndex = Coordinate::columnIndexFromString ($ highestColumn );
1077
+ for ($ i = $ beforeColumn ; $ i <= $ highestColumnIndex ; ++$ i ) {
1078
+ // Style
1079
+ $ coordinate = Coordinate::stringFromColumnIndex ($ i ) . ($ beforeRow - 1 );
1080
+ if ($ worksheet ->cellExists ($ coordinate )) {
1081
+ $ xfIndex = $ worksheet ->getCell ($ coordinate )->getXfIndex ();
1082
+ $ conditionalStyles = $ worksheet ->conditionalStylesExists ($ coordinate ) ?
1083
+ $ worksheet ->getConditionalStyles ($ coordinate ) : false ;
1084
+ for ($ j = $ beforeRow ; $ j <= $ beforeRow - 1 + $ numberOfRows ; ++$ j ) {
1085
+ $ worksheet ->getCell (Coordinate::stringFromColumnIndex ($ i ) . $ j )->setXfIndex ($ xfIndex );
1086
+ if ($ conditionalStyles ) {
1087
+ $ cloned = [];
1088
+ foreach ($ conditionalStyles as $ conditionalStyle ) {
1089
+ $ cloned [] = clone $ conditionalStyle ;
1090
+ }
1091
+ $ worksheet ->setConditionalStyles (Coordinate::stringFromColumnIndex ($ i ) . $ j , $ cloned );
1092
+ }
1093
+ }
1094
+ }
1095
+ }
1096
+ }
1097
+
1041
1098
/**
1042
1099
* __clone implementation. Cloning should not be allowed in a Singleton!
1043
1100
*/
0 commit comments