Completed
Push — develop ( bb41d1...5d35fc )
by Franck
08:46
created

XMLReader::elementExists()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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