@@ -121,35 +121,90 @@ public function getVariables()
121
121
preg_match_all ('/\$\{(.*?)}/i ' , $ this ->_documentXML , $ matches );
122
122
return $ matches [1 ];
123
123
}
124
-
124
+
125
+ /**
126
+ * Find the start position of the nearest table row before $offset
127
+ *
128
+ * @param mixed $offset
129
+ */
130
+ private function _findRowStart ($ offset ) {
131
+ return strrpos ($ this ->_documentXML , "<w:tr " , ((strlen ($ this ->_documentXML ) - $ offset ) * -1 ));
132
+ }
133
+
134
+ /**
135
+ * Find the end position of the nearest table row after $offset
136
+ *
137
+ * @param mixed $offset
138
+ */
139
+ private function _findRowEnd ($ offset ) {
140
+ return strpos ($ this ->_documentXML , "</w:tr> " , $ offset ) + 7 ;
141
+ }
142
+
143
+ /**
144
+ * Get a slice of a string
145
+ *
146
+ * @param mixed $offset
147
+ */
148
+ private function _getSlice ($ startPosition , $ endPosition = 0 ) {
149
+ if (!$ endPosition ) {
150
+ $ endPosition = strlen ($ this ->_documentXML );
151
+ }
152
+ return substr ($ this ->_documentXML , $ startPosition , ($ endPosition - $ startPosition ));
153
+ }
154
+
125
155
/**
126
156
* Clone a table row in a template document
127
157
*
128
158
* @param mixed $search
129
159
* @param mixed $numberOfClones
130
160
*/
131
- public function cloneRow ($ search , $ numberOfClones ) {
161
+ public function cloneRow ($ search , $ numberOfClones ) {
132
162
if (substr ($ search , 0 , 2 ) !== '${ ' && substr ($ search , -1 ) !== '} ' ) {
133
163
$ search = '${ ' .$ search .'} ' ;
134
164
}
135
165
136
- $ tagPos = strpos ($ this ->_documentXML , $ search );
166
+ $ tagPos = strpos ($ this ->_documentXML , $ search );
137
167
if (!$ tagPos ) {
138
168
trigger_error ("Can not clone row, template variable not found or variable contains markup. " );
139
169
return false ;
140
170
}
141
- $ rowStartPos = strrpos ($ this ->_documentXML , "<w:tr " , ((strlen ($ this ->_documentXML ) - $ tagPos ) * -1 ));
142
- $ rowEndPos = strpos ($ this ->_documentXML , "</w:tr> " , $ tagPos ) + 7 ;
143
-
144
- $ result = substr ($ this ->_documentXML , 0 , $ rowStartPos );
145
- $ xmlRow = substr ($ this ->_documentXML , $ rowStartPos , ($ rowEndPos - $ rowStartPos ));
171
+
172
+ $ rowStart = $ this ->_findRowStart ($ tagPos );
173
+ $ rowEnd = $ this ->_findRowEnd ($ tagPos );
174
+ $ xmlRow = $ this ->_getSlice ($ rowStart , $ rowEnd );
175
+
176
+ // Check if there's a cell spanning multiple rows.
177
+ if (preg_match ('#<w:vMerge w:val="restart"/># ' , $ xmlRow )) {
178
+ $ extraRowStart = $ rowEnd ;
179
+ $ extraRowEnd = $ rowEnd ;
180
+ while (true ) {
181
+ $ extraRowStart = $ this ->_findRowStart ($ extraRowEnd + 1 );
182
+ $ extraRowEnd = $ this ->_findRowEnd ($ extraRowEnd + 1 );
183
+
184
+ // If extraRowEnd is lower then 7, there was no next row found.
185
+ if ($ extraRowEnd < 7 ) {
186
+ break ;
187
+ }
188
+
189
+ // If tmpXmlRow doesn't contain continue, this row is no longer part of the spanned row.
190
+ $ tmpXmlRow = $ this ->_getSlice ($ extraRowStart , $ extraRowEnd );
191
+ if (!preg_match ('#<w:vMerge/># ' , $ tmpXmlRow ) && !preg_match ('#<w:vMerge w:val="continue" /># ' , $ tmpXmlRow )) {
192
+ break ;
193
+ }
194
+ // This row was a spanned row, update $rowEnd and search for the next row.
195
+ $ rowEnd = $ extraRowEnd ;
196
+ }
197
+ $ xmlRow = $ this ->_getSlice ($ rowStart , $ rowEnd );
198
+ }
199
+
200
+ $ result = $ this ->_getSlice (0 , $ rowStart );
146
201
for ($ i = 1 ; $ i <= $ numberOfClones ; $ i ++) {
147
- $ result .= preg_replace ('/\$\{(.*?)\}/ ' ,'\${ \\1# ' .$ i .'} ' , $ xmlRow );
202
+ $ result .= preg_replace ('/\$\{(.*?)\}/ ' ,'\${ \\1# ' .$ i .'} ' , $ xmlRow );
148
203
}
149
- $ result .= substr ( $ this ->_documentXML , $ rowEndPos );
150
-
204
+ $ result .= $ this ->_getSlice ( $ rowEnd );
205
+
151
206
$ this ->_documentXML = $ result ;
152
- }
207
+ }
153
208
154
209
/**
155
210
* Save Template
0 commit comments