Completed
Push — master ( ac4bd7...8d332b )
by Andrew
11:57
created

NodeList   B

Complexity

Total Complexity 38

Size/Duplication

Total Lines 273
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 70.37%

Importance

Changes 3
Bugs 0 Features 1
Metric Value
wmc 38
c 3
b 0
f 1
lcom 1
cbo 4
dl 0
loc 273
ccs 57
cts 81
cp 0.7037
rs 8.3999

25 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A __call() 0 13 3
A collection() 0 3 1
A document() 0 3 1
A result() 0 3 1
A reverse() 0 5 1
A first() 0 3 2
A last() 0 3 1
A end() 0 3 2
A get() 0 7 2
A set() 0 5 1
A each() 0 11 3
A map() 0 13 4
A reduce() 0 3 1
A toArray() 0 3 1
A fromArray() 0 7 2
A merge() 0 7 2
A slice() 0 5 1
A push() 0 5 1
A pop() 0 3 1
A unshift() 0 5 1
A shift() 0 3 1
A exists() 0 3 1
A delete() 0 9 2
A isRemoved() 0 3 1
1
<?php declare(strict_types=1);
2
3
namespace DOMWrap;
4
5
use DOMWrap\Traits\{
6
    CommonTrait,
7
    TraversalTrait,
8
    ManipulationTrait
9
};
10
use DOMWrap\Collections\NodeCollection;
11
12
/**
13
 * Node List
14
 *
15
 * @package DOMWrap
16
 * @license http://opensource.org/licenses/BSD-3-Clause BSD 3 Clause
17
 */
