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

TraversalTrait::getNodesMatchingInput()   B

Complexity

Conditions 6
Paths 4

Size

Total Lines 34
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 6.0052

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 34
ccs 18
cts 19
cp 0.9474
rs 8.439
cc 6
eloc 17
nc 4
nop 2
crap 6.0052
1
<?php declare(strict_types=1);
2
3
namespace DOMWrap\Traits;
4
5
use DOMWrap\{
6
    Element,
7
    NodeList
8
};
9
use Symfony\Component\CssSelector\CssSelectorConverter;
10
11
/**
12
 * Traversal Trait
13
 *
14
 * @package DOMWrap\Traits
15
 * @license http://opensource.org/licenses/BSD-3-Clause BSD 3 Clause
16
 */
17
trait TraversalTrait
18
{
19
    /**
20
     * @param iterable $nodes
21
     *
22
     * @return NodeList
23
     */
24 138
    public function newNodeList(iterable $nodes = null): NodeList {
25
26 138
        if (!is_iterable($nodes)) {
27 134
            if (!is_null($nodes)) {
28
                $nodes = [$nodes];
29
            } else {
30 134
                $nodes = [];
31
            }
32
        }
33
34 138
        return new NodeList($this->document(), $nodes);
0 ignored issues
show
Bug introduced by
It seems like document() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
Bug introduced by
It seems like $nodes can also be of type array; however, DOMWrap\NodeList::__construct() does only seem to accept object<DOMWrap\iterable>|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
35
    }
36
37
    /**
38
     * @param string $selector
39
     * @param string $prefix
40
     *
41
     * @return NodeList
42
     */
43 130
    public function find(string $selector, string $prefix = 'descendant::'): NodeList {
44 130
        $converter = new CssSelectorConverter();
45
46 130
        return $this->findXPath($converter->toXPath($selector, $prefix));
47
    }
48
49
    /**
50
     * @param string $xpath
51
     *
52
     * @return NodeList
53
     */
54 130
    public function findXPath(string $xpath): NodeList {
55 130
        $results = $this->newNodeList();
56
57 130
        if ($this->isRemoved()) {
0 ignored issues
show
Bug introduced by
It seems like isRemoved() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
58
            return $results;
59
        }
60
61 130
        $domxpath = new \DOMXPath($this->document());
0 ignored issues
show
Bug introduced by
It seems like document() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
62
63 130
        foreach ($this->collection() as $node) {
0 ignored issues
show
Bug introduced by
It seems like collection() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
64 130
            $results = $results->merge(
65 130
                $node->newNodeList($domxpath->query($xpath, $node))
66
            );
67
        }
68
69 130
        return $results;
70
    }
71
72
    /**
73
     * @param string|NodeList|\DOMNode|callable $input
74
     * @param bool $matchType
75
     *
76
     * @return NodeList
77
     */
78 18
    protected function getNodesMatchingInput($input, bool $matchType = true): NodeList {
79 18
        if ($input instanceof NodeList || $input instanceof \DOMNode) {
80 8
            $inputNodes = $this->inputAsNodeList($input);
0 ignored issues
show
Bug introduced by
It seems like inputAsNodeList() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
81
82 8
            $fn = function($node) use ($inputNodes) {
83 8
                return $inputNodes->exists($node);
84 8
            };
85
86
87 11
        } elseif (is_callable($input)) {
88
            // Since we're at the behest of the input callable, the 'matched'
89
            //  return value is always true.
90 2
            $matchType = true;
91
92 2
            $fn = $input;
93
94 10
        } elseif (is_string($input)) {
95 10
            $fn = function($node) use ($input) {
96 10
                return $node->find($input, 'self::')->count() != 0;
97 10
            };
98
99
        } else {
100
            throw new \InvalidArgumentException('Unexpected input value of type "' . gettype($input) . '"');
101
        }
102
103
        // Build a list of matching nodes.
104 18
        return $this->collection()->map(function($node) use ($fn, $matchType) {
0 ignored issues
show
Bug introduced by
It seems like collection() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
105 18
            if ($fn($node) !== $matchType) {
106 17
                return null;
107
            }
108
109 18
            return $node;
110 18
        });
111
    }
112
113
    /**
114
     * @param string|NodeList|\DOMNode|callable $input
115
     *
116
     * @return bool
117
     */
118 15
    public function is($input): bool {
119 15
        return $this->getNodesMatchingInput($input)->count() != 0;
120
    }
121
122
    /**
123
     * @param string|NodeList|\DOMNode|callable $input
124
     *
125
     * @return NodeList
126
     */
127 1
    public function not($input): NodeList {
128 1
        return $this->getNodesMatchingInput($input, false);
129
    }
130
131
    /**
132
     * @param string|NodeList|\DOMNode|callable $input
133
     *
134
     * @return NodeList
135
     */
136 1
    public function filter($input): NodeList {
137 1
        return $this->getNodesMatchingInput($input);
138
    }
139
140
    /**
141
     * @param string|NodeList|\DOMNode|callable $input
142
     *
143
     * @return NodeList
144
     */
145 1
    public function has($input): NodeList {
146 1
        if ($input instanceof NodeList || $input instanceof \DOMNode) {
147 1
            $inputNodes = $this->inputAsNodeList($input);
0 ignored issues
show
Bug introduced by
It seems like inputAsNodeList() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
148
149 1
            $fn = function($node) use ($inputNodes) {
150 1
                $descendantNodes = $node->find('*', 'descendant::');
151
152
                // Determine if we have a descendant match.
153 1
                return $inputNodes->reduce(function($carry, $inputNode) use ($descendantNodes) {
154
                    // Match descendant nodes against input nodes.
155 1
                    if ($descendantNodes->exists($inputNode)) {
156 1
                        return true;
157
                    }
158
159
                    return $carry;
160 1
                }, false);
161 1
            };
162
163 1
        } elseif (is_string($input)) {
164 1
            $fn = function($node) use ($input) {
165 1
                return $node->find($input, 'descendant::')->count() != 0;
166 1
            };
167
168
        } elseif (is_callable($input)) {
169
            $fn = $input;
170
171
        } else {
172
            throw new \InvalidArgumentException('Unexpected input value of type "' . gettype($input) . '"');
173
        }
174
175 1
        return $this->getNodesMatchingInput($fn);
176
    }
177
178
    /**
179
     * @param string|NodeList|\DOMNode|callable $selector
180
     *
181
     * @return \DOMNode|null
182
     */
183
    public function preceding($selector = null): ?\DOMNode {
184
        return $this->precedingUntil(null, $selector)->first();
185
    }
186
187
    /**
188
     * @param string|NodeList|\DOMNode|callable $selector
189
     *
190
     * @return NodeList
191
     */
192 21
    public function precedingAll($selector = null): NodeList {
193 21
        return $this->precedingUntil(null, $selector);
194
    }
195
196
    /**
197
     * @param string|NodeList|\DOMNode|callable $input
198
     * @param string|NodeList|\DOMNode|callable $selector
199
     *
200
     * @return NodeList
201
     */
202 32
    public function precedingUntil($input = null, $selector = null): NodeList {
203 32
        return $this->_walkPathUntil('previousSibling', $input, $selector);
204
    }
205
206
    /**
207
     * @param string|NodeList|\DOMNode|callable $selector
208
     *
209
     * @return \DOMNode|null
210
     */
211 12
    public function following($selector = null): ?\DOMNode {
212 12
        return $this->followingUntil(null, $selector)->first();
213
    }
214
215
    /**
216
     * @param string|NodeList|\DOMNode|callable $selector
217
     *
218
     * @return NodeList
219
     */
220 21
    public function followingAll($selector = null): NodeList {
221 21
        return $this->followingUntil(null, $selector);
222
    }
223
224
    /**
225
     * @param string|NodeList|\DOMNode|callable $input
226
     * @param string|NodeList|\DOMNode|callable $selector
227
     *
228
     * @return NodeList
229
     */
230 25
    public function followingUntil($input = null, $selector = null): NodeList {
231 25
        return $this->_walkPathUntil('nextSibling', $input, $selector);
232
    }
233
234
    /**
235
     * @param string|NodeList|\DOMNode|callable $selector
236
     *
237
     * @return NodeList
238
     */
239
    public function siblings($selector = null): NodeList {
240 21
        $results = $this->collection()->reduce(function($carry, $node) use ($selector) {
0 ignored issues
show
Bug introduced by
It seems like collection() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
241 21
            return $carry->merge(
242 21
                $node->precedingAll($selector)->merge(
243 21
                    $node->followingAll($selector)
244
                )
245
            );
246 21
        }, $this->newNodeList());
247
248 21
        return $results;
249
    }
250
251
    /**
252
     * NodeList is only array like. Removing items using foreach() has undesired results.
253
     *
254
     * @return NodeList
255
     */
256
    public function children(): NodeList {
257 93
        $results = $this->collection()->reduce(function($carry, $node) {
0 ignored issues
show
Bug introduced by
It seems like collection() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
258 93
            return $carry->merge(
259 93
                $node->findXPath('child::*')
260
            );
261 93
        }, $this->newNodeList());
262
263 93
        return $results;
264
    }
265
266
    /**
267
     * @param string|NodeList|\DOMNode|callable $selector
268
     *
269
     * @return Element|NodeList|null
270
     */
271 51
    public function parent($selector = null) {
272 51
        $results = $this->_walkPathUntil('parentNode', null, $selector, self::$MATCH_TYPE_FIRST);
273
274 51
        return $this->result($results);
0 ignored issues
show
Bug introduced by
It seems like result() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
275
    }
276
277
    /**
278
     * @param int $index
279
     *
280
     * @return \DOMNode|null
281
     */
282 2
    public function eq(int $index): ?\DOMNode {
283 2
        if ($index < 0) {
284 1
            $index = $this->collection()->count() + $index;
0 ignored issues
show
Bug introduced by
It seems like collection() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
285
        }
286
287 2
        return $this->collection()->offsetGet($index);
0 ignored issues
show
Bug introduced by
It seems like collection() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
288
    }
289
290
    /**
291
     * @param string $selector
292
     *
293
     * @return NodeList
294
     */
295
    public function parents(string $selector = null): NodeList {
296
        return $this->parentsUntil(null, $selector);
297
    }
298
299
    /**
300
     * @param string|NodeList|\DOMNode|callable $input
301
     * @param string|NodeList|\DOMNode|callable $selector
302
     *
303
     * @return NodeList
304
     */
305
    public function parentsUntil($input = null, $selector = null): NodeList {
306
        return $this->_walkPathUntil('parentNode', $input, $selector);
307
    }
308
309
    /**
310
     * @return \DOMNode
311
     */
312
    public function intersect(): \DOMNode {
313
        if ($this->collection()->count() < 2) {
0 ignored issues
show
Bug introduced by
It seems like collection() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
314
            return $this->collection()->first();
0 ignored issues
show
Bug introduced by
It seems like collection() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
315
        }
316
317
        $nodeParents = [];
318
319
        // Build a multi-dimensional array of the collection nodes parent elements
320
        $this->collection()->each(function($node) use(&$nodeParents) {
0 ignored issues
show
Bug introduced by
It seems like collection() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
321
            $nodeParents[] = $node->parents()->unshift($node)->toArray();
322
        });
323
324
        // Find the common parent
325
        $diff = call_user_func_array('array_uintersect', array_merge($nodeParents, [function($a, $b) {
326
            return strcmp(spl_object_hash($a), spl_object_hash($b));
327
        }]));
328
329
        return array_shift($diff);
330
    }
331
332
    /**
333
     * @param string|NodeList|\DOMNode|callable $input
334
     *
335
     * @return Element|NodeList|null
336
     */
337 3
    public function closest($input) {
338 3
        $results = $this->_walkPathUntil('parentNode', $input, null, self::$MATCH_TYPE_LAST);
339
340 3
        return $this->result($results);
0 ignored issues
show
Bug introduced by
It seems like result() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
341
    }
342
343
    /**
344
     * NodeList is only array like. Removing items using foreach() has undesired results.
345
     *
346
     * @return NodeList
347
     */
348
    public function contents(): NodeList {
349 26
        $results = $this->collection()->reduce(function($carry, $node) {
0 ignored issues
show
Bug introduced by
It seems like collection() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
350 26
            if($node->isRemoved())
351
                return $this->newNodeList();
352 26
            return $carry->merge(
353 26
                $node->newNodeList($node->childNodes)
354
            );
355 26
        }, $this->newNodeList());
356
357 26
        return $results;
358
    }
359
360
    /**
361
     * @param string|NodeList|\DOMNode $input
362
     *
363
     * @return NodeList
364
     */
365
    public function add($input): NodeList {
366
        $nodes = $this->inputAsNodeList($input);
0 ignored issues
show
Bug introduced by
It seems like inputAsNodeList() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
367
368
        $results = $this->collection()->merge(
0 ignored issues
show
Bug introduced by
It seems like collection() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
369
            $nodes
370
        );
371
372
        return $results;
373
    }
374
375
    /** @var int */
376
    private static $MATCH_TYPE_FIRST = 1;
377
378
    /** @var int */
379
    private static $MATCH_TYPE_LAST = 2;
380
381
    /**
382
     * @param \DOMNode $baseNode
383
     * @param string $property
384
     * @param string|NodeList|\DOMNode|callable $input
385
     * @param string|NodeList|\DOMNode|callable $selector
386
     * @param int $matchType
387
     *
388
     * @return NodeList
389
     */
390 65
    protected function _buildNodeListUntil(\DOMNode $baseNode, string $property, $input = null, $selector = null, int $matchType = null): NodeList {
391 65
        $resultNodes = $this->newNodeList();
392
393
        // Get our first node
394 65
        $node = $baseNode->$property;
395
396
        // Keep looping until we're either out of nodes, or at the root of the DOM.
397 65
        while ($node instanceof \DOMNode && !($node instanceof \DOMDocument)) {
398
            // Filter nodes if not matching last
399 64
            if ($matchType != self::$MATCH_TYPE_LAST && (is_null($selector) || $node->is($selector))) {
400 61
                $resultNodes[] = $node;
401
            }
402
403
            // 'Until' check or first match only
404 64
            if ($matchType == self::$MATCH_TYPE_FIRST || (!is_null($input) && $node->is($input))) {
405
                // Set last match
406 60
                if ($matchType == self::$MATCH_TYPE_LAST) {
407 2
                    $resultNodes[] = $node;
408
                }
409
410 60
                break;
411
            }
412
413
            // Find the next node
414 21
            $node = $node->{$property};
415
        }
416
417 65
        return $resultNodes;
418
    }
419
420
    /**
421
     * @param iterable $nodeLists
422
     *
423
     * @return NodeList
424
     */
425 65
    protected function _uniqueNodes(iterable $nodeLists): NodeList {
426 65
        $resultNodes = $this->newNodeList();
427
428
        // Loop through our array of NodeLists
429 65
        foreach ($nodeLists as $nodeList) {
430
            // Each node in the NodeList
431 65
            foreach ($nodeList as $node) {
432
                // We're only interested in unique nodes
433 63
                if (!$resultNodes->exists($node)) {
434 65
                    $resultNodes[] = $node;
435
                }
436
            }
437
        }
438
439
        // Sort resulting NodeList: outer-most => inner-most.
440 65
        return $resultNodes->reverse();
441
    }
442
443
    /**
444
     * @param string $property
445
     * @param string|NodeList|\DOMNode|callable $input
446
     * @param string|NodeList|\DOMNode|callable $selector
447
     * @param int $matchType
448
     *
449
     * @return NodeList
450
     */
451 65
    protected function _walkPathUntil(string $property, $input = null, $selector = null, int $matchType = null): NodeList {
452 65
        $nodeLists = [];
453
454 65
        $this->collection()->each(function($node) use($property, $input, $selector, $matchType, &$nodeLists) {
0 ignored issues
show
Bug introduced by
It seems like collection() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
455 65
            $nodeLists[] = $this->_buildNodeListUntil($node, $property, $input, $selector, $matchType);
456 65
        });
457
458 65
        return $this->_uniqueNodes($nodeLists);
0 ignored issues
show
Documentation introduced by
$nodeLists is of type array, but the function expects a object<DOMWrap\Traits\iterable>.

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...
459
    }
460
}