Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
142 / 142
100.00% covered (success)
100.00%
5 / 5
CRAP
100.00% covered (success)
100.00%
1 / 1
Styles
100.00% covered (success)
100.00%
142 / 142
100.00% covered (success)
100.00%
5 / 5
26
100.00% covered (success)
100.00%
1 / 1
 write
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
5
 writeDefaultStyles
100.00% covered (success)
100.00%
62 / 62
100.00% covered (success)
100.00%
1 / 1
9
 writeFontStyle
100.00% covered (success)
100.00%
36 / 36
100.00% covered (success)
100.00%
1 / 1
10
 writeParagraphStyle
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
1
 writeTableStyle
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
1
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
18namespace PhpOffice\PhpWord\Writer\Word2007\Part;
19
20use PhpOffice\PhpWord\Shared\XMLWriter;
21use PhpOffice\PhpWord\Style;
22use PhpOffice\PhpWord\Style\Font as FontStyle;
23use PhpOffice\PhpWord\Style\Paragraph as ParagraphStyle;
24use PhpOffice\PhpWord\Style\Table as TableStyle;
25use PhpOffice\PhpWord\Writer\Word2007\Style\Font as FontStyleWriter;
26use PhpOffice\PhpWord\Writer\Word2007\Style\Paragraph as ParagraphStyleWriter;
27use PhpOffice\PhpWord\Writer\Word2007\Style\Table as TableStyleWriter;
28
29/**
30 * Word2007 styles part writer: word/styles.xml.
31 *
32 * @todo Do something with the numbering style introduced in 0.10.0
33 *
34 * @SuppressWarnings(PHPMD.UnusedPrivateMethod) For writeFontStyle, writeParagraphStyle, and writeTableStyle
35 */
36class Styles extends AbstractPart
37{
38    /**
39     * Write part.
40     *
41     * @return string
42     */
43    public function write()
44    {
45        $xmlWriter = $this->getXmlWriter();
46
47        $xmlWriter->startDocument('1.0', 'UTF-8', 'yes');
48        $xmlWriter->startElement('w:styles');
49        $xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');
50        $xmlWriter->writeAttribute('xmlns:w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main');
51
52        // Write default styles
53        $styles = Style::getStyles();
54        $this->writeDefaultStyles($xmlWriter, $styles);
55
56        // Write styles
57        if (count($styles) > 0) {
58            foreach ($styles as $styleName => $style) {
59                if ($styleName == 'Normal') {
60                    continue;
61                }
62
63                // Get style class and execute if the private method exists
64                $styleClass = substr(get_class($style), strrpos(get_class($style), '\\') + 1);
65                $method = "write{$styleClass}Style";
66                if (method_exists($this, $method)) {
67                    $this->$method($xmlWriter, $styleName, $style);
68                }
69            }
70        }
71
72        $xmlWriter->endElement(); // w:styles
73
74        return $xmlWriter->getData();
75    }
76
77    /**
78     * Write default font and other default styles.
79     *
80     * @param \PhpOffice\PhpWord\Style\AbstractStyle[] $styles
81     */
82    private function writeDefaultStyles(XMLWriter $xmlWriter, $styles): void
83    {
84        $phpWord = $this->getParentWriter()->getPhpWord();
85        $fontName = $phpWord->getDefaultFontName();
86        $fontSize = $phpWord->getDefaultFontSize();
87        $language = $phpWord->getSettings()->getThemeFontLang();
88        $latinLanguage = ($language == null || $language->getLatin() === null) ? 'en-US' : $language->getLatin();
89
90        // Default font
91        $xmlWriter->startElement('w:docDefaults');
92        $xmlWriter->startElement('w:rPrDefault');
93        $xmlWriter->startElement('w:rPr');
94        $xmlWriter->startElement('w:rFonts');
95        $xmlWriter->writeAttribute('w:ascii', $fontName);
96        $xmlWriter->writeAttribute('w:hAnsi', $fontName);
97        $xmlWriter->writeAttribute('w:eastAsia', $fontName);
98        $xmlWriter->writeAttribute('w:cs', $fontName);
99        $xmlWriter->endElement(); // w:rFonts
100        $xmlWriter->startElement('w:sz');
101        $xmlWriter->writeAttribute('w:val', $fontSize * 2);
102        $xmlWriter->endElement(); // w:sz
103        $xmlWriter->startElement('w:szCs');
104        $xmlWriter->writeAttribute('w:val', $fontSize * 2);
105        $xmlWriter->endElement(); // w:szCs
106        $xmlWriter->startElement('w:lang');
107        $xmlWriter->writeAttribute('w:val', $latinLanguage);
108        if ($language != null) {
109            $xmlWriter->writeAttributeIf($language->getEastAsia() !== null, 'w:eastAsia', $language->getEastAsia());
110            $xmlWriter->writeAttributeIf($language->getBidirectional() !== null, 'w:bidi', $language->getBidirectional());
111        }
112        $xmlWriter->endElement(); // w:lang
113        $xmlWriter->endElement(); // w:rPr
114        $xmlWriter->endElement(); // w:rPrDefault
115        $xmlWriter->endElement(); // w:docDefaults
116
117        // Normal style
118        $xmlWriter->startElement('w:style');
119        $xmlWriter->writeAttribute('w:type', 'paragraph');
120        $xmlWriter->writeAttribute('w:default', '1');
121        $xmlWriter->writeAttribute('w:styleId', 'Normal');
122        $xmlWriter->startElement('w:name');
123        $xmlWriter->writeAttribute('w:val', 'Normal');
124        $xmlWriter->endElement(); // w:name
125        if (isset($styles['Normal'])) {
126            $normalStyle = $styles['Normal'];
127            // w:pPr
128            if ($normalStyle instanceof Fontstyle && $normalStyle->getParagraph() != null) {
129                $styleWriter = new ParagraphStyleWriter($xmlWriter, $normalStyle->getParagraph());
130                $styleWriter->write();
131            } elseif ($normalStyle instanceof ParagraphStyle) {
132                $styleWriter = new ParagraphStyleWriter($xmlWriter, $normalStyle);
133                $styleWriter->write();
134            }
135
136            // w:rPr
137            $styleWriter = new FontStyleWriter($xmlWriter, $normalStyle);
138            $styleWriter->write();
139        }
140        $xmlWriter->endElement(); // w:style
141
142        // FootnoteReference style
143        if (!isset($styles['FootnoteReference'])) {
144            $xmlWriter->startElement('w:style');
145            $xmlWriter->writeAttribute('w:type', 'character');
146            $xmlWriter->writeAttribute('w:styleId', 'FootnoteReference');
147            $xmlWriter->startElement('w:name');
148            $xmlWriter->writeAttribute('w:val', 'Footnote Reference');
149            $xmlWriter->endElement(); // w:name
150            $xmlWriter->writeElement('w:semiHidden');
151            $xmlWriter->writeElement('w:unhideWhenUsed');
152            $xmlWriter->startElement('w:rPr');
153            $xmlWriter->startElement('w:vertAlign');
154            $xmlWriter->writeAttribute('w:val', 'superscript');
155            $xmlWriter->endElement(); // w:vertAlign
156            $xmlWriter->endElement(); // w:rPr
157            $xmlWriter->endElement(); // w:style
158        }
159    }
160
161    /**
162     * Write font style.
163     *
164     * @param string $styleName
165     */
166    private function writeFontStyle(XMLWriter $xmlWriter, $styleName, FontStyle $style): void
167    {
168        $paragraphStyle = $style->getParagraph();
169        $styleType = $style->getStyleType();
170        $type = ($styleType == 'title') ? 'paragraph' : 'character';
171        if (null !== $paragraphStyle) {
172            $type = 'paragraph';
173        }
174
175        $xmlWriter->startElement('w:style');
176        $xmlWriter->writeAttribute('w:type', $type);
177
178        // Heading style
179        if ($styleType == 'title') {
180            $arrStyle = explode('_', $styleName);
181            if (count($arrStyle) > 1) {
182                $styleId = 'Heading' . $arrStyle[1];
183                $styleName = 'heading ' . $arrStyle[1];
184                $styleLink = 'Heading' . $arrStyle[1] . 'Char';
185            } else {
186                $styleId = $styleName;
187                $styleName = strtolower($styleName);
188                $styleLink = $styleName . 'Char';
189            }
190            $xmlWriter->writeAttribute('w:styleId', $styleId);
191
192            $xmlWriter->startElement('w:link');
193            $xmlWriter->writeAttribute('w:val', $styleLink);
194            $xmlWriter->endElement();
195        } elseif (null !== $paragraphStyle) {
196            // if type is 'paragraph' it should have a styleId
197            $xmlWriter->writeAttribute('w:styleId', $styleName);
198        }
199
200        // Style name
201        $xmlWriter->startElement('w:name');
202        $xmlWriter->writeAttribute('w:val', $styleName);
203        $xmlWriter->endElement();
204
205        // Parent style
206        if (null !== $paragraphStyle) {
207            if ($paragraphStyle->getStyleName() != null) {
208                $xmlWriter->writeElementBlock('w:basedOn', 'w:val', $paragraphStyle->getStyleName());
209            } elseif ($paragraphStyle->getBasedOn() != null) {
210                $xmlWriter->writeElementBlock('w:basedOn', 'w:val', $paragraphStyle->getBasedOn());
211            }
212        }
213
214        // w:pPr
215        if (null !== $paragraphStyle) {
216            $styleWriter = new ParagraphStyleWriter($xmlWriter, $paragraphStyle);
217            $styleWriter->write();
218        }
219
220        // w:rPr
221        $styleWriter = new FontStyleWriter($xmlWriter, $style);
222        $styleWriter->write();
223
224        $xmlWriter->endElement();
225    }
226
227    /**
228     * Write paragraph style.
229     *
230     * @param string $styleName
231     */
232    private function writeParagraphStyle(XMLWriter $xmlWriter, $styleName, ParagraphStyle $style): void
233    {
234        $xmlWriter->startElement('w:style');
235        $xmlWriter->writeAttribute('w:type', 'paragraph');
236        $xmlWriter->writeAttribute('w:customStyle', '1');
237        $xmlWriter->writeAttribute('w:styleId', $styleName);
238        $xmlWriter->startElement('w:name');
239        $xmlWriter->writeAttribute('w:val', $styleName);
240        $xmlWriter->endElement();
241
242        // Parent style
243        $basedOn = $style->getBasedOn();
244        $xmlWriter->writeElementIf(null !== $basedOn, 'w:basedOn', 'w:val', $basedOn);
245
246        // Next paragraph style
247        $next = $style->getNext();
248        $xmlWriter->writeElementIf(null !== $next, 'w:next', 'w:val', $next);
249
250        // w:pPr
251        $styleWriter = new ParagraphStyleWriter($xmlWriter, $style);
252        $styleWriter->write();
253
254        $xmlWriter->endElement();
255    }
256
257    /**
258     * Write table style.
259     *
260     * @param string $styleName
261     */
262    private function writeTableStyle(XMLWriter $xmlWriter, $styleName, TableStyle $style): void
263    {
264        $xmlWriter->startElement('w:style');
265        $xmlWriter->writeAttribute('w:type', 'table');
266        $xmlWriter->writeAttribute('w:customStyle', '1');
267        $xmlWriter->writeAttribute('w:styleId', $styleName);
268        $xmlWriter->startElement('w:name');
269        $xmlWriter->writeAttribute('w:val', $styleName);
270        $xmlWriter->endElement();
271        $xmlWriter->startElement('w:uiPriority');
272        $xmlWriter->writeAttribute('w:val', '99');
273        $xmlWriter->endElement();
274
275        $styleWriter = new TableStyleWriter($xmlWriter, $style);
276        $styleWriter->write();
277
278        $xmlWriter->endElement(); // w:style
279    }
280}