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