Completed
Pull Request — master (#51)
by Günter
02:20
created

Response::serverTransactionId()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 9
rs 9.6666
c 0
b 0
f 0
cc 2
eloc 5
nc 2
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\Frame;
13
14
use AfriCC\EPP\AbstractFrame;
15
use AfriCC\EPP\Frame\Response\Result;
16
use DOMNode;
17
use DOMNodeList;
18
19
/**
20
 * @see http://tools.ietf.org/html/rfc5730#section-2.6
21
 */
22
class Response extends AbstractFrame
23
{
24
    /**
25
     * nodeToArray force array values for the following tags. Usually the upper
26
     * level will expect them as an array to traverse. Otherwise, if only one
27
     * value exists it will be converted directly to a string
28
     *
29
     * @var array
30
     */
31
    protected $n2a_force_array = [
32
        'hostAttr' => true,
33
        'hostObj' => true,
34
        'street' => true,
35
        'hostAddr' => true,
36
    ];
37
38
    /**
39
     * nodeToArray ignore conversion of following attributes. Usually because
40
     * the information is redundant or useless (like the definition of IP types
41
     * which should be done on the higher level)
42
     *
43
     * @var array
44
     */
45
    protected $n2a_ignore_attr = [
46
        'hostAddr' => true,
47
    ];
48
49
    public function results()
50
    {
51
        $results = [];
52
        $nodes = $this->get('//epp:epp/epp:response/epp:result');
53
        foreach ($nodes as $node) {
0 ignored issues
show
Bug introduced by
The expression $nodes of type false|string|object<DOMNodeList> is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
54
            $results[] = new Result($node);
55
        }
56
57
        return $results;
58
    }
59
60
    public function success()
61
    {
62
        $code = $this->code();
63
        if ($code >= 1000 && $code < 2000) {
64
            return true;
65
        }
66
67
        return false;
68
    }
69
70
    public function code()
71
    {
72
        return (int) $this->get('//epp:epp/epp:response/epp:result/@code');
73
    }
74
75
    public function message()
76
    {
77
        return (string) $this->get('//epp:epp/epp:response/epp:result/epp:msg/text()');
78
    }
79
80
    public function clientTransactionId()
81
    {
82
        $value = $this->get('//epp:epp/epp:response/epp:trID/epp:clTRID/text()');
83
        if ($value === false) {
84
            return;
85
        }
86
87
        return (string) $value;
88
    }
89
90
    public function serverTransactionId()
91
    {
92
        $value = $this->get('//epp:epp/epp:response/epp:trID/epp:svTRID/text()');
93
        if ($value === false) {
94
            return;
95
        }
96
97
        return (string) $value;
98
    }
99
100
    public function data()
101
    {
102
        $nodes = $this->get('//epp:epp/epp:response/epp:resData');
103
        if ($nodes === false || !($nodes instanceof DOMNodeList) || $nodes->length === 0 || !$nodes->item(0)->hasChildNodes()) {
104
            $data = [];
105
        } else {
106
            $data = $this->nodeToArray($nodes->item(0));
107
        }
108
109
        // check for extension data
110
        $nodes = $this->get('//epp:epp/epp:response/epp:extension');
111
        if ($nodes !== false && $nodes instanceof DOMNodeList && $nodes->length > 0 && $nodes->item(0)->hasChildNodes()) {
112
            $data = array_merge_recursive($data, $this->nodeToArray($nodes->item(0)));
113
        }
114
115
        return $data;
116
    }
117
118
    private function nodeToArray(DOMNode $node)
119
    {
120
        $tmp = [];
121
        foreach ($node->childNodes as $each) {
122
            if ($each->nodeType !== XML_ELEMENT_NODE) {
123
                continue;
124
            }
125
126
            // if node only has a type attribute lets distinguish them directly
127
            // and then ignore the attribtue
128
            if ($each->hasAttribute('type')) {
129
                $key = $each->localName . '@' . $each->getAttribute('type');
130
                $ignore_attributes = true;
131
            } else {
132
                $key = $each->localName;
133
                $ignore_attributes = false;
134
            }
135
136
            // in case of special keys, always create array
137
            if (isset($this->n2a_force_array[$key])) {
138
                $current = &$tmp[$key][];
139
                end($tmp[$key]);
140
                $insert_key = key($tmp[$key]);
141
            }
142
            // if key already exists, dynamically create an array
143
            elseif (isset($tmp[$key])) {
144
                if (!is_array($tmp[$key]) || !isset($tmp[$key][0])) {
145
                    $tmp[$key] = [$tmp[$key]];
146
                }
147
                $current = &$tmp[$key][];
148
                end($tmp[$key]);
149
                $insert_key = key($tmp[$key]);
150
            }
151
            // key was not yet set, so lets start off with a string
152
            else {
153
                $current = &$tmp[$key];
154
                $insert_key = null;
155
            }
156
157
            if ($each->hasChildNodes()) {
158
                $current = $this->nodeToArray($each);
159
            } else {
160
                $current = $each->nodeValue;
161
162
                if (!$ignore_attributes && !isset($this->n2a_ignore_attr[$each->localName]) && $each->hasAttributes()) {
163
                    foreach ($each->attributes as $attr) {
164
165
                        // single attribute with empty node, use the attr-value directly
166
                        if ($each->localName === 'status' || ($each->attributes->length === 1 && $each->nodeValue === '')) {
167
                            $current = $attr->nodeValue;
168
                            break;
169
                        }
170
171
                        if ($insert_key) {
172
                            if (isset($tmp['@' . $key][$attr->nodeName]) && !is_array($tmp['@' . $key][$attr->nodeName])) {
173
                                $tmp['@' . $key][$attr->nodeName] = [$tmp['@' . $key][$attr->nodeName]];
174
                            }
175
                            $tmp['@' . $key][$attr->nodeName][$insert_key] = $attr->nodeValue;
176
                        } else {
177
                            $tmp['@' . $key][$attr->nodeName] = $attr->nodeValue;
178
                        }
179
                    }
180
                }
181
            }
182
        }
183
184
        return $tmp;
185
    }
186
}
187