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