@@ -759,6 +759,70 @@ public function cloneRow($search, $numberOfClones): void
759
759
$ this ->tempDocumentMainPart = $ result ;
760
760
}
761
761
762
+ /**
763
+ * Delete a table row in a template document.
764
+ */
765
+ public function deleteRow (string $ search ): void
766
+ {
767
+ if ('${ ' !== substr ($ search , 0 , 2 ) && '} ' !== substr ($ search , -1 )) {
768
+ $ search = '${ ' . $ search . '} ' ;
769
+ }
770
+
771
+ $ tagPos = strpos ($ this ->tempDocumentMainPart , $ search );
772
+ if (!$ tagPos ) {
773
+ throw new Exception (sprintf ('Can not delete row %s, template variable not found or variable contains markup. ' , $ search ));
774
+ }
775
+
776
+ $ tableStart = $ this ->findTableStart ($ tagPos );
777
+ $ tableEnd = $ this ->findTableEnd ($ tagPos );
778
+ $ xmlTable = $ this ->getSlice ($ tableStart , $ tableEnd );
779
+
780
+ if (substr_count ($ xmlTable , '<w:tr ' ) === 1 ) {
781
+ $ this ->tempDocumentMainPart = $ this ->getSlice (0 , $ tableStart ) . $ this ->getSlice ($ tableEnd );
782
+
783
+ return ;
784
+ }
785
+
786
+ $ rowStart = $ this ->findRowStart ($ tagPos );
787
+ $ rowEnd = $ this ->findRowEnd ($ tagPos );
788
+ $ xmlRow = $ this ->getSlice ($ rowStart , $ rowEnd );
789
+
790
+ $ this ->tempDocumentMainPart = $ this ->getSlice (0 , $ rowStart ) . $ this ->getSlice ($ rowEnd );
791
+
792
+ // Check if there's a cell spanning multiple rows.
793
+ if (preg_match ('#<w:vMerge w:val="restart"/># ' , $ xmlRow )) {
794
+ $ extraRowStart = $ rowStart ;
795
+ while (true ) {
796
+ $ extraRowStart = $ this ->findRowStart ($ extraRowStart + 1 );
797
+ $ extraRowEnd = $ this ->findRowEnd ($ extraRowStart + 1 );
798
+
799
+ // If extraRowEnd is lower then 7, there was no next row found.
800
+ if ($ extraRowEnd < 7 ) {
801
+ break ;
802
+ }
803
+
804
+ // If tmpXmlRow doesn't contain continue, this row is no longer part of the spanned row.
805
+ $ tmpXmlRow = $ this ->getSlice ($ extraRowStart , $ extraRowEnd );
806
+ if (!preg_match ('#<w:vMerge/># ' , $ tmpXmlRow ) &&
807
+ !preg_match ('#<w:vMerge w:val="continue" /># ' , $ tmpXmlRow )
808
+ ) {
809
+ break ;
810
+ }
811
+
812
+ $ tableStart = $ this ->findTableStart ($ extraRowEnd + 1 );
813
+ $ tableEnd = $ this ->findTableEnd ($ extraRowEnd + 1 );
814
+ $ xmlTable = $ this ->getSlice ($ tableStart , $ tableEnd );
815
+ if (substr_count ($ xmlTable , '<w:tr ' ) === 1 ) {
816
+ $ this ->tempDocumentMainPart = $ this ->getSlice (0 , $ tableStart ) . $ this ->getSlice ($ tableEnd );
817
+
818
+ return ;
819
+ }
820
+
821
+ $ this ->tempDocumentMainPart = $ this ->getSlice (0 , $ extraRowStart ) . $ this ->getSlice ($ extraRowEnd );
822
+ }
823
+ }
824
+ }
825
+
762
826
/**
763
827
* Clones a table row and populates it's values from a two-dimensional array in a template document.
764
828
*
@@ -1079,6 +1143,39 @@ protected function getDocumentContentTypesName()
1079
1143
return '[Content_Types].xml ' ;
1080
1144
}
1081
1145
1146
+ /**
1147
+ * Find the start position of the nearest table before $offset.
1148
+ */
1149
+ protected function findTableStart (int $ offset ): int
1150
+ {
1151
+ $ rowStart = strrpos (
1152
+ $ this ->tempDocumentMainPart ,
1153
+ '<w:tbl ' ,
1154
+ ((strlen ($ this ->tempDocumentMainPart ) - $ offset ) * -1 )
1155
+ );
1156
+
1157
+ if (!$ rowStart ) {
1158
+ $ rowStart = strrpos (
1159
+ $ this ->tempDocumentMainPart ,
1160
+ '<w:tbl> ' ,
1161
+ ((strlen ($ this ->tempDocumentMainPart ) - $ offset ) * -1 )
1162
+ );
1163
+ }
1164
+ if (!$ rowStart ) {
1165
+ throw new Exception ('Can not find the start position of the table. ' );
1166
+ }
1167
+
1168
+ return $ rowStart ;
1169
+ }
1170
+
1171
+ /**
1172
+ * Find the end position of the nearest table row after $offset.
1173
+ */
1174
+ protected function findTableEnd (int $ offset ): int
1175
+ {
1176
+ return strpos ($ this ->tempDocumentMainPart , '</w:tbl> ' , $ offset ) + 7 ;
1177
+ }
1178
+
1082
1179
/**
1083
1180
* Find the start position of the nearest table row before $offset.
1084
1181
*
0 commit comments