Parser::parseSelectorString()   F
last analyzed

Complexity

Conditions 18
Paths 770

Size

Total Lines 88
Code Lines 54

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 54
CRAP Score 18

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 18
eloc 54
c 1
b 0
f 0
nc 770
nop 1
dl 0
loc 88
ccs 54
cts 54
cp 1
crap 18
rs 1.0194

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace PHPHtmlParser\Selector;
6
7
use PHPHtmlParser\Contracts\Selector\ParserInterface;
8
use PHPHtmlParser\DTO\Selector\ParsedSelectorCollectionDTO;
9
use PHPHtmlParser\DTO\Selector\ParsedSelectorDTO;
10
use PHPHtmlParser\DTO\Selector\RuleDTO;
11
12
/**
13
 * This is the default parser for the selector.
14
 */
15
class Parser implements ParserInterface
16
{
17
    /**
18
     * Pattern of CSS selectors, modified from 'mootools'.
19
     *
20
     * @var string
21
     */
22
    private $pattern = "/([\w\-:\*>]*)(?:\#([\w\-]+)|\.([\w\.\-]+))?(?:\[@?(!?[\w\-:]+)(?:([!*^$]?=)[\"']?(.*?)[\"']?)?\])?([\/, ]+)/is";
23
24
    /**
25
     * Parses the selector string.
26
     */
27 351
    public function parseSelectorString(string $selector): ParsedSelectorCollectionDTO
28
    {
29 351
        $selectors = [];
30 351
        $matches = [];
31 351
        $rules = [];
32 351
        \preg_match_all($this->pattern, \trim($selector) . ' ', $matches, PREG_SET_ORDER);
33
34
        // skip tbody
35 351
        foreach ($matches as $match) {
36
            // default values
37 351
            $tag = \strtolower(\trim($match[1]));
38 351
            $operator = '=';
39 351
            $key = null;
40 351
            $value = null;
41 351
            $noKey = false;
42 351
            $alterNext = false;
43
44
            // check for elements that alter the behavior of the next element
45 351
            if ($tag == '>') {
46 3
                $alterNext = true;
47
            }
48
49
            // check for id selector
50 351
            if (!empty($match[2])) {
51 21
                $key = 'id';
52 21
                $value = $match[2];
53
            }
54
55
            // check for class selector
56 351
            if (!empty($match[3])) {
57 57
                $key = 'class';
58 57
                $value = \explode('.', $match[3]);
59
            }
60
61
            // and final attribute selector
62 351
            if (!empty($match[4])) {
63 300
                $key = \strtolower($match[4]);
64
            }
65 351
            if (!empty($match[5])) {
66 291
                $operator = $match[5];
67
            }
68 351
            if (!empty($match[6])) {
69 291
                $value = $match[6];
70 291
                if (\strpos($value, '][') !== false) {
71
                    // we have multiple type selectors
72 3
                    $keys = [];
73 3
                    $keys[] = $key;
74 3
                    $key = $keys;
75 3
                    $parts = \explode('][', $value);
76 3
                    $value = [];
77 3
                    foreach ($parts as $part) {
78 3
                        if (\strpos($part, '=') !== false) {
79 3
                            list($first, $second) = \explode('=', $part);
80 3
                            $key[] = $first;
81 3
                            $value[] = $second;
82
                        } else {
83 3
                            $value[] = $part;
84
                        }
85
                    }
86
                }
87
            }
88
89
            // check for elements that do not have a specified attribute
90 351
            if (\is_string($key) && isset($key[0]) && $key[0] == '!') {
91 3
                $key = \substr($key, 1);
92 3
                $noKey = true;
93
            }
94
95 351
            $rules[] = RuleDTO::makeFromPrimitives(
96 351
                $tag,
97 234
                $operator,
98 234
                $key,
99 234
                $value,
100 234
                $noKey,
101 234
                $alterNext
102
            );
103 351
            if (isset($match[7]) && \is_string($match[7]) && \trim($match[7]) == ',') {
104 3
                $selectors[] = ParsedSelectorDTO::makeFromRules($rules);
105 3
                $rules = [];
106
            }
107
        }
108
109
        // save last results
110 351
        if (\count($rules) > 0) {
111 351
            $selectors[] = ParsedSelectorDTO::makeFromRules($rules);
112
        }
113
114 351
        return ParsedSelectorCollectionDTO::makeCollection($selectors);
115
    }
116
}
117