Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
63 / 63
100.00% covered (success)
100.00%
5 / 5
CRAP
100.00% covered (success)
100.00%
1 / 1
Document
100.00% covered (success)
100.00%
63 / 63
100.00% covered (success)
100.00%
5 / 5
21
100.00% covered (success)
100.00%
1 / 1
 read
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
4
 readHeaderFooter
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
8
 readSectionStyle
100.00% covered (success)
100.00%
26 / 26
100.00% covered (success)
100.00%
1 / 1
4
 readWPNode
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
4
 readWSectPrNode
100.00% covered (success)
100.00%
3 / 3
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\Reader\Word2007;
19
20use DOMElement;
21use PhpOffice\PhpWord\Element\Section;
22use PhpOffice\PhpWord\PhpWord;
23use PhpOffice\PhpWord\Shared\XMLReader;
24
25/**
26 * Document reader.
27 *
28 * @since 0.10.0
29 *
30 * @SuppressWarnings(PHPMD.UnusedPrivateMethod) For readWPNode
31 */
32class Document extends AbstractPart
33{
34    /**
35     * PhpWord object.
36     *
37     * @var \PhpOffice\PhpWord\PhpWord
38     */
39    private $phpWord;
40
41    /**
42     * Read document.xml.
43     */
44    public function read(PhpWord $phpWord): void
45    {
46        $this->phpWord = $phpWord;
47        $xmlReader = new XMLReader();
48        $xmlReader->getDomFromZip($this->docFile, $this->xmlFile);
49        $readMethods = ['w:p' => 'readWPNode', 'w:tbl' => 'readTable', 'w:sectPr' => 'readWSectPrNode'];
50
51        $nodes = $xmlReader->getElements('w:body/*');
52        if ($nodes->length > 0) {
53            $section = $this->phpWord->addSection();
54            foreach ($nodes as $node) {
55                if (isset($readMethods[$node->nodeName])) {
56                    $readMethod = $readMethods[$node->nodeName];
57                    $this->$readMethod($xmlReader, $node, $section);
58                }
59            }
60        }
61    }
62
63    /**
64     * Read header footer.
65     *
66     * @param array $settings
67     */
68    private function readHeaderFooter($settings, Section &$section): void
69    {
70        $readMethods = ['w:p' => 'readParagraph', 'w:tbl' => 'readTable'];
71
72        if (is_array($settings) && isset($settings['hf'])) {
73            foreach ($settings['hf'] as $rId => $hfSetting) {
74                if (isset($this->rels['document'][$rId])) {
75                    [$hfType, $xmlFile, $docPart] = array_values($this->rels['document'][$rId]);
76                    $addMethod = "add{$hfType}";
77                    $hfObject = $section->$addMethod($hfSetting['type']);
78
79                    // Read header/footer content
80                    $xmlReader = new XMLReader();
81                    $xmlReader->getDomFromZip($this->docFile, $xmlFile);
82                    $nodes = $xmlReader->getElements('*');
83                    if ($nodes->length > 0) {
84                        foreach ($nodes as $node) {
85                            if (isset($readMethods[$node->nodeName])) {
86                                $readMethod = $readMethods[$node->nodeName];
87                                $this->$readMethod($xmlReader, $node, $hfObject, $docPart);
88                            }
89                        }
90                    }
91                }
92            }
93        }
94    }
95
96    /**
97     * Read w:sectPr.
98     *
99     * @ignoreScrutinizerPatch
100     *
101     * @return array
102     */
103    private function readSectionStyle(XMLReader $xmlReader, DOMElement $domNode)
104    {
105        $styleDefs = [
106            'breakType' => [self::READ_VALUE, 'w:type'],
107            'vAlign' => [self::READ_VALUE, 'w:vAlign'],
108            'pageSizeW' => [self::READ_VALUE, 'w:pgSz', 'w:w'],
109            'pageSizeH' => [self::READ_VALUE, 'w:pgSz', 'w:h'],
110            'orientation' => [self::READ_VALUE, 'w:pgSz', 'w:orient'],
111            'colsNum' => [self::READ_VALUE, 'w:cols', 'w:num'],
112            'colsSpace' => [self::READ_VALUE, 'w:cols', 'w:space'],
113            'marginTop' => [self::READ_VALUE, 'w:pgMar', 'w:top'],
114            'marginLeft' => [self::READ_VALUE, 'w:pgMar', 'w:left'],
115            'marginBottom' => [self::READ_VALUE, 'w:pgMar', 'w:bottom'],
116            'marginRight' => [self::READ_VALUE, 'w:pgMar', 'w:right'],
117            'headerHeight' => [self::READ_VALUE, 'w:pgMar', 'w:header'],
118            'footerHeight' => [self::READ_VALUE, 'w:pgMar', 'w:footer'],
119            'gutter' => [self::READ_VALUE, 'w:pgMar', 'w:gutter'],
120        ];
121        $styles = $this->readStyleDefs($xmlReader, $domNode, $styleDefs);
122
123        // Header and footer
124        // @todo Cleanup this part
125        $nodes = $xmlReader->getElements('*', $domNode);
126        foreach ($nodes as $node) {
127            if ($node->nodeName == 'w:headerReference' || $node->nodeName == 'w:footerReference') {
128                $id = $xmlReader->getAttribute('r:id', $node);
129                $styles['hf'][$id] = [
130                    'method' => str_replace('w:', '', str_replace('Reference', '', $node->nodeName)),
131                    'type' => $xmlReader->getAttribute('w:type', $node),
132                ];
133            }
134        }
135
136        return $styles;
137    }
138
139    /**
140     * Read w:p node.
141     */
142    private function readWPNode(XMLReader $xmlReader, DOMElement $node, Section &$section): void
143    {
144        // Page break
145        if ($xmlReader->getAttribute('w:type', $node, 'w:r/w:br') == 'page') {
146            $section->addPageBreak(); // PageBreak
147        }
148
149        // Paragraph
150        $this->readParagraph($xmlReader, $node, $section);
151
152        // Section properties
153        if ($xmlReader->elementExists('w:pPr/w:sectPr', $node)) {
154            $sectPrNode = $xmlReader->getElement('w:pPr/w:sectPr', $node);
155            if ($sectPrNode !== null) {
156                $this->readWSectPrNode($xmlReader, $sectPrNode, $section);
157            }
158            $section = $this->phpWord->addSection();
159        }
160    }
161
162    /**
163     * Read w:sectPr node.
164     */
165    private function readWSectPrNode(XMLReader $xmlReader, DOMElement $node, Section &$section): void
166    {
167        $style = $this->readSectionStyle($xmlReader, $node);
168        $section->setStyle($style);
169        $this->readHeaderFooter($style, $section);
170    }
171}