24
24
use PhpOffice \PhpWord \ComplexType \TblWidth as TblWidthComplexType ;
25
25
use PhpOffice \PhpWord \Element \AbstractContainer ;
26
26
use PhpOffice \PhpWord \Element \AbstractElement ;
27
+ use PhpOffice \PhpWord \Element \FormField ;
27
28
use PhpOffice \PhpWord \Element \TextRun ;
28
29
use PhpOffice \PhpWord \Element \TrackChange ;
29
30
use PhpOffice \PhpWord \PhpWord ;
@@ -192,8 +193,44 @@ protected function readParagraph(XMLReader $xmlReader, DOMElement $domNode, $par
192
193
// Paragraph style
193
194
$ paragraphStyle = $ xmlReader ->elementExists ('w:pPr ' , $ domNode ) ? $ this ->readParagraphStyle ($ xmlReader , $ domNode ) : null ;
194
195
195
- // PreserveText
196
- if ($ xmlReader ->elementExists ('w:r/w:instrText ' , $ domNode )) {
196
+ if ($ xmlReader ->elementExists ('w:r/w:fldChar/w:ffData ' , $ domNode )) {
197
+ // FormField
198
+ $ partOfFormField = false ;
199
+ $ formNodes = [];
200
+ $ formType = null ;
201
+ $ textRunContainers = $ xmlReader ->countElements ('w:r|w:ins|w:del|w:hyperlink|w:smartTag ' , $ domNode );
202
+ if ($ textRunContainers > 0 ) {
203
+ $ nodes = $ xmlReader ->getElements ('* ' , $ domNode );
204
+ $ paragraph = $ parent ->addTextRun ($ paragraphStyle );
205
+ foreach ($ nodes as $ node ) {
206
+ if ($ xmlReader ->elementExists ('w:fldChar/w:ffData ' , $ node )) {
207
+ $ partOfFormField = true ;
208
+ $ formNodes [] = $ node ;
209
+ if ($ xmlReader ->elementExists ('w:fldChar/w:ffData/w:ddList ' , $ node )) {
210
+ $ formType = 'dropdown ' ;
211
+ } elseif ($ xmlReader ->elementExists ('w:fldChar/w:ffData/w:textInput ' , $ node )) {
212
+ $ formType = 'textinput ' ;
213
+ } elseif ($ xmlReader ->elementExists ('w:fldChar/w:ffData/w:checkBox ' , $ node )) {
214
+ $ formType = 'checkbox ' ;
215
+ }
216
+ } elseif ($ partOfFormField &&
217
+ $ xmlReader ->elementExists ('w:fldChar ' , $ node ) &&
218
+ 'end ' == $ xmlReader ->getAttribute ('w:fldCharType ' , $ node , 'w:fldChar ' )
219
+ ) {
220
+ $ formNodes [] = $ node ;
221
+ $ partOfFormField = false ;
222
+ // Process the form fields
223
+ $ this ->readFormField ($ xmlReader , $ formNodes , $ paragraph , $ paragraphStyle , $ formType );
224
+ } elseif ($ partOfFormField ) {
225
+ $ formNodes [] = $ node ;
226
+ } else {
227
+ // normal runs
228
+ $ this ->readRun ($ xmlReader , $ node , $ paragraph , $ docPart , $ paragraphStyle );
229
+ }
230
+ }
231
+ }
232
+ } elseif ($ xmlReader ->elementExists ('w:r/w:instrText ' , $ domNode )) {
233
+ // PreserveText
197
234
$ ignoreText = false ;
198
235
$ textContent = '' ;
199
236
$ fontStyle = $ this ->readFontStyle ($ xmlReader , $ domNode );
@@ -272,7 +309,7 @@ protected function readParagraph(XMLReader $xmlReader, DOMElement $domNode, $par
272
309
// Text and TextRun
273
310
$ textRunContainers = $ xmlReader ->countElements ('w:r|w:ins|w:del|w:hyperlink|w:smartTag|w:commentReference|w:commentRangeStart|w:commentRangeEnd ' , $ domNode );
274
311
if (0 === $ textRunContainers ) {
275
- $ parent ->addTextBreak (null , $ paragraphStyle );
312
+ $ parent ->addTextBreak (1 , $ paragraphStyle );
276
313
} else {
277
314
$ nodes = $ xmlReader ->getElements ('* ' , $ domNode );
278
315
$ paragraph = $ parent ->addTextRun ($ paragraphStyle );
@@ -282,6 +319,109 @@ protected function readParagraph(XMLReader $xmlReader, DOMElement $domNode, $par
282
319
}
283
320
}
284
321
322
+ /**
323
+ * @param DOMElement[] $domNodes
324
+ * @param AbstractContainer $parent
325
+ * @param mixed $paragraphStyle
326
+ * @param string $formType
327
+ */
328
+ private function readFormField (XMLReader $ xmlReader , array $ domNodes , $ parent , $ paragraphStyle , $ formType ): void
329
+ {
330
+ if (!in_array ($ formType , ['textinput ' , 'checkbox ' , 'dropdown ' ])) {
331
+ return ;
332
+ }
333
+
334
+ $ formField = $ parent ->addFormField ($ formType , null , $ paragraphStyle );
335
+ $ ffData = $ xmlReader ->getElement ('w:fldChar/w:ffData ' , $ domNodes [0 ]);
336
+
337
+ foreach ($ xmlReader ->getElements ('* ' , $ ffData ) as $ node ) {
338
+ /** @var DOMElement $node */
339
+ switch ($ node ->localName ) {
340
+ case 'name ' :
341
+ $ formField ->setName ($ node ->getAttribute ('w:val ' ));
342
+
343
+ break ;
344
+ case 'ddList ' :
345
+ $ listEntries = [];
346
+ foreach ($ xmlReader ->getElements ('* ' , $ node ) as $ ddListNode ) {
347
+ switch ($ ddListNode ->localName ) {
348
+ case 'result ' :
349
+ $ formField ->setValue ($ xmlReader ->getAttribute ('w:val ' , $ ddListNode ));
350
+
351
+ break ;
352
+ case 'default ' :
353
+ $ formField ->setDefault ($ xmlReader ->getAttribute ('w:val ' , $ ddListNode ));
354
+
355
+ break ;
356
+ case 'listEntry ' :
357
+ $ listEntries [] = $ xmlReader ->getAttribute ('w:val ' , $ ddListNode );
358
+
359
+ break ;
360
+ }
361
+ }
362
+ $ formField ->setEntries ($ listEntries );
363
+ if (null !== $ formField ->getValue ()) {
364
+ $ formField ->setText ($ listEntries [$ formField ->getValue ()]);
365
+ }
366
+
367
+ break ;
368
+ case 'textInput ' :
369
+ foreach ($ xmlReader ->getElements ('* ' , $ node ) as $ ddListNode ) {
370
+ switch ($ ddListNode ->localName ) {
371
+ case 'default ' :
372
+ $ formField ->setDefault ($ xmlReader ->getAttribute ('w:val ' , $ ddListNode ));
373
+
374
+ break ;
375
+ case 'format ' :
376
+ case 'maxLength ' :
377
+ break ;
378
+ }
379
+ }
380
+
381
+ break ;
382
+ case 'checkBox ' :
383
+ foreach ($ xmlReader ->getElements ('* ' , $ node ) as $ ddListNode ) {
384
+ switch ($ ddListNode ->localName ) {
385
+ case 'default ' :
386
+ $ formField ->setDefault ($ xmlReader ->getAttribute ('w:val ' , $ ddListNode ));
387
+
388
+ break ;
389
+ case 'checked ' :
390
+ $ formField ->setValue ($ xmlReader ->getAttribute ('w:val ' , $ ddListNode ));
391
+
392
+ break ;
393
+ case 'size ' :
394
+ case 'sizeAuto ' :
395
+ break ;
396
+ }
397
+ }
398
+
399
+ break ;
400
+ }
401
+ }
402
+
403
+ if ('textinput ' == $ formType ) {
404
+ $ ignoreText = true ;
405
+ $ textContent = '' ;
406
+ foreach ($ domNodes as $ node ) {
407
+ if ($ xmlReader ->elementExists ('w:fldChar ' , $ node )) {
408
+ $ fldCharType = $ xmlReader ->getAttribute ('w:fldCharType ' , $ node , 'w:fldChar ' );
409
+ if ('separate ' == $ fldCharType ) {
410
+ $ ignoreText = false ;
411
+ } elseif ('end ' == $ fldCharType ) {
412
+ $ ignoreText = true ;
413
+ }
414
+ }
415
+
416
+ if (false === $ ignoreText ) {
417
+ $ textContent .= $ xmlReader ->getValue ('w:t ' , $ node );
418
+ }
419
+ }
420
+ $ formField ->setValue (htmlspecialchars ($ textContent , ENT_QUOTES , 'UTF-8 ' ));
421
+ $ formField ->setText (htmlspecialchars ($ textContent , ENT_QUOTES , 'UTF-8 ' ));
422
+ }
423
+ }
424
+
285
425
/**
286
426
* Returns the depth of the Heading, returns 0 for a Title.
287
427
*
0 commit comments