Completed
Branch scrutinizer (fbaa3d)
by Thomas
02:21
created

HtmlQuery   B

Complexity

Total Complexity 48

Size/Duplication

Total Lines 526
Duplicated Lines 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
eloc 99
c 2
b 1
f 0
dl 0
loc 526
rs 8.5599
wmc 48

32 Methods

Rating   Name   Duplication   Size   Complexity  
A removeData() 0 3 1
A remove() 0 11 2
A val() 0 7 2
A hasData() 0 3 1
A empty() 0 4 1
A html() 0 7 2
A text() 0 7 2
A setHtml() 0 9 2
A __construct() 0 4 1
A prop() 0 3 1
A attr() 0 15 4
A setText() 0 4 1
A outerHtml() 0 4 1
A getText() 0 4 1
A setAttr() 0 4 1
A hasAttr() 0 5 1
A removeProp() 0 3 1
A removeAllAttrs() 0 4 1
A removeAttr() 0 4 1
A getHtml() 0 4 1
A getAttr() 0 4 1
A setCss() 0 4 1
A getCss() 0 4 1
A hasClass() 0 5 1
A setVal() 0 4 1
A removeClass() 0 4 1
A toggleClass() 0 4 1
A addClass() 0 4 1
A removeCss() 0 4 1
A css() 0 15 5
A data() 0 28 5
A getVal() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like HtmlQuery often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use HtmlQuery, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Sulao\HtmlQuery;
4
5
use DOMDocument, DOMNode, DOMNodeList;
6
7
/**
8
 * Class HtmlQuery
9
 *
10
 * @package Sulao\HtmlQuery
11
 */
