Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
154 / 154 |
|
100.00% |
12 / 12 |
CRAP | |
100.00% |
1 / 1 |
Settings | |
100.00% |
154 / 154 |
|
100.00% |
12 / 12 |
43 | |
100.00% |
1 / 1 |
write | |
100.00% |
15 / 15 |
|
100.00% |
1 / 1 |
2 | |||
writeSetting | |
100.00% |
10 / 10 |
|
100.00% |
1 / 1 |
7 | |||
getSettings | |
100.00% |
57 / 57 |
|
100.00% |
1 / 1 |
1 | |||
setOnOffValue | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
3 | |||
setDocumentProtection | |
100.00% |
24 / 24 |
|
100.00% |
1 / 1 |
4 | |||
setProofState | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
4 | |||
setRevisionView | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
7 | |||
setThemeFontLang | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
6 | |||
setZoom | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
3 | |||
setConsecutiveHyphenLimit | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
2 | |||
setHyphenationZone | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
2 | |||
setCompatibility | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
2 |
1 | <?php |
2 | /** |
3 | * This file is part of PHPWord - A pure PHP library for reading and writing |
4 | * word processing documents. |
5 | * |
6 | * PHPWord is free software distributed under the terms of the GNU Lesser |
7 | * General Public License version 3 as published by the Free Software Foundation. |
8 | * |
9 | * For the full copyright and license information, please read the LICENSE |
10 | * file that was distributed with this source code. For the full list of |
11 | * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. |
12 | * |
13 | * @see https://github.com/PHPOffice/PHPWord |
14 | * |
15 | * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 |
16 | */ |
17 | |
18 | namespace PhpOffice\PhpWord\Writer\Word2007\Part; |
19 | |
20 | use PhpOffice\PhpWord\ComplexType\ProofState; |
21 | use PhpOffice\PhpWord\ComplexType\TrackChangesView; |
22 | use PhpOffice\PhpWord\Shared\Microsoft\PasswordEncoder; |
23 | use PhpOffice\PhpWord\Style\Language; |
24 | |
25 | /** |
26 | * Word2007 settings part writer: word/settings.xml. |
27 | * |
28 | * @see http://www.schemacentral.com/sc/ooxml/t-w_CT_Settings.html |
29 | */ |
30 | class Settings extends AbstractPart |
31 | { |
32 | /** |
33 | * Settings value. |
34 | * |
35 | * @var array |
36 | */ |
37 | private $settings = []; |
38 | |
39 | /** |
40 | * Write part. |
41 | * |
42 | * @return string |
43 | */ |
44 | public function write() |
45 | { |
46 | $this->getSettings(); |
47 | |
48 | $xmlWriter = $this->getXmlWriter(); |
49 | |
50 | $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); |
51 | $xmlWriter->startElement('w:settings'); |
52 | $xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'); |
53 | $xmlWriter->writeAttribute('xmlns:w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'); |
54 | $xmlWriter->writeAttribute('xmlns:m', 'http://schemas.openxmlformats.org/officeDocument/2006/math'); |
55 | $xmlWriter->writeAttribute('xmlns:sl', 'http://schemas.openxmlformats.org/schemaLibrary/2006/main'); |
56 | $xmlWriter->writeAttribute('xmlns:o', 'urn:schemas-microsoft-com:office:office'); |
57 | $xmlWriter->writeAttribute('xmlns:v', 'urn:schemas-microsoft-com:vml'); |
58 | $xmlWriter->writeAttribute('xmlns:w10', 'urn:schemas-microsoft-com:office:word'); |
59 | |
60 | foreach ($this->settings as $settingKey => $settingValue) { |
61 | $this->writeSetting($xmlWriter, $settingKey, $settingValue); |
62 | } |
63 | |
64 | $xmlWriter->endElement(); // w:settings |
65 | |
66 | return $xmlWriter->getData(); |
67 | } |
68 | |
69 | /** |
70 | * Write indivual setting, recursive to any child settings. |
71 | * |
72 | * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter |
73 | * @param string $settingKey |
74 | * @param array|string $settingValue |
75 | */ |
76 | protected function writeSetting($xmlWriter, $settingKey, $settingValue): void |
77 | { |
78 | if ($settingValue == '') { |
79 | $xmlWriter->writeElement($settingKey); |
80 | } elseif (is_array($settingValue) && !empty($settingValue)) { |
81 | $xmlWriter->startElement($settingKey); |
82 | |
83 | /** @var array $settingValue Type hint */ |
84 | foreach ($settingValue as $childKey => $childValue) { |
85 | if ($childKey == '@attributes') { |
86 | foreach ($childValue as $key => $val) { |
87 | $xmlWriter->writeAttribute($key, $val); |
88 | } |
89 | } else { |
90 | $this->writeSetting($xmlWriter, $childKey, $childValue); |
91 | } |
92 | } |
93 | $xmlWriter->endElement(); |
94 | } |
95 | } |
96 | |
97 | /** |
98 | * Get settings. |
99 | */ |
100 | private function getSettings(): void |
101 | { |
102 | /** @var \PhpOffice\PhpWord\Metadata\Settings $documentSettings */ |
103 | $documentSettings = $this->getParentWriter()->getPhpWord()->getSettings(); |
104 | |
105 | // Default settings |
106 | $this->settings = [ |
107 | 'w:defaultTabStop' => ['@attributes' => ['w:val' => '708']], |
108 | 'w:hyphenationZone' => ['@attributes' => ['w:val' => '425']], |
109 | 'w:characterSpacingControl' => ['@attributes' => ['w:val' => 'doNotCompress']], |
110 | 'w:decimalSymbol' => ['@attributes' => ['w:val' => $documentSettings->getDecimalSymbol()]], |
111 | 'w:listSeparator' => ['@attributes' => ['w:val' => ';']], |
112 | 'w:compat' => [], |
113 | 'm:mathPr' => [ |
114 | 'm:mathFont' => ['@attributes' => ['m:val' => 'Cambria Math']], |
115 | 'm:brkBin' => ['@attributes' => ['m:val' => 'before']], |
116 | 'm:brkBinSub' => ['@attributes' => ['m:val' => '--']], |
117 | 'm:smallFrac' => ['@attributes' => ['m:val' => 'off']], |
118 | 'm:dispDef' => '', |
119 | 'm:lMargin' => ['@attributes' => ['m:val' => '0']], |
120 | 'm:rMargin' => ['@attributes' => ['m:val' => '0']], |
121 | 'm:defJc' => ['@attributes' => ['m:val' => 'centerGroup']], |
122 | 'm:wrapIndent' => ['@attributes' => ['m:val' => '1440']], |
123 | 'm:intLim' => ['@attributes' => ['m:val' => 'subSup']], |
124 | 'm:naryLim' => ['@attributes' => ['m:val' => 'undOvr']], |
125 | ], |
126 | 'w:clrSchemeMapping' => [ |
127 | '@attributes' => [ |
128 | 'w:bg1' => 'light1', |
129 | 'w:t1' => 'dark1', |
130 | 'w:bg2' => 'light2', |
131 | 'w:t2' => 'dark2', |
132 | 'w:accent1' => 'accent1', |
133 | 'w:accent2' => 'accent2', |
134 | 'w:accent3' => 'accent3', |
135 | 'w:accent4' => 'accent4', |
136 | 'w:accent5' => 'accent5', |
137 | 'w:accent6' => 'accent6', |
138 | 'w:hyperlink' => 'hyperlink', |
139 | 'w:followedHyperlink' => 'followedHyperlink', |
140 | ], |
141 | ], |
142 | ]; |
143 | |
144 | $this->setOnOffValue('w:mirrorMargins', $documentSettings->hasMirrorMargins()); |
145 | $this->setOnOffValue('w:hideSpellingErrors', $documentSettings->hasHideSpellingErrors()); |
146 | $this->setOnOffValue('w:hideGrammaticalErrors', $documentSettings->hasHideGrammaticalErrors()); |
147 | $this->setOnOffValue('w:trackRevisions', $documentSettings->hasTrackRevisions()); |
148 | $this->setOnOffValue('w:doNotTrackMoves', $documentSettings->hasDoNotTrackMoves()); |
149 | $this->setOnOffValue('w:doNotTrackFormatting', $documentSettings->hasDoNotTrackFormatting()); |
150 | $this->setOnOffValue('w:evenAndOddHeaders', $documentSettings->hasEvenAndOddHeaders()); |
151 | $this->setOnOffValue('w:updateFields', $documentSettings->hasUpdateFields()); |
152 | $this->setOnOffValue('w:autoHyphenation', $documentSettings->hasAutoHyphenation()); |
153 | $this->setOnOffValue('w:doNotHyphenateCaps', $documentSettings->hasDoNotHyphenateCaps()); |
154 | $this->setOnOffValue('w:bookFoldPrinting', $documentSettings->hasBookFoldPrinting()); |
155 | |
156 | $this->setThemeFontLang($documentSettings->getThemeFontLang()); |
157 | $this->setRevisionView($documentSettings->getRevisionView()); |
158 | $this->setDocumentProtection($documentSettings->getDocumentProtection()); |
159 | $this->setProofState($documentSettings->getProofState()); |
160 | $this->setZoom($documentSettings->getZoom()); |
161 | $this->setConsecutiveHyphenLimit($documentSettings->getConsecutiveHyphenLimit()); |
162 | $this->setHyphenationZone($documentSettings->getHyphenationZone()); |
163 | $this->setCompatibility(); |
164 | } |
165 | |
166 | /** |
167 | * Adds a boolean attribute to the settings array. |
168 | * |
169 | * @param string $settingName |
170 | * @param null|bool $booleanValue |
171 | */ |
172 | private function setOnOffValue($settingName, $booleanValue): void |
173 | { |
174 | if (!is_bool($booleanValue)) { |
175 | return; |
176 | } |
177 | |
178 | $value = $booleanValue ? 'true' : 'false'; |
179 | $this->settings[$settingName] = ['@attributes' => ['w:val' => $value]]; |
180 | } |
181 | |
182 | /** |
183 | * Get protection settings. |
184 | * |
185 | * @param \PhpOffice\PhpWord\Metadata\Protection $documentProtection |
186 | */ |
187 | private function setDocumentProtection($documentProtection): void |
188 | { |
189 | if ($documentProtection->getEditing() !== null) { |
190 | if ($documentProtection->getPassword() == null) { |
191 | $this->settings['w:documentProtection'] = [ |
192 | '@attributes' => [ |
193 | 'w:enforcement' => 1, |
194 | 'w:edit' => $documentProtection->getEditing(), |
195 | ], |
196 | ]; |
197 | } else { |
198 | if ($documentProtection->getSalt() == null) { |
199 | $documentProtection->setSalt(openssl_random_pseudo_bytes(16)); |
200 | } |
201 | $passwordHash = PasswordEncoder::hashPassword($documentProtection->getPassword(), $documentProtection->getAlgorithm(), $documentProtection->getSalt(), $documentProtection->getSpinCount()); |
202 | $this->settings['w:documentProtection'] = [ |
203 | '@attributes' => [ |
204 | 'w:enforcement' => 1, |
205 | 'w:edit' => $documentProtection->getEditing(), |
206 | 'w:cryptProviderType' => 'rsaFull', |
207 | 'w:cryptAlgorithmClass' => 'hash', |
208 | 'w:cryptAlgorithmType' => 'typeAny', |
209 | 'w:cryptAlgorithmSid' => PasswordEncoder::getAlgorithmId($documentProtection->getAlgorithm()), |
210 | 'w:cryptSpinCount' => $documentProtection->getSpinCount(), |
211 | 'w:hash' => $passwordHash, |
212 | 'w:salt' => base64_encode($documentProtection->getSalt()), |
213 | ], |
214 | ]; |
215 | } |
216 | } |
217 | } |
218 | |
219 | /** |
220 | * Set the Proof state. |
221 | */ |
222 | private function setProofState(?ProofState $proofState = null): void |
223 | { |
224 | if ($proofState != null && $proofState->getGrammar() !== null && $proofState->getSpelling() !== null) { |
225 | $this->settings['w:proofState'] = [ |
226 | '@attributes' => [ |
227 | 'w:spelling' => $proofState->getSpelling(), |
228 | 'w:grammar' => $proofState->getGrammar(), |
229 | ], |
230 | ]; |
231 | } |
232 | } |
233 | |
234 | /** |
235 | * Set the Revision View. |
236 | */ |
237 | private function setRevisionView(?TrackChangesView $trackChangesView = null): void |
238 | { |
239 | if ($trackChangesView != null) { |
240 | $revisionView = []; |
241 | $revisionView['w:markup'] = $trackChangesView->hasMarkup() ? 'true' : 'false'; |
242 | $revisionView['w:comments'] = $trackChangesView->hasComments() ? 'true' : 'false'; |
243 | $revisionView['w:insDel'] = $trackChangesView->hasInsDel() ? 'true' : 'false'; |
244 | $revisionView['w:formatting'] = $trackChangesView->hasFormatting() ? 'true' : 'false'; |
245 | $revisionView['w:inkAnnotations'] = $trackChangesView->hasInkAnnotations() ? 'true' : 'false'; |
246 | |
247 | $this->settings['w:revisionView'] = ['@attributes' => $revisionView]; |
248 | } |
249 | } |
250 | |
251 | /** |
252 | * Sets the language. |
253 | */ |
254 | private function setThemeFontLang(?Language $language = null): void |
255 | { |
256 | $latinLanguage = ($language == null || $language->getLatin() === null) ? 'en-US' : $language->getLatin(); |
257 | $lang = []; |
258 | $lang['w:val'] = $latinLanguage; |
259 | if ($language != null) { |
260 | $lang['w:eastAsia'] = $language->getEastAsia() === null ? 'x-none' : $language->getEastAsia(); |
261 | $lang['w:bidi'] = $language->getBidirectional() === null ? 'x-none' : $language->getBidirectional(); |
262 | } |
263 | $this->settings['w:themeFontLang'] = ['@attributes' => $lang]; |
264 | } |
265 | |
266 | /** |
267 | * Set the magnification. |
268 | * |
269 | * @param mixed $zoom |
270 | */ |
271 | private function setZoom($zoom = null): void |
272 | { |
273 | if ($zoom !== null) { |
274 | $attr = is_int($zoom) ? 'w:percent' : 'w:val'; |
275 | $this->settings['w:zoom'] = ['@attributes' => [$attr => $zoom]]; |
276 | } |
277 | } |
278 | |
279 | /** |
280 | * @param null|int $consecutiveHyphenLimit |
281 | */ |
282 | private function setConsecutiveHyphenLimit($consecutiveHyphenLimit): void |
283 | { |
284 | if ($consecutiveHyphenLimit === null) { |
285 | return; |
286 | } |
287 | |
288 | $this->settings['w:consecutiveHyphenLimit'] = [ |
289 | '@attributes' => ['w:val' => $consecutiveHyphenLimit], |
290 | ]; |
291 | } |
292 | |
293 | /** |
294 | * @param null|float $hyphenationZone |
295 | */ |
296 | private function setHyphenationZone($hyphenationZone): void |
297 | { |
298 | if ($hyphenationZone === null) { |
299 | return; |
300 | } |
301 | |
302 | $this->settings['w:hyphenationZone'] = [ |
303 | '@attributes' => ['w:val' => $hyphenationZone], |
304 | ]; |
305 | } |
306 | |
307 | /** |
308 | * Get compatibility setting. |
309 | */ |
310 | private function setCompatibility(): void |
311 | { |
312 | $compatibility = $this->getParentWriter()->getPhpWord()->getCompatibility(); |
313 | if ($compatibility->getOoxmlVersion() !== null) { |
314 | $this->settings['w:compat']['w:compatSetting'] = [ |
315 | '@attributes' => [ |
316 | 'w:name' => 'compatibilityMode', |
317 | 'w:uri' => 'http://schemas.microsoft.com/office/word', |
318 | 'w:val' => $compatibility->getOoxmlVersion(), |
319 | ], |
320 | ]; |
321 | } |
322 | } |
323 | } |