Completed
Pull Request — master (#82)
by
unknown
01:27
created

AbstractFrame::getExtensionName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
/**
4
 * This file is part of the php-epp2 library.
5
 *
6
 * (c) Gunter Grodotzki <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE file
9
 * that was distributed with this source code.
10
 */
11
12
namespace AfriCC\EPP;
13
14
use DOMDocument;
15
use DOMXPath;
16
use Exception;
17
18
/**
19
 * This is a Frame implementation using DOMDocument that other Frames can
20
 * inherit from.
21
 */
22
abstract class AbstractFrame extends DOMDocument implements FrameInterface
23
{
24
    protected $xpath;
25
    /**
26
     * @var \DOMElement[]
27
     */
28
    protected $nodes;
29
    protected $format;
30
    protected $command;
31
    protected $mapping;
32
    protected $extension;
33
    /**
34
     * @var bool whether to ignore command part when building realxpath
35
     */
36
    protected $ignore_command = false;
37
38
    /**
39
     * @var ObjectSpec custom objectspec used to create XML
40
     */
41
    protected $objectSpec;
42
43
    /**
44
     * Construct (with import if specified) frame
45
     *
46
     * @param DOMDocument $import
0 ignored issues
show
Bug introduced by
There is no parameter named $import. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
47
     * @param ObjectSpec $objectSpec
0 ignored issues
show
Bug introduced by
There is no parameter named $objectSpec. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
48
     */
49
    public function __construct()
50
    {
51
        parent::__construct('1.0', 'UTF-8');
52
        $this->xmlStandalone = false;
53
        $this->formatOutput = true;
54
55
        $import = null;
56
        $objectSpec = null;
57
58
        $num = func_num_args();
59
        if ($num > 2) {
60
            throw new Exception('Too many arguments');
61
        }
62
63
        $args = func_get_args();
64
        foreach ($args as $arg) {
65
            if ($arg instanceof \DOMDocument) {
66
                $import = $arg;
67
            }
68
            if ($arg instanceof ObjectSpec) {
69
                $objectSpec = $arg;
70
            }
71
        }
72
73
        if (\is_null($objectSpec)) {
74
            $objectSpec = new ObjectSpec();
75
        }
76
77
        $this->objectSpec = $objectSpec;
78
79
        if ($import instanceof DOMDocument) {
80
            $node = $this->importNode($import->documentElement, true);
81
            $this->appendChild($node);
82
83
            // register namespaces
84
            $this->xpath = new DOMXPath($this);
85
            foreach ($this->objectSpec->specs as $prefix => $spec) {
86
                $this->xpath->registerNamespace($prefix, $spec['xmlns']);
87
            }
88
89
            $this->registerNodeClass('\DOMElement', '\AfriCC\EPP\DOM\DOMElement');
90
        }
91
92
        $this->getStructure();
93
    }
94
95
    /**
96
     * {@inheritdoc}
97
     *
98
     * @see \AfriCC\EPP\FrameInterface::set()
99
     */
100
    public function set($path = null, $value = null)
101
    {
102
        $path = $this->realxpath($path);
103
104
        if (!isset($this->nodes[$path])) {
105
            $path = $this->createNodes($path);
106
        }
107
108
        if ($value !== null) {
109
            $this->nodes[$path]->nodeValue = htmlspecialchars($value, ENT_XML1, 'UTF-8');
110
        }
111
112
        return $this->nodes[$path];
113
    }
114
115
    /**
116
     * {@inheritdoc}
117
     *
118
     * @see \AfriCC\EPP\FrameInterface::get()
119
     */
120
    public function get($query)
121
    {
122
        $nodes = $this->xpath->query($query);
123
        if ($nodes === null || $nodes->length === 0) {
124
            return false;
125
        }
126
127
        // try to figure out what type is being requested
128
        $last_bit = substr(strrchr($query, '/'), 1);
129
130
        // @see http://stackoverflow.com/a/24730245/567193
131
        if ($nodes->length === 1 && (
132
                ($last_bit[0] === '@' && $nodes->item(0)->nodeType === XML_ATTRIBUTE_NODE) ||
133
                (stripos($last_bit, 'text()') === 0 && $nodes->item(0)->nodeType === XML_TEXT_NODE)
134
            )) {
135
            return $nodes->item(0)->nodeValue;
136
        } else {
137
            return $nodes;
138
        }
139
    }
140
141
    /**
142
     * {@inheritdoc}
143
     *
144
     * @see \AfriCC\EPP\FrameInterface::__toString()
145
     */
146
    public function __toString()
147
    {
148
        return $this->saveXML();
149
    }
150
151
    /**
152
     * Create nodes specified by path
153
     *
154
     * @param string $path
155
     *
156
     * @throws Exception
157
     *
158
     * @return null|string
159
     */
160
    protected function createNodes($path)
161
    {
162
        $path_parts = explode('/', $path);
163
        $node_path = null;
164
165
        for ($i = 0, $limit = count($path_parts); $i < $limit; ++$i) {
166
            $attr_name = $attr_value = $matches = null;
167
168
            // if no namespace given, use root-namespace
169
            if (strpos($path_parts[$i], ':') === false) {
170
                $node_ns = 'epp';
171
                $node_name = $path_parts[$i];
172
                $path_parts[$i] = $node_ns . ':' . $node_name;
173
            } else {
174
                list($node_ns, $node_name) = explode(':', $path_parts[$i], 2);
175
            }
176
177
            // check for node-array
178
            if (substr($node_name, -2) === '[]') {
179
                $node_name = substr($node_name, 0, -2);
180
                // get next key
181
                $next_key = -1;
182
                foreach (array_keys($this->nodes) as $each) {
183
                    if (preg_match('/' . preg_quote($node_ns . ':' . $node_name, '/') . '\[(\d+)\]$/', $each, $matches)) {
184
                        if ($matches[1] > $next_key) {
185
                            $next_key = (int) $matches[1];
186
                        }
187
                    }
188
                }
189
                ++$next_key;
190
                $path_parts[$i] = sprintf('%s:%s[%d]', $node_ns, $node_name, $next_key);
191
            }
192
193
            if (preg_match('/^(.*)\[(\d+)\]$/', $node_name, $matches)) {
194
                // direct node-array access
195
                $node_name = $matches[1];
196
            } elseif (preg_match('/^(.*)\[@([a-z0-9]+)=\'([a-z0-9_]+)\'\]$/i', $node_name, $matches)) {
197
                // check if attribute needs to be set
198
                $node_name = $matches[1];
199
                $attr_name = $matches[2];
200
                $attr_value = $matches[3];
201
            }
202
203
            $node_path = implode('/', array_slice($path_parts, 0, $i + 1));
204
205
            if (isset($this->nodes[$node_path])) {
206
                continue;
207
            }
208
209
            // resolve node namespace
210
            $node_xmlns = $this->objectSpec->xmlns($node_ns);
211
            if ($node_xmlns === false) {
212
                throw new Exception(sprintf('unknown namespace: %s', $node_ns));
213
            }
214
215
            // create node (but don't explicitly define root-node)
216
            if ($node_ns === 'epp') {
217
                $this->nodes[$node_path] = $this->createElementNS($node_xmlns, $node_name);
218
            } else {
219
                $this->nodes[$node_path] = $this->createElementNS($node_xmlns, $node_ns . ':' . $node_name);
220
            }
221
222
            // set attribute
223
            if ($attr_name !== null && $attr_value !== null) {
224
                $this->nodes[$node_path]->setAttribute($attr_name, $attr_value);
225
            }
226
227
            // now append node to parent
228
            if ($i === 0) {
229
                $parent = $this;
230
            } else {
231
                $parent = $this->nodes[implode('/', array_slice($path_parts, 0, $i))];
232
            }
233
            $parent->appendChild($this->nodes[$node_path]);
234
        }
235
236
        return $node_path;
237
    }
238
239
    /**
240
     * Get Real XPath for provided path
241
     *
242
     * @param string $path
243
     *
244
     * @return string
245
     */
246
    protected function realxpath($path)
247
    {
248
        if ($path === null) {
249
            $path_parts = [];
250
        } elseif (isset($path[1]) && $path[0] === '/' && $path[1] === '/') {
251
            // absolute path
252
            return substr($path, 2);
253
        } else {
254
            $path_parts = explode('/', $path);
255
        }
256
257
        if (!empty($this->mapping) && !empty($this->command)) {
258
            array_unshift($path_parts, $this->mapping . ':' . $this->command);
259
        }
260
261
        if (!empty($this->command) && !$this->ignore_command) {
262
            array_unshift($path_parts, 'epp:' . $this->command);
263
        }
264
265
        if (!empty($this->format)) {
266
            array_unshift($path_parts, 'epp:' . $this->format);
267
        }
268
269
        array_unshift($path_parts, 'epp:epp');
270
271
        return implode('/', $path_parts);
272
    }
273
274
    private function getStructure()
275
    {
276
        // get class structure
277
        $classes = [get_class($this)];
278
        $classes = array_merge($classes, class_parents($this));
279
280
        foreach ($classes as $class) {
281
            $bare_class = $this->className($class);
282
283
            // stop when we reach self
284
            if ($bare_class === $this->className(__CLASS__)) {
285
                break;
286
            }
287
288
            // try to figure out the structure
289
            $parent_class = $this->className(get_parent_class($class));
290
            if ($parent_class === false) {
291
                continue;
292
            } elseif (empty($this->mapping) && in_array(strtolower($parent_class), $this->objectSpec->mappings)) {
293
                $this->mapping = strtolower($bare_class);
294
            } elseif (empty($this->command) && $parent_class === 'Command') {
295
                $this->command = strtolower($bare_class);
296
            } elseif ($parent_class === 'AbstractFrame') {
297
                $this->format = strtolower($bare_class);
298
            }
299
        }
300
301
        if ($this instanceof ExtensionInterface) {
302
            // automatically guess extension according to class name if not defined in class
303
            if (!isset($this->extension)) {
304
                $this->extension = $this->getExtensionName();
305
            }
306
307
            // add to object spec
308
            $this->objectSpec->specs[$this->extension]['xmlns'] = $this->getExtensionNamespace();
0 ignored issues
show
Bug introduced by
The method getExtensionNamespace() does not exist on AfriCC\EPP\AbstractFrame. Did you maybe mean getExtensionName()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
309
        }
310
    }
311
312
    /**
313
     * Get Class name from full class
314
     *
315
     * @param string $class
316
     *
317
     * @return string
318
     */
319
    private function className($class)
320
    {
321
        if (!is_string($class)) {
322
            return $class;
323
        }
324
        if (($pos = strrpos($class, '\\')) === false) {
325
            return $class;
326
        }
327
328
        return substr($class, $pos + 1);
329
    }
330
331
    public function getExtensionName()
332
    {
333
        return strtolower($this->className(get_class($this)));
334
    }
335
}
336