Parser   A
last analyzed

Complexity

Total Complexity 18

Size/Duplication

Total Lines 100
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 56
c 1
b 0
f 0
dl 0
loc 100
ccs 54
cts 54
cp 1
rs 10
wmc 18

1 Method

Rating   Name   Duplication   Size   Complexity  
F parseSelectorString() 0 88 18
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