Passed
Push — master ( f85170...1d219c )
by Andrew
02:17
created

XMLReaderElement::__get()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 6
Bugs 0 Features 0
Metric Value
c 6
b 0
f 0
dl 0
loc 10
rs 9.4285
cc 3
eloc 5
nc 3
nop 1
1
<?php
2
namespace Sabre\Xml;
3
4
class XMLReaderElement implements \Iterator {
5
6
    protected $namespace;
7
    protected $name;
8
    protected $attributes;
9
    protected $value;
10
11
    public function rewind() {
12
        reset($this->value);
13
    }
14
15
    public function current() {
16
        return current($this->value);
17
    }
18
19
    public function key() {
20
        return key($this->value);
21
    }
22
23
    public function next() {
24
        return next($this->value);
25
    }
26
27
    public function valid() {
28
        $key = key($this->value);
29
        return ($key !== NULL && $key !== FALSE);
30
    }
31
32
    public function parse($data) {
33
        $this->parseNameSpace($data);
34
        $this->attributes = (object) $this->convertAttributes($data['attributes']);
35
36
        if ($this->isElementArray($data['value'])) {
37
            $this->value = [];
38
39
            foreach ($data['value'] as $value) {
40
                $this->value[] = (new XMLReaderElement())->parse($value);
41
            }
42
        } elseif ($this->isElementValue($data['value'])) {
43
            $this->value = $this->convertValue($data['value']);
44
        } else {
45
            $this->value = (new XMLReaderElement())->parse($data['value']);
46
        }
47
48
        return $this;
49
    }
50
51
    protected function isElementArray($value) {
52
        return is_array($value) && !array_key_exists('name', $value) && array_key_exists('name', current($value));
53
    }
54
55
    protected function isElementValue($value) {
56
        return !is_array($value) || !array_key_exists('name', $value);
57
    }
58
59
    protected function parseNameSpace($data) {
60
        $namespace = [];
61
        preg_match_all('/{(.*?)}/', $data['name'], $namespace);
62
63
        if (count($namespace) === 2) {
64
            $this->namespace = $namespace[1][0];
65
            $this->name      = str_replace($namespace[0][0], '', $data['name']);
66
        } else {
67
            $this->name      = $data['name'];
68
        }
69
    }
70
71
    protected function convertAttributes($attributes) {
72
        foreach ($attributes as $k=>$attribute) {
73
            $attributes[$k] = $this->convertValue($attribute);
74
        }
75
76
        return $attributes;
77
    }
78
79
    protected function convertValue($value) {
80
        if (!is_string($value)) {
81
            return $value;
82
        }
83
84
        if ($this->isBool($value)) {
85
            return filter_var($value, FILTER_VALIDATE_BOOLEAN);
86
        }
87
88
        if ($this->isInteger($value)) {
89
            return (int) $value;
90
        }
91
92
        return $value;
93
    }
94
95
    /* Very specific type of integer checking to ensure
96
    that we have a number value, and not one that has been
97
    mistakenly casted by PHP. Examples below.
98
99
    var_dump(isInteger(23));    //bool(true)
100
    var_dump(isInteger("23"));  //bool(true)
101
    var_dump(isInteger(23.5));  //bool(false)
102
    var_dump(isInteger(NULL));  //bool(false)
103
    var_dump(isInteger(""));    //bool(false)
104
    */
105
    protected function isInteger($input) {
106
        return (ctype_digit(strval($input)));
107
    }
108
109
    /* Very specific type of boolean checking to ensure
110
    that we have a bool value, and not one that has been
111
    mistakenly casted by PHP. Examples below.
112
113
    var_dump(isBool(true));     //bool(true)
114
    var_dump(isBool("false"));  //bool(true)
115
    var_dump(isBool(0));        //bool(false)
116
    var_dump(isBool(NULL));     //bool(false)
117
    var_dump(isBool(""));       //bool(false)
118
    */
119
    protected function isBool($input) {
120
        return in_array(strtolower($input), ['true', 'false']) !== false;
121
    }
122
123
    public function children() {
124
        if ($this->value instanceof XMLReaderElement) {
125
            return [$this->value];
126
        }
127
128
        if (is_array($this->value)) {
129
            $results = [];
130
            foreach ($this->value as $value) {
131
                if ($value instanceof XMLReaderElement) {
132
                    $results[] = $value;
133
                }
134
            }
135
            return $results;
136
        }
137
138
        return [];
139
    }
140
141
    public function hasChildren() {
142
        return !empty($this->children());
143
    }
144
145
    public function findFirst($search) {
146
        return current($this->find($search));
147
    }
148
149
    public function find($search) {
150
151
        $results = [];
152
153
        if ($this->name == $search) {
154
            $results[] = $this;
155
        }
156
157
        foreach ($this->children() as $child) {
158
            $results = array_merge($results, $child->find($search));
159
        }
160
161
        if ($search[0] == '@') {
162
            $search = substr($search, 1);
163
            $results = array_merge($results, $this->findAttribute($search));
164
        }
165
166
        return $results;
167
    }
168
169
    protected function findAttribute($search) {
170
171
        $results = [];
172
        if (property_exists($this->attributes, $search)) {
173
            $results[] = $this->attributes->$search;
174
        }
175
176
        return $results;
177
    }
178
179
    public function __get($name) {
180
        /* Access the Elements Attributes */
181
        foreach($this->children() as $child) {
182
            if ($child->name == $name) {
183
                return $child;
184
            }
185
        }
186
187
        return $this->$name;
188
    }
189
190
    public function __debugInfo() {
191
192
        $arr = ['name'       => $this->name,
193
                'namespace'  => $this->namespace,
194
                'attributes' => $this->attributes
195
                ];
196
197
        if ($this->hasChildren()) {
198
            $names = [];
199
            foreach ($this->children() as $child) {
200
                $names[] = $child->name;
201
            }
202
203
            $arr += ['children' => implode(',', $names)];
204
        } else {
205
            $arr += ['value' => $this->value];
206
        }
207
208
        return $arr;
209
    }
210
}
211