Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
52 / 52
100.00% covered (success)
100.00%
2 / 2
CRAP
100.00% covered (success)
100.00%
1 / 1
Numbering
100.00% covered (success)
100.00%
52 / 52
100.00% covered (success)
100.00%
2 / 2
14
100.00% covered (success)
100.00%
1 / 1
 read
100.00% covered (success)
100.00%
35 / 35
100.00% covered (success)
100.00%
1 / 1
11
 readLevel
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
3
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\PhpWord;
23use PhpOffice\PhpWord\Shared\XMLReader;
24
25/**
26 * Numbering reader.
27 *
28 * @since 0.10.0
29 */
30class Numbering extends AbstractPart
31{
32    /**
33     * Read numbering.xml.
34     */
35    public function read(PhpWord $phpWord): void
36    {
37        $abstracts = [];
38        $numberings = [];
39        $xmlReader = new XMLReader();
40        $xmlReader->getDomFromZip($this->docFile, $this->xmlFile);
41
42        // Abstract numbering definition
43        $nodes = $xmlReader->getElements('w:abstractNum');
44        if ($nodes->length > 0) {
45            foreach ($nodes as $node) {
46                $abstractId = $xmlReader->getAttribute('w:abstractNumId', $node);
47                $abstracts[$abstractId] = ['levels' => []];
48                $abstract = &$abstracts[$abstractId];
49                $subnodes = $xmlReader->getElements('*', $node);
50                foreach ($subnodes as $subnode) {
51                    switch ($subnode->nodeName) {
52                        case 'w:multiLevelType':
53                            $abstract['type'] = $xmlReader->getAttribute('w:val', $subnode);
54
55                            break;
56                        case 'w:lvl':
57                            $levelId = $xmlReader->getAttribute('w:ilvl', $subnode);
58                            $abstract['levels'][$levelId] = $this->readLevel($xmlReader, $subnode, $levelId);
59
60                            break;
61                    }
62                }
63            }
64        }
65
66        // Numbering instance definition
67        $nodes = $xmlReader->getElements('w:num');
68        if ($nodes->length > 0) {
69            foreach ($nodes as $node) {
70                $numId = $xmlReader->getAttribute('w:numId', $node);
71                $abstractId = $xmlReader->getAttribute('w:val', $node, 'w:abstractNumId');
72                $numberings[$numId] = $abstracts[$abstractId];
73                $numberings[$numId]['numId'] = $numId;
74                $subnodes = $xmlReader->getElements('w:lvlOverride/w:lvl', $node);
75                foreach ($subnodes as $subnode) {
76                    $levelId = $xmlReader->getAttribute('w:ilvl', $subnode);
77                    $overrides = $this->readLevel($xmlReader, $subnode, $levelId);
78                    foreach ($overrides as $key => $value) {
79                        $numberings[$numId]['levels'][$levelId][$key] = $value;
80                    }
81                }
82            }
83        }
84
85        // Push to Style collection
86        foreach ($numberings as $numId => $numbering) {
87            $phpWord->addNumberingStyle("PHPWordList{$numId}", $numbering);
88        }
89    }
90
91    /**
92     * Read numbering level definition from w:abstractNum and w:num.
93     *
94     * @param int $levelId
95     *
96     * @return array
97     */
98    private function readLevel(XMLReader $xmlReader, DOMElement $subnode, $levelId)
99    {
100        $level = [];
101
102        $level['level'] = $levelId;
103        $level['start'] = $xmlReader->getAttribute('w:val', $subnode, 'w:start');
104        $level['format'] = $xmlReader->getAttribute('w:val', $subnode, 'w:numFmt');
105        $level['restart'] = $xmlReader->getAttribute('w:val', $subnode, 'w:lvlRestart');
106        $level['suffix'] = $xmlReader->getAttribute('w:val', $subnode, 'w:suff');
107        $level['text'] = $xmlReader->getAttribute('w:val', $subnode, 'w:lvlText');
108        $level['alignment'] = $xmlReader->getAttribute('w:val', $subnode, 'w:lvlJc');
109        $level['tab'] = $xmlReader->getAttribute('w:pos', $subnode, 'w:pPr/w:tabs/w:tab');
110        $level['left'] = $xmlReader->getAttribute('w:left', $subnode, 'w:pPr/w:ind');
111        $level['hanging'] = $xmlReader->getAttribute('w:hanging', $subnode, 'w:pPr/w:ind');
112        $level['font'] = $xmlReader->getAttribute('w:ascii', $subnode, 'w:rPr/w:rFonts');
113        $level['hint'] = $xmlReader->getAttribute('w:hint', $subnode, 'w:rPr/w:rFonts');
114
115        foreach ($level as $key => $value) {
116            if (null === $value) {
117                unset($level[$key]);
118            }
119        }
120
121        return $level;
122    }
123}