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