18
class NodeList extends NodeCollection
19
{
20
    use CommonTrait;
21
    use TraversalTrait;
22
    use ManipulationTrait {
23
        ManipulationTrait::__call as __manipulationCall;
24
    }
25
26
    /** @var Document */
27
    protected $document;
28
29
    /**
30
     * @param Document $document
31
     * @param iterable $nodes
32
     */
33 138
    public function __construct(Document $document = null, iterable $nodes = null) {
34 138
        parent::__construct($nodes);
35
36 138
        $this->document = $document;
37 138
    }
38
39
    /**
40
     * @param string $name
41
     * @param array $arguments
42
     *
43
     * @return mixed
44
     */
45 4
    public function __call(string $name, array $arguments) {
46
        try {
47 4
            $result = $this->__manipulationCall($name, $arguments);
48 1
        } catch (\BadMethodCallException $e) {
49 1
            if (!method_exists($this->first(), $name)) {
50 1
                throw new \BadMethodCallException("Call to undefined method " . get_class($this) . '::' . $name . "()");
51
            }
52
53
            $result = call_user_func_array([$this->first(), $name], $arguments);
54
        }
55
56 3
        return $result;
57
    }
58
59
    /**
60
     * {@inheritdoc}
61
     */
62 116
    public function collection(): NodeList {
63 116
        return $this;
64
    }
65
66
    /**
67
     * {@inheritdoc}
68
     */
69 130
    public function document(): ?\DOMDocument {
70 130
        return $this->document;
71
    }
72
73
    /**
74
     * {@inheritdoc}
75
     */
76 4
    public function result(NodeList $nodeList) {
77 4
        return $nodeList;
78
    }
79
80
    /**
81
     * @return NodeList
82
     */
83 65
    public function reverse(): NodeList {
84 65
        array_reverse($this->nodes);
85
86 65
        return $this;
87
    }
88
89
    /**
90
     * @return mixed
91
     */
92 121
    public function first() {
93 121
        return !empty($this->nodes) ? $this->rewind() : null;
94
    }
95
96
    /**
97
     * @return mixed
98
     */
99 2
    public function last() {
100 2
        return $this->end();
101
    }
102
103
    /**
104
     * @return mixed
105
     */
106 2
    public function end() {
107 2
        return !empty($this->nodes) ? end($this->nodes) : null;
108
    }
109
110
    /**
111
     * @param int $key
112
     *
113
     * @return mixed
114
     */
115
    public function get(int $key) {
116
        if (isset($this->nodes[$key])) {
117
            return $this->nodes[$key];
118
        }
119
120
        return null;
121
    }
122
123
    /**
124
     * @param int $key
125
     * @param mixed $value
126
     *
127
     * @return self
128
     */
129
    public function set(int $key, $value): self {
130
        $this->nodes[$key] = $value;
131
132
        return $this;
133
    }
134
135
    /**
136
     * @param callable $function
137
     *
138
     * @return self
139
     */
140 111
    public function each(callable $function): self {
141 111
        foreach ($this->nodes as $index => $node) {
142 101
            $result = $function($node, $index);
143
144 101
            if ($result === false) {
145 101
                break;
146
            }
147
        }
148
149 111
        return $this;
150
    }
151
152
    /**
153
     * @param callable $function
154
     *
155
     * @return NodeList
156
     */
157 18
    public function map(callable $function): NodeList {
158 18
        $nodes = $this->newNodeList();
159
160 18
        foreach ($this->nodes as $node) {
161 18
            $result = $function($node);
162
163 18
            if (!is_null($result) && $result !== false) {
164 18
                $nodes[] = $result;
165
            }
166
        }
167
168 18
        return $nodes;
169
    }
170
171
    /**
172
     * @param callable $function
173
     * @param mixed|null $initial
174
     *
175
     * @return iterable
176
     */
177 107
    public function reduce(callable $function, $initial = null) {
178 107
        return array_reduce($this->nodes, $function, $initial);
179
    }
180
181
    /**
182
     * @return iterable
183
     */
184 130
    public function toArray() {
185 130
        return $this->nodes;
186
    }
187
188
    /**
189
     * @param iterable $nodes
190
     */
191 40
    public function fromArray(iterable $nodes = null) {
192 40
        if (!is_iterable($nodes)) {
193
            $nodes = [];
194
        }
195
196 40
        $this->nodes = $nodes;
0 ignored issues
show
Documentation Bug introduced by
It seems like $nodes can also be of type object<DOMWrap\iterable> or array. However, the property $nodes is declared as type object<DOMWrap\Collections\iterable>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
197 40
    }
198
199
    /**
200
     * @param NodeList|array $elements
201
     *
202
     * @return NodeList
203
     */
204 130
    public function merge($elements = []): NodeList {
205 130
        if (!is_array($elements)) {
206 130
            $elements = $elements->toArray();
207
        }
208
209 130
        return $this->newNodeList(array_merge($this->toArray(), $elements));
0 ignored issues
show
Documentation introduced by
array_merge($this->toArray(), $elements) is of type array, but the function expects a object<DOMWrap\Traits\iterable>|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
210
    }
211
212
    /**
213
     * @param int $start
214
     * @param int $end
215
     *
216
     * @return NodeList
217
     */
218
    public function slice(int $start, int $end = null): NodeList {
219
        $nodeList = array_slice($this->toArray(), $start, $end);
220
221
        return $this->newNodeList($nodeList);
0 ignored issues
show
Documentation introduced by
$nodeList is of type array, but the function expects a object<DOMWrap\Traits\iterable>|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
222
    }
223
224
    /**
225
     * @param \DOMNode $node
226
     *
227
     * @return self
228
     */
229
    public function push(\DOMNode $node): self {
230
        $this->nodes[] = $node;
231
232
        return $this;
233
    }
234
235
    /**
236
     * @return \DOMNode
237
     */
238
    public function pop(): \DOMNode {
239
        return array_pop($this->nodes);
240
    }
241
242
    /**
243
     * @param \DOMNode $node
244
     *
245
     * @return self
246
     */
247 1
    public function unshift(\DOMNode $node): self {
248 1
        array_unshift($this->nodes, $node);
249
250 1
        return $this;
251
    }
252
253
    /**
254
     * @return \DOMNode
255
     */
256
    public function shift(): \DOMNode {
257
        return array_shift($this->nodes);
258
    }
259
260
    /**
261
     * @param \DOMNode $node
262
     *
263
     * @return bool
264
     */
265 66
    public function exists(\DOMNode $node): bool {
266 66
        return in_array($node, $this->nodes, true);
267
    }
268
269
    /**
270
     * @param \DOMNode $node
271
     *
272
     * @return self
273
     */
274
    public function delete(\DOMNode $node): self {
275
        $index = array_search($node, $this->nodes, true);
276
277
        if ($index !== false) {
278
            unset($this->nodes[$index]);
279
        }
280
281
        return $this;
282
    }
283
284
    /**
285
     * @return bool
286
     */
287 23
    public function isRemoved(): bool {
288 23
        return false;
289
    }
290
}