@@ -152,6 +152,99 @@ public function getVariables()
152
152
return $ matches [1 ];
153
153
}
154
154
155
+ /**
156
+ * Find the start position of the nearest table row before $offset
157
+ *
158
+ * @param mixed $offset
159
+ */
160
+ private function _findRowStart ($ offset ) {
161
+ $ rowStart = strrpos ($ this ->_documentXML , "<w:tr " , ((strlen ($ this ->_documentXML ) - $ offset ) * -1 ));
162
+ if (!$ rowStart ) {
163
+ $ rowStart = strrpos ($ this ->_documentXML , "<w:tr> " , ((strlen ($ this ->_documentXML ) - $ offset ) * -1 ));
164
+ }
165
+ if (!$ rowStart ) {
166
+ trigger_error ("Can not find the start position of the row to clone. " );
167
+ return false ;
168
+ }
169
+ return $ rowStart ;
170
+ }
171
+
172
+ /**
173
+ * Find the end position of the nearest table row after $offset
174
+ *
175
+ * @param mixed $offset
176
+ */
177
+ private function _findRowEnd ($ offset ) {
178
+ $ rowEnd = strpos ($ this ->_documentXML , "</w:tr> " , $ offset ) + 7 ;
179
+ return $ rowEnd ;
180
+ }
181
+
182
+ /**
183
+ * Get a slice of a string
184
+ *
185
+ * @param mixed $offset
186
+ */
187
+ private function _getSlice ($ startPosition , $ endPosition = 0 ) {
188
+ if (!$ endPosition ) {
189
+ $ endPosition = strlen ($ this ->_documentXML );
190
+ }
191
+ return substr ($ this ->_documentXML , $ startPosition , ($ endPosition - $ startPosition ));
192
+ }
193
+
194
+ /**
195
+ * Clone a table row in a template document
196
+ *
197
+ * @param mixed $search
198
+ * @param mixed $numberOfClones
199
+ */
200
+ public function cloneRow ($ search , $ numberOfClones ) {
201
+ if (substr ($ search , 0 , 2 ) !== '${ ' && substr ($ search , -1 ) !== '} ' ) {
202
+ $ search = '${ ' .$ search .'} ' ;
203
+ }
204
+
205
+ $ tagPos = strpos ($ this ->_documentXML , $ search );
206
+ if (!$ tagPos ) {
207
+ trigger_error ("Can not clone row, template variable not found or variable contains markup. " );
208
+ return false ;
209
+ }
210
+
211
+ $ rowStart = $ this ->_findRowStart ($ tagPos );
212
+ $ rowEnd = $ this ->_findRowEnd ($ tagPos );
213
+ $ xmlRow = $ this ->_getSlice ($ rowStart , $ rowEnd );
214
+
215
+ // Check if there's a cell spanning multiple rows.
216
+ if (preg_match ('#<w:vMerge w:val="restart"/># ' , $ xmlRow )) {
217
+ $ extraRowStart = $ rowEnd ;
218
+ $ extraRowEnd = $ rowEnd ;
219
+ while (true ) {
220
+ $ extraRowStart = $ this ->_findRowStart ($ extraRowEnd + 1 );
221
+ $ extraRowEnd = $ this ->_findRowEnd ($ extraRowEnd + 1 );
222
+
223
+ // If extraRowEnd is lower then 7, there was no next row found.
224
+ if ($ extraRowEnd < 7 ) {
225
+ break ;
226
+ }
227
+
228
+ // If tmpXmlRow doesn't contain continue, this row is no longer part of the spanned row.
229
+ $ tmpXmlRow = $ this ->_getSlice ($ extraRowStart , $ extraRowEnd );
230
+ if (!preg_match ('#<w:vMerge/># ' , $ tmpXmlRow ) && !preg_match ('#<w:vMerge w:val="continue" /># ' , $ tmpXmlRow )) {
231
+ break ;
232
+ }
233
+ // This row was a spanned row, update $rowEnd and search for the next row.
234
+ $ rowEnd = $ extraRowEnd ;
235
+ }
236
+ $ xmlRow = $ this ->_getSlice ($ rowStart , $ rowEnd );
237
+ }
238
+
239
+ $ result = $ this ->_getSlice (0 , $ rowStart );
240
+ for ($ i = 1 ; $ i <= $ numberOfClones ; $ i ++) {
241
+ $ result .= preg_replace ('/\$\{(.*?)\}/ ' ,'\${ \\1# ' .$ i .'} ' , $ xmlRow );
242
+ }
243
+ $ result .= $ this ->_getSlice ($ rowEnd );
244
+
245
+ $ this ->_documentXML = $ result ;
246
+ }
247
+
155
248
/**
156
249
* Save Template
157
250
*
0 commit comments