12
class HtmlQuery extends HtmlQueryNode
13
{
14
    const VERSION = '1.0.0';
15
16
    /**
17
     * @var DOMDocument
18
     */
19
    protected $doc;
20
21
    /**
22
     * @var DOMNode[]
23
     */
24
    protected $nodes;
25
26
    /**
27
     * HtmlQuery constructor.
28
     *
29
     * @param DOMDocument                   $doc
30
     * @param DOMNode|DOMNode[]|DOMNodeList $nodes
31
     *
32
     * @throws Exception
33
     */
34
    public function __construct(DOMDocument $doc, $nodes)
35
    {
36
        $this->doc = $doc;
37
        $this->nodes = $this->validateNodes($nodes);
38
    }
39
40
    /**
41
     * Get the outer HTML contents of the first matched node.
42
     *
43
     * @return string|null
44
     */
45
    public function outerHtml()
46
    {
47
        return $this->mapFirst(function (HtmlNode $node) {
48
            return $node->outerHtml();
49
        });
50
    }
51
52
    /**
53
     * Get the inner HTML contents of the first matched node or
54
     * set the inner HTML contents of every matched node.
55
     *
56
     * @param string|null $html
57
     *
58
     * @return string|null|static
59
     */
60
    public function html(?string $html = null)
61
    {
62
        if (!is_null($html)) {
63
            return $this->setHtml($html);
64
        }
65
66
        return $this->getHtml();
67
    }
68
69
    /**
70
     * Get the inner HTML contents of the first matched node.
71
     *
72
     * @return string|null
73
     */
74
    public function getHtml()
75
    {
76
        return $this->mapFirst(function (HtmlNode $node) {
77
            return $node->getHtml();
78
        });
79
    }
80
81
    /**
82
     * Set the inner HTML contents of every matched node.
83
     *
84
     * @param string $html
85
     *
86
     * @return static
87
     */
88
    public function setHtml(string $html)
89
    {
90
        $this->empty();
91
92
        if ($html !== '') {
93
            $this->append($html);
94
        }
95
96
        return $this;
97
    }
98
99
    /**
100
     * Get the combined text contents of the first matched node, including
101
     * it's descendants, or set the text contents of every matched node.
102
     *
103
     * @param string|null $text
104
     *
105
     * @return string|null|static
106
     */
107
    public function text(?string $text = null)
108
    {
109
        if (!is_null($text)) {
110
            return $this->setText($text);
111
        }
112
113
        return $this->getText();
114
    }
115
116
    /**
117
     * Get the combined text contents of the first matched node,
118
     * including it's descendants.
119
     *
120
     * @return string|null
121
     */
122
    public function getText()
123
    {
124
        return $this->mapFirst(function (HtmlNode $node) {
125
            return $node->getText();
126
        });
127
    }
128
129
    /**
130
     * set the text contents of every matched node.
131
     *
132
     * @param string $text
133
     *
134
     * @return static
135
     */
136
    public function setText(string $text)
137
    {
138
        return $this->each(function (HtmlNode $node) use ($text) {
139
            $node->setText($text);
140
        });
141
    }
142
143
    /**
144
     * Get the value of an attribute for the first matched node
145
     * or set one or more attributes for every matched node.
146
     *
147
     * @param string|array $name
148
     * @param string|null  $value
149
     *
150
     * @return static|mixed|null
151
     */
152
    public function attr($name, $value = null)
153
    {
154
        if (is_array($name)) {
155
            foreach ($name as $key => $val) {
156
                $this->setAttr($key, $val);
157
            }
158
159
            return $this;
160
        }
161
162
        if (!is_null($value)) {
163
            return $this->setAttr($name, $value);
164
        }
165
166
        return $this->getAttr($name);
167
    }
168
169
    /**
170
     * Get the value of an attribute for the first matched node
171
     *
172
     * @param string $name
173
     *
174
     * @return string|null
175
     */
176
    public function getAttr(string $name)
177
    {
178
        return $this->mapFirst(function (HtmlElement $node) use ($name) {
179
            return $node->getAttr($name);
180
        });
181
    }
182
183
    /**
184
     * Set one or more attributes for every matched node.
185
     *
186
     * @param string $name
187
     * @param string $value
188
     *
189
     * @return static
190
     */
191
    public function setAttr(string $name, string $value)
192
    {
193
        return $this->each(function (HtmlElement $node) use ($name, $value) {
194
            $node->setAttr($name, $value);
195
        });
196
    }
197
198
    /**
199
     * Remove an attribute from every matched nodes.
200
     *
201
     * @param string $attributeName
202
     *
203
     * @return static
204
     */
205
    public function removeAttr(string $attributeName)
206
    {
207
        return $this->each(function (HtmlElement $node) use ($attributeName) {
208
            $node->removeAttr($attributeName);
209
        });
210
    }
211
212
    /**
213
     * Remove all attributes from every matched nodes except the specified ones.
214
     *
215
     * @param string|array $except The attribute name(s) that won't be removed
216
     *
217
     * @return static
218
     */
219
    public function removeAllAttrs($except = [])
220
    {
221
        return $this->each(function (HtmlElement $node) use ($except) {
222
            $node->removeAllAttrs($except);
223
        });
224
    }
225
226
    /**
227
     * Determine whether any of the nodes have the given attribute.
228
     *
229
     * @param string $attributeName
230
     *
231
     * @return bool
232
     */
233
    public function hasAttr(string $attributeName)
234
    {
235
        return $this->mapAnyTrue(
236
            function (HtmlElement $node) use ($attributeName) {
237
                return $node->hasAttr($attributeName);
238
            }
239
        );
240
    }
241
242
    /**
243
     * Alias of attr
244
     *
245
     * @param string|array $name
246
     * @param string|null  $value
247
     *
248
     * @return static|mixed|null
249
     */
250
    public function prop($name, $value = null)
251
    {
252
        return $this->attr($name, $value);
253
    }
254
255
    /**
256
     * Alias of removeAttr
257
     *
258
     * @param string $attributeName
259
     *
260
     * @return static
261
     */
262
    public function removeProp(string $attributeName)
263
    {
264
        return $this->removeAttr($attributeName);
265
    }
266
267
    /**
268
     * Get the value of an attribute with prefix data- for the first matched
269
     * node, if the value is valid json string, returns the value encoded in
270
     * json in appropriate PHP type
271
     *
272
     * or set one or more attributes with prefix data- for every matched node.
273
     *
274
     * @param string|array $name
275
     * @param string|array|null  $value
276
     *
277
     * @return static|mixed|null
278
     */
279
    public function data($name, $value = null)
280
    {
281
        if (is_array($name)) {
282
            array_walk($name, function ($val, $key) {
283
                $this->data($key, $val);
284
            });
285
286
            return $this;
287
        }
288
289
        $name = 'data-' . $name;
290
291
        if (is_null($value)) {
292
            $result = $this->getAttr($name);
293
294
            $json = json_decode($result);
295
            if (json_last_error() === JSON_ERROR_NONE) {
296
                return $json;
297
            }
298
299
            return $result;
300
        }
301
302
        if (is_array($value)) {
303
            $value = (string) json_encode($value);
304
        }
305
306
        return $this->setAttr($name, $value);
307
    }
308
309
    /**
310
     * Determine whether any of the nodes have the given attribute
311
     * prefix with data-.
312
     *
313
     * @param string $name
314
     *
315
     * @return bool
316
     */
317
    public function hasData(string $name)
318
    {
319
        return $this->hasAttr('data-' . $name);
320
    }
321
322
    /**
323
     * Remove an attribute prefix with data- from every matched nodes.
324
     *
325
     * @param string $name
326
     *
327
     * @return static
328
     */
329
    public function removeData(string $name)
330
    {
331
        return $this->removeAttr('data-' . $name);
332
    }
333
334
    /**
335
     * Remove all child nodes of all matched nodes from the DOM.
336
     *
337
     * @return static
338
     */
339
    public function empty()
340
    {
341
        return $this->each(function (HtmlNode $node) {
342
            $node->empty();
343
        });
344
    }
345
346
    /**
347
     * Remove the matched nodes from the DOM.
348
     * optionally filtered by a selector.
349
     *
350
     * @param string|null $selector
351
     *
352
     * @return static
353
     */
354
    public function remove(?string $selector = null)
355
    {
356
        if (!is_null($selector)) {
357
            $this->filter($selector)->remove();
358
        } else {
359
            $this->each(function (HtmlNode $node) {
360
                $node->remove();
361
            });
362
        }
363
364
        return $this;
365
    }
366
367
    /**
368
     * Get the current value of the first matched node
369
     * or set the value of every matched node.
370
     *
371
     * @param string|null $value
372
     *
373
     * @return string|null|static
374
     */
375
    public function val(?string $value = null)
376
    {
377
        if (is_null($value)) {
378
            return $this->getVal();
379
        }
380
381
        return $this->setVal($value);
382
    }
383
384
    /**
385
     * Get the current value of the first matched node
386
     *
387
     * @return string|null
388
     */
389
    public function getVal()
390
    {
391
        return $this->mapFirst(function (HtmlElement $node) {
392
            return $node->getVal();
393
        });
394
    }
395
396
    /**
397
     * Set the value of every matched node.
398
     *
399
     * @param string $value
400
     *
401
     * @return static
402
     */
403
    public function setVal(string $value)
404
    {
405
        return $this->each(function (HtmlElement $node) use ($value) {
406
            $node->setVal($value);
407
        });
408
    }
409
410
    /**
411
     * Adds the specified class(es) to each node in the matched nodes.
412
     *
413
     * @param string $className
414
     *
415
     * @return static
416
     */
417
    public function addClass(string $className)
418
    {
419
        return $this->each(function (HtmlElement $node) use ($className) {
420
            $node->addClass($className);
421
        });
422
    }
423
424
    /**
425
     * Determine whether any of the matched nodes are assigned the given class.
426
     *
427
     * @param string $className
428
     *
429
     * @return bool
430
     */
431
    public function hasClass(string $className)
432
    {
433
        return $this->mapAnyTrue(
434
            function (HtmlElement $node) use ($className) {
435
                return $node->hasClass($className);
436
            }
437
        );
438
    }
439
440
    /**
441
     * Remove a single class, multiple classes, or all classes
442
     * from each matched node.
443
     *
444
     * @param string|null $className
445
     *
446
     * @return static
447
     */
448
    public function removeClass(?string $className = null)
449
    {
450
        return $this->each(function (HtmlElement $node) use ($className) {
451
            $node->removeClass($className);
452
        });
453
    }
454
455
    /**
456
     * Add or remove class(es) from each matched node, depending on
457
     * either the class's presence or the value of the state argument.
458
     *
459
     * @param string $className
460
     * @param bool|null   $state
461
     *
462
     * @return static
463
     */
464
    public function toggleClass(string $className, ?bool $state = null)
465
    {
466
        return $this->each(function (HtmlElement $node) use ($className, $state) {
467
            $node->toggleClass($className, $state);
468
        });
469
    }
470
471
    /**
472
     * Get the value of a computed style property for the first matched node
473
     * or set one or more CSS properties for every matched node.
474
     *
475
     * @param string|array $name
476
     * @param string|null  $value
477
     *
478
     * @return static|string|null
479
     */
480
    public function css($name, $value = null)
481
    {
482
        if (is_null($value) && !is_array($name)) {
483
            return $this->getCss($name);
484
        }
485
486
        if (is_array($name)) {
487
            foreach ($name as $key => $val) {
488
                $this->setCss($key, $val);
489
            }
490
        } else {
491
            $this->setCss($name, $value);
492
        }
493
494
        return $this;
495
    }
496
497
498
    /**
499
     * Get the value of a computed style property for the first matched node
500
     *
501
     * @param string $name
502
     *
503
     * @return string|null
504
     */
505
    public function getCss(string $name)
506
    {
507
        return $this->mapFirst(function (HtmlElement $node) use ($name) {
508
            return $node->getCss($name);
509
        });
510
    }
511
512
    /**
513
     * Set or Remove one CSS property for every matched node.
514
     *
515
     * @param string      $name
516
     * @param string|null $value
517
     *
518
     * @return static
519
     */
520
    public function setCss(string $name, ?string $value)
521
    {
522
        return $this->each(function (HtmlElement $node) use ($name, $value) {
523
            $node->setCss($name, $value);
524
        });
525
    }
526
527
    /**
528
     * Remove one CSS property for every matched node.
529
     *
530
     * @param string $name
531
     *
532
     * @return static
533
     */
534
    public function removeCss(string $name)
535
    {
536
        return $this->each(function (HtmlElement $node) use ($name) {
537
            $node->removeCss($name);
538
        });
539
    }
540
}
541