Completed
Push — master ( 028970...edb5d3 )
by Franck
10s
created

XMLReader   A

Complexity

Total Complexity 22

Size/Duplication

Total Lines 186
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 22
lcom 1
cbo 0
dl 0
loc 186
ccs 54
cts 54
cp 1
rs 10
c 0
b 0
f 0

9 Methods

Rating   Name   Duplication   Size   Complexity  
A getDomFromZip() 0 17 3
A getDomFromString() 0 8 1
A getElements() 0 15 4
A registerNamespace() 0 10 3
A getElement() 0 9 2
A getAttribute() 0 18 5
A getValue() 0 9 2
A countElements() 0 6 1
A elementExists() 0 4 1
1
<?php
2
/**
3
 * This file is part of PHPOffice Common
4
 *
5
 * PHPOffice Common is free software distributed under the terms of the GNU Lesser
6
 * General Public License version 3 as published by the Free Software Foundation.
7
 *
8
 * For the full copyright and license information, please read the LICENSE
9
 * file that was distributed with this source code. For the full list of
10
 * contributors, visit https://github.com/PHPOffice/Common/contributors.
11
 *
12
 * @link        https://github.com/PHPOffice/Common
13
 * @copyright   2009-2016 PHPOffice Common contributors
14
 * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
15
 */
16
17
namespace PhpOffice\Common;
18
19
/**
20
 * XML Reader wrapper
21
 *
22
 * @since   0.2.1
23
 */
24
class XMLReader
25
{
26
    /**
27
     * DOMDocument object
28
     *
29
     * @var \DOMDocument
30
     */
31
    private $dom = null;
32
33
    /**
34
     * DOMXpath object
35
     *
36
     * @var \DOMXpath
37
     */
38
    private $xpath = null;
39
40
    /**
41
     * Get DOMDocument from ZipArchive
42
     *
43
     * @param string $zipFile
44
     * @param string $xmlFile
45
     * @return \DOMDocument|false
46
     * @throws \Exception
47
     */
48 2
    public function getDomFromZip($zipFile, $xmlFile)
49
    {
50 2
        if (file_exists($zipFile) === false) {
51 1
            throw new \Exception('Cannot find archive file.');
52
        }
53
54 1
        $zip = new \ZipArchive();
55 1
        $zip->open($zipFile);
56 1
        $content = $zip->getFromName($xmlFile);
57 1
        $zip->close();
58
59 1
        if ($content === false) {
60 1
            return false;
61
        }
62
63 1
        return $this->getDomFromString($content);
64
    }
65
66
    /**
67
     * Get DOMDocument from content string
68
     *
69
     * @param string $content
70
     * @return \DOMDocument
71
     */
72 6
    public function getDomFromString($content)
73
    {
74 6
        libxml_disable_entity_loader(true);
75 6
        $this->dom = new \DOMDocument();
76 6
        $this->dom->loadXML($content);
77
78 6
        return $this->dom;
79
    }
80
81
    /**
82
     * Get elements
83
     *
84
     * @param string $path
85
     * @param \DOMElement $contextNode
86
     * @return \DOMNodeList
87
     */
88 6
    public function getElements($path, \DOMElement $contextNode = null)
89
    {
90 6
        if ($this->dom === null) {
91 1
            return array();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return array(); (array) is incompatible with the return type documented by PhpOffice\Common\XMLReader::getElements of type DOMNodeList.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
92
        }
93 6
        if ($this->xpath === null) {
94 5
            $this->xpath = new \DOMXpath($this->dom);
95
        }
96
97 6
        if (is_null($contextNode)) {
98 6
            return $this->xpath->query($path);
99
        }
100
101 1
        return $this->xpath->query($path, $contextNode);
102
    }
103
104
    /**
105
     * Registers the namespace with the DOMXPath object
106
     *
107
     * @param string $prefix The prefix
108
     * @param string $namespaceURI The URI of the namespace
109
     * @return bool true on success or false on failure
110
     * @throws \InvalidArgumentException If called before having loaded the DOM document
111
     */
112 2
    public function registerNamespace($prefix, $namespaceURI)
113
    {
114 2
        if ($this->dom === null) {
115 1
            throw new \InvalidArgumentException('Dom needs to be loaded before registering a namespace');
116
        }
117 1
        if ($this->xpath === null) {
118 1
            $this->xpath = new \DOMXpath($this->dom);
119
        }
120 1
        return $this->xpath->registerNamespace($prefix, $namespaceURI);
121
    }
122
123
    /**
124
     * Get element
125
     *
126
     * @param string $path
127
     * @param \DOMElement $contextNode
128
     * @return \DOMElement|null
129
     */
130 3
    public function getElement($path, \DOMElement $contextNode = null)
131
    {
132 3
        $elements = $this->getElements($path, $contextNode);
133 3
        if ($elements->length > 0) {
134 2
            return $elements->item(0);
135
        }
136
137 1
        return null;
138
    }
139
140
    /**
141
     * Get element attribute
142
     *
143
     * @param string $attribute
144
     * @param \DOMElement $contextNode
145
     * @param string $path
146
     * @return string|null
147
     */
148 1
    public function getAttribute($attribute, \DOMElement $contextNode = null, $path = null)
149
    {
150 1
        $return = null;
151 1
        if ($path !== null) {
152 1
            $elements = $this->getElements($path, $contextNode);
153 1
            if ($elements->length > 0) {
154
                /** @var \DOMElement $node Type hint */
155 1
                $node = $elements->item(0);
156 1
                $return = $node->getAttribute($attribute);
157
            }
158
        } else {
159 1
            if ($contextNode !== null) {
160 1
                $return = $contextNode->getAttribute($attribute);
161
            }
162
        }
163
164 1
        return ($return == '') ? null : $return;
165
    }
166
167
    /**
168
     * Get element value
169
     *
170
     * @param string $path
171
     * @param \DOMElement $contextNode
172
     * @return string|null
173
     */
174 2
    public function getValue($path, \DOMElement $contextNode = null)
175
    {
176 2
        $elements = $this->getElements($path, $contextNode);
177 2
        if ($elements->length > 0) {
178 1
            return $elements->item(0)->nodeValue;
179
        }
180
181 1
        return null;
182
    }
183
184
    /**
185
     * Count elements
186
     *
187
     * @param string $path
188
     * @param \DOMElement $contextNode
189
     * @return integer
190
     */
191 1
    public function countElements($path, \DOMElement $contextNode = null)
192
    {
193 1
        $elements = $this->getElements($path, $contextNode);
194
195 1
        return $elements->length;
196
    }
197
198
    /**
199
     * Element exists
200
     *
201
     * @param string $path
202
     * @param \DOMElement $contextNode
203
     * @return boolean
204
     */
205 4
    public function elementExists($path, \DOMElement $contextNode = null)
206
    {
207 4
        return $this->getElements($path, $contextNode)->length > 0;
208
    }
209
}
210