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