XmlFileParser::addNode()   B
last analyzed

Complexity

Conditions 7
Paths 19

Size

Total Lines 37
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 15
dl 0
loc 37
rs 8.8333
c 0
b 0
f 0
cc 7
nc 19
nop 3
1
<?php
2
3
/**
4
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
5
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
6
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
7
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
8
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
9
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
10
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
11
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
12
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
13
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
14
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
15
 *
16
 * This software consists of voluntary contributions made by many individuals
17
 * and is licensed under the LGPL. For more information please see
18
 * <http://phing.info>.
19
 */
20
21
namespace Phing\Io;
22
23
use Phing\Util\Properties;
24
use SimpleXMLElement;
25
26
/**
27
 * Implements an XmlFileParser.
28
 *
29
 * @author  Siad Ardroumli <[email protected]>
30
 */
31
class XmlFileParser implements FileParserInterface
32
{
33
    private $keepRoot = true;
34
    private $collapseAttr = true;
35
    private $delimiter = ',';
36
37
    public function setKeepRoot(bool $keepRoot): void
38
    {
39
        $this->keepRoot = $keepRoot;
40
    }
41
42
    public function setCollapseAttr(bool $collapseAttr): void
43
    {
44
        $this->collapseAttr = $collapseAttr;
45
    }
46
47
    public function setDelimiter(string $delimiter): void
48
    {
49
        $this->delimiter = $delimiter;
50
    }
51
52
    /**
53
     * {@inheritDoc}
54
     */
55
    public function parseFile(File $file)
56
    {
57
        $properties = $this->getProperties($file);
58
59
        return $properties->getProperties();
60
    }
61
62
    /**
63
     * Parses an XML file and returns properties.
64
     *
65
     * @throws IOException
66
     *
67
     * @return Properties
68
     */
69
    private function getProperties(File $file)
70
    {
71
        // load() already made sure that file is readable
72
        // but we'll double check that when reading the file into
73
        // an array
74
75
        if ((@file($file)) === false) {
76
            throw new IOException("Unable to parse contents of {$file}");
77
        }
78
79
        $prop = new Properties();
80
81
        $xml = simplexml_load_string(file_get_contents($file));
82
83
        if (false === $xml) {
84
            throw new IOException("Unable to parse XML file {$file}");
85
        }
86
87
        $path = [];
88
89
        if ($this->keepRoot) {
90
            $path[] = dom_import_simplexml($xml)->tagName;
91
92
            $prefix = implode('.', $path);
93
94
            if (strlen($prefix) > 0) {
95
                $prefix .= '.';
96
            }
97
98
            // Check for attributes
99
            foreach ($xml->attributes() as $attribute => $val) {
100
                if ($this->collapseAttr) {
101
                    $prop->setProperty($prefix . (string) $attribute, (string) $val);
102
                } else {
103
                    $prop->setProperty($prefix . "({$attribute})", (string) $val);
104
                }
105
            }
106
        }
107
108
        $this->addNode($xml, $path, $prop);
109
110
        return $prop;
111
    }
112
113
    /**
114
     * Adds an XML node.
115
     *
116
     * @param SimpleXMLElement $node
117
     * @param array            $path Path to this node
118
     * @param Properties       $prop Properties will be added as they are found (by reference here)
119
     */
120
    private function addNode($node, $path, $prop)
121
    {
122
        foreach ($node as $tag => $value) {
123
            $prefix = implode('.', $path);
124
125
            if ('' !== $prefix) {
126
                $prefix .= '.';
127
            }
128
129
            // Check for attributes
130
            foreach ($value->attributes() as $attribute => $val) {
0 ignored issues
show
Bug introduced by
The method attributes() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

130
            foreach ($value->/** @scrutinizer ignore-call */ attributes() as $attribute => $val) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
131
                if ($this->collapseAttr) {
132
                    $prop->setProperty($prefix . "{$tag}.{$attribute}", (string) $val);
133
                } else {
134
                    $prop->setProperty($prefix . "{$tag}({$attribute})", (string) $val);
135
                }
136
            }
137
138
            // Add tag
139
            if (count($value->children())) {
140
                $this->addNode($value, array_merge($path, [$tag]), $prop);
141
            } else {
142
                $val = (string) $value;
143
144
                /* Check for * and ** on 'exclude' and 'include' tag / ant seems to do this? could use FileSet here
145
                if ($tag == 'exclude') {
146
                }*/
147
148
                // When property already exists, i.e. multiple xml tag
149
                // <project>
150
                //    <exclude>file/a.php</exclude>
151
                //    <exclude>file/a.php</exclude>
152
                // </project>
153
                //
154
                // Would be come project.exclude = file/a.php,file/a.php
155
                $p = empty($prefix) ? $tag : $prefix . $tag;
156
                $prop->append($p, (string) $val, $this->delimiter);
157
            }
158
        }
159
    }
160
}
161