XMLReader::getAttribute()   A
last analyzed

Complexity

Conditions 5
Paths 8

Size

Total Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 5

Importance

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