Skip to content

Commit 2de4cfc

Browse files
authored
Merge branch 'master' into nounlink
2 parents 7e92c29 + 050e74e commit 2de4cfc

27 files changed

+716
-151
lines changed

composer.lock

+116-115
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/changes/1.x/1.2.0.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# [1.2.0](https://github.com/PHPOffice/PHPWord/tree/1.2.0) (WIP)
1+
# [1.2.0](https://github.com/PHPOffice/PHPWord/tree/1.2.0)
22

33
[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/1.1.0...1.2.0)
44

@@ -29,6 +29,9 @@
2929
- PDF Writer : Added support for PageBreak
3030
- PDF Writer : Added callback for modifying the HTML
3131
- Added Support for Language, both for document overall and individual text elements
32+
- Template : Set a checkbox by [@nxtpge](https://github.com/nxtpge) in [#2509](https://github.com/PHPOffice/PHPWord/pull/2509)
33+
- ODText / RTF / Word2007 Writer : Add field FILENAME by [@milkyway-git](https://github.com/milkyway-git) in [#2510](https://github.com/PHPOffice/PHPWord/pull/2510)
34+
- ODText Reader : Improve Section Reader by [@oleibman](https://github.com/oleibman) in [#2507](https://github.com/PHPOffice/PHPWord/pull/2507)
3235

3336
### Bug fixes
3437

@@ -39,6 +42,7 @@
3942
- Template Processor : Fixed choose dimention for Float Value by [@gdevilbat](https://github.com/gdevilbat) in GH-2449
4043
- HTML Parser : Fix image parsing from url without extension by [@JokubasR](https://github.com/JokubasR) in GH-2459
4144
- Word2007 Reader : Fixed reading of Office365 DocX file by [@filippotoso](https://github.com/filippotoso) & [@lfglopes](https://github.com/lfglopes) in [#2506](https://github.com/PHPOffice/PHPWord/pull/2506)
45+
- Word2007 Reader : Check for null on $fontDefaultStyle by [@spatialfree](https://github.com/spatialfree) in [#2513](https://github.com/PHPOffice/PHPWord/pull/2513)
4246

4347
### Miscellaneous
4448

docs/usage/elements/field.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Currently the following fields are supported:
77
- DATE
88
- XE
99
- INDEX
10+
- FILENAME
1011

1112
``` php
1213
<?php
@@ -36,4 +37,4 @@ $section->addField('XE', array(), array(), $fieldText);
3637

3738
//this actually adds the index
3839
$section->addField('INDEX', array(), array('\\e " " \\h "A" \\c "3"'), 'right click to update index');
39-
```
40+
```

docs/usage/template.md

+25
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,31 @@ You can also set multiple values by passing all of them in an array.
3838
$templateProcessor->setValues(array('firstname' => 'John', 'lastname' => 'Doe'));
3939
```
4040

41+
## setCheckbox
42+
43+
Given a template containing a checkbox control with the title or tag named:
44+
45+
``` clean
46+
${checkbox}
47+
```
48+
The following will check the checkbox:
49+
50+
``` php
51+
<?php
52+
53+
$templateProcessor->setCheckbox('checkbox', true);
54+
```
55+
56+
!!! note annotate "To add a checkbox and set its title or tag in a template"
57+
58+
1. Go to **Developer** tab > **Controls** group
59+
2. Select the **Check Box Content Control**
60+
3. Right-click on your checkbox
61+
4. Click on **Properties**
62+
5. Set the title or the tag
63+
64+
These steps may change regarding the version of Microsoft Word used.
65+
4166
## setMacroOpeningChars
4267

4368
You can define a custom opening macro. The following will set ``{#`` as the opening search pattern.

mkdocs.yml

+4-1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ nav:
5555
- Comment: 'usage/elements/comment.md'
5656
- Field: 'usage/elements/field.md'
5757
- Footnote & Endnote: 'usage/elements/note.md'
58+
- Formula: 'usage/elements/formula.md'
5859
- Image: 'usage/elements/image.md'
5960
- Line: 'usage/elements/line.md'
6061
- Link: 'usage/elements/link.md'
@@ -85,8 +86,10 @@ nav:
8586
- How to: 'howto.md'
8687
- Credits: 'credits.md'
8788
- Releases:
89+
- '2.x':
90+
- '2.0.0 (WIP)': 'changes/2.x/2.0.0.md'
8891
- '1.x':
89-
- '1.2.0 (WIP)': 'changes/1.x/1.2.0.md'
92+
- '1.2.0': 'changes/1.x/1.2.0.md'
9093
- '1.1.0': 'changes/1.x/1.1.0.md'
9194
- '1.0.0': 'changes/1.x/1.0.0.md'
9295
- '0.x':

phpstan-baseline.neon

-5
Original file line numberDiff line numberDiff line change
@@ -165,11 +165,6 @@ parameters:
165165
count: 1
166166
path: src/PhpWord/Reader/HTML.php
167167

168-
-
169-
message: "#^Call to an undefined method DOMNode\\:\\:getAttribute\\(\\)\\.$#"
170-
count: 2
171-
path: src/PhpWord/Reader/ODText/Content.php
172-
173168
-
174169
message: "#^Offset 'textNodes' on array\\{changed\\: PhpOffice\\\\PhpWord\\\\Element\\\\TrackChange, textNodes\\: DOMNodeList\\<DOMElement\\>\\} in isset\\(\\) always exists and is not nullable\\.$#"
175170
count: 1

samples/Sample_27_Field.php

+3
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@
2626

2727
$section->addText('Number of pages field:');
2828
$section->addField('NUMPAGES', ['numformat' => '0,00', 'format' => 'Arabic'], ['PreserveFormat']);
29+
30+
$section->addText('Filename field:');
31+
$section->addField('FILENAME', ['format' => 'Upper'], ['Path', 'PreserveFormat']);
2932
$section->addTextBreak();
3033

3134
$textrun = $section->addTextRun();
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
include_once 'Sample_Header.php';
4+
5+
use PhpOffice\PhpWord\TemplateProcessor;
6+
7+
// Template processor instance creation
8+
echo date('H:i:s'), ' Creating new TemplateProcessor instance...', EOL;
9+
$filename = 'Sample_42_TemplateSetCheckbox.docx';
10+
$templateProcessor = new TemplateProcessor(__DIR__ . "/resources/{$filename}");
11+
12+
$templateProcessor->setCheckbox('checkbox', true);
13+
$templateProcessor->setCheckbox('checkbox2', false);
14+
15+
echo date('H:i:s'), ' Saving the result document...', EOL;
16+
$templateProcessor->saveAs(__DIR__ . "/results/{$filename}");
17+
18+
echo getEndingNotes(['Word2007' => 'docx'], "results/{$filename}");
19+
if (!CLI) {
20+
include_once 'Sample_Footer.php';
21+
}
File renamed without changes.
Binary file not shown.

src/PhpWord/Element/Field.php

+6
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,12 @@ class Field extends AbstractElement
8585
'properties' => ['StyleIdentifier' => ''],
8686
'options' => ['PreserveFormat'],
8787
],
88+
'FILENAME' => [
89+
'properties' => [
90+
'format' => ['Upper', 'Lower', 'FirstCap', 'Caps'],
91+
],
92+
'options' => ['Path', 'PreserveFormat'],
93+
],
8894
];
8995

9096
/**

src/PhpWord/Element/TextRun.php

+12
Original file line numberDiff line numberDiff line change
@@ -78,4 +78,16 @@ public function setParagraphStyle($style = null)
7878

7979
return $this->paragraphStyle;
8080
}
81+
82+
public function getText(): string
83+
{
84+
$outstr = '';
85+
foreach ($this->getElements() as $element) {
86+
if ($element instanceof Text) {
87+
$outstr .= $element->getText();
88+
}
89+
}
90+
91+
return $outstr;
92+
}
8193
}

src/PhpWord/Reader/MsDoc.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -1871,7 +1871,7 @@ private function readPrl($data, $pos, $cbNum)
18711871
break;
18721872
// sprmCHps
18731873
case 0x43:
1874-
$oStylePrl->styleFont['size'] = dechex($operand / 2);
1874+
$oStylePrl->styleFont['size'] = $operand / 2;
18751875

18761876
break;
18771877
// sprmCIss

src/PhpWord/Reader/ODText/Content.php

+75-6
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@
1818
namespace PhpOffice\PhpWord\Reader\ODText;
1919

2020
use DateTime;
21+
use DOMElement;
22+
use DOMNodeList;
2123
use PhpOffice\Math\Reader\MathML;
24+
use PhpOffice\PhpWord\Element\Section;
2225
use PhpOffice\PhpWord\Element\TrackChange;
2326
use PhpOffice\PhpWord\PhpWord;
2427
use PhpOffice\PhpWord\Shared\XMLReader;
@@ -30,6 +33,9 @@
3033
*/
3134
class Content extends AbstractPart
3235
{
36+
/** @var ?Section */
37+
private $section;
38+
3339
/**
3440
* Read content.xml.
3541
*/
@@ -41,17 +47,28 @@ public function read(PhpWord $phpWord): void
4147
$trackedChanges = [];
4248

4349
$nodes = $xmlReader->getElements('office:body/office:text/*');
50+
$this->section = null;
51+
$this->processNodes($nodes, $xmlReader, $phpWord);
52+
$this->section = null;
53+
}
54+
55+
/** @param DOMNodeList<DOMElement> $nodes */
56+
public function processNodes(DOMNodeList $nodes, XMLReader $xmlReader, PhpWord $phpWord): void
57+
{
4458
if ($nodes->length > 0) {
45-
$section = $phpWord->addSection();
4659
foreach ($nodes as $node) {
4760
// $styleName = $xmlReader->getAttribute('text:style-name', $node);
4861
switch ($node->nodeName) {
4962
case 'text:h': // Heading
5063
$depth = $xmlReader->getAttribute('text:outline-level', $node);
51-
$section->addTitle($node->nodeValue, $depth);
64+
$this->getSection($phpWord)->addTitle($node->nodeValue, $depth);
5265

5366
break;
5467
case 'text:p': // Paragraph
68+
$styleName = $xmlReader->getAttribute('text:style-name', $node);
69+
if (substr($styleName, 0, 2) === 'SB') {
70+
break;
71+
}
5572
$element = $xmlReader->getElement('draw:frame/draw:object', $node);
5673
if ($element) {
5774
$mathFile = str_replace('./', '', $element->getAttribute('xlink:href')) . '/content.xml';
@@ -65,11 +82,13 @@ public function read(PhpWord $phpWord): void
6582
$reader = new MathML();
6683
$math = $reader->read($mathXML);
6784

68-
$section->addFormula($math);
85+
$this->getSection($phpWord)->addFormula($math);
6986
}
7087
}
7188
} else {
7289
$children = $node->childNodes;
90+
$spans = false;
91+
/** @var DOMElement $child */
7392
foreach ($children as $child) {
7493
switch ($child->nodeName) {
7594
case 'text:change-start':
@@ -89,16 +108,49 @@ public function read(PhpWord $phpWord): void
89108
$changed = $trackedChanges[$changeId];
90109
}
91110

111+
break;
112+
case 'text:span':
113+
$spans = true;
114+
92115
break;
93116
}
94117
}
95118

96-
$element = $section->addText($node->nodeValue);
119+
if ($spans) {
120+
$element = $this->getSection($phpWord)->addTextRun();
121+
foreach ($children as $child) {
122+
switch ($child->nodeName) {
123+
case 'text:span':
124+
/** @var DOMElement $child2 */
125+
foreach ($child->childNodes as $child2) {
126+
switch ($child2->nodeName) {
127+
case '#text':
128+
$element->addText($child2->nodeValue);
129+
130+
break;
131+
case 'text:tab':
132+
$element->addText("\t");
133+
134+
break;
135+
case 'text:s':
136+
$spaces = (int) $child2->getAttribute('text:c') ?: 1;
137+
$element->addText(str_repeat(' ', $spaces));
138+
139+
break;
140+
}
141+
}
142+
143+
break;
144+
}
145+
}
146+
} else {
147+
$element = $this->getSection($phpWord)->addText($node->nodeValue);
148+
}
97149
if (isset($changed) && is_array($changed)) {
98150
$element->setTrackChange($changed['changed']);
99151
if (isset($changed['textNodes'])) {
100152
foreach ($changed['textNodes'] as $changedNode) {
101-
$element = $section->addText($changedNode->nodeValue);
153+
$element = $this->getSection($phpWord)->addText($changedNode->nodeValue);
102154
$element->setTrackChange($changed['changed']);
103155
}
104156
}
@@ -110,7 +162,7 @@ public function read(PhpWord $phpWord): void
110162
$listItems = $xmlReader->getElements('text:list-item/text:p', $node);
111163
foreach ($listItems as $listItem) {
112164
// $listStyleName = $xmlReader->getAttribute('text:style-name', $listItem);
113-
$section->addListItem($listItem->nodeValue, 0);
165+
$this->getSection($phpWord)->addListItem($listItem->nodeValue, 0);
114166
}
115167

116168
break;
@@ -129,9 +181,26 @@ public function read(PhpWord $phpWord): void
129181
$trackedChanges[$changedRegion->getAttribute('text:id')] = ['changed' => $changed, 'textNodes' => $textNodes];
130182
}
131183

184+
break;
185+
case 'text:section': // Section
186+
// $sectionStyleName = $xmlReader->getAttribute('text:style-name', $listItem);
187+
$this->section = $phpWord->addSection();
188+
$children = $node->childNodes;
189+
$this->processNodes($children, $xmlReader, $phpWord);
190+
132191
break;
133192
}
134193
}
135194
}
136195
}
196+
197+
private function getSection(PhpWord $phpWord): Section
198+
{
199+
$section = $this->section;
200+
if ($section === null) {
201+
$section = $this->section = $phpWord->addSection();
202+
}
203+
204+
return $section;
205+
}
137206
}

src/PhpWord/Reader/Word2007/Styles.php

+10-8
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,16 @@ public function read(PhpWord $phpWord): void
3939
$fontDefaults = $xmlReader->getElement('w:docDefaults/w:rPrDefault');
4040
if ($fontDefaults !== null) {
4141
$fontDefaultStyle = $this->readFontStyle($xmlReader, $fontDefaults);
42-
if (array_key_exists('name', $fontDefaultStyle)) {
43-
$phpWord->setDefaultFontName($fontDefaultStyle['name']);
44-
}
45-
if (array_key_exists('size', $fontDefaultStyle)) {
46-
$phpWord->setDefaultFontSize($fontDefaultStyle['size']);
47-
}
48-
if (array_key_exists('lang', $fontDefaultStyle)) {
49-
$phpWord->getSettings()->setThemeFontLang(new Language($fontDefaultStyle['lang']));
42+
if ($fontDefaultStyle) {
43+
if (array_key_exists('name', $fontDefaultStyle)) {
44+
$phpWord->setDefaultFontName($fontDefaultStyle['name']);
45+
}
46+
if (array_key_exists('size', $fontDefaultStyle)) {
47+
$phpWord->setDefaultFontSize($fontDefaultStyle['size']);
48+
}
49+
if (array_key_exists('lang', $fontDefaultStyle)) {
50+
$phpWord->getSettings()->setThemeFontLang(new Language($fontDefaultStyle['lang']));
51+
}
5052
}
5153
}
5254

src/PhpWord/TemplateProcessor.php

+21
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,27 @@ public function setValues(array $values): void
360360
}
361361
}
362362

363+
public function setCheckbox(string $search, bool $checked): void
364+
{
365+
$search = static::ensureMacroCompleted($search);
366+
$blockType = 'w:sdt';
367+
368+
$where = $this->findContainingXmlBlockForMacro($search, $blockType);
369+
if (!is_array($where)) {
370+
return;
371+
}
372+
373+
$block = $this->getSlice($where['start'], $where['end']);
374+
375+
$val = $checked ? '1' : '0';
376+
$block = preg_replace('/(<w14:checked w14:val=)".*?"(\/>)/', '$1"' . $val . '"$2', $block);
377+
378+
$text = $checked ? '' : '';
379+
$block = preg_replace('/(<w:t>).*?(<\/w:t>)/', '$1' . $text . '$2', $block);
380+
381+
$this->replaceXmlBlock($search, $block, $blockType);
382+
}
383+
363384
/**
364385
* @param string $search
365386
*/

0 commit comments

Comments
 (0)