Passed
Pull Request — master (#207)
by
unknown
02:09
created

Parser::getInstance()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 0
dl 0
loc 5
ccs 4
cts 4
cp 1
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace PHPHtmlParser\Selector;
6
7
/**
8
 * This is the parser for the selector.
9
 *
10
 * 
11
 */
12
class Parser implements ParserInterface
13
{
14
15
    private static $instance = null;
16
17 315
    public static function getInstance(): Parser {
18 315
        if (is_null(self::$instance)) {
19 3
            self::$instance = new Parser();
20
        }
21 315
        return self::$instance;
22
    }
23
24 3
    private function __construct() {
25
        // use getInstance()
26 3
    }
27
28
    /**
29
     * Pattern of CSS selectors, modified from 'mootools'
30
     *
31
     * @var string
32
     */
33
    protected $pattern = "/([\w\-:\*>]*)(?:\#([\w\-]+)|\.([\w\.\-]+))?(?:\[@?(!?[\w\-:]+)(?:([!*^$]?=)[\"']?(.*?)[\"']?)?\])?([\/, ]+)/is";
34
35
    /**
36
     * Parses the selector string
37
     *
38
     * @param string $selector
39
     *
40
     * @return array
41
     */
42 315
    public function parseSelectorString(string $selector): array
43
    {
44 315
        $selectors = [];
45
46 315
        $matches = [];
47 315
        preg_match_all($this->pattern, trim($selector).' ', $matches, PREG_SET_ORDER);
48
49
        // skip tbody
50 315
        $result = [];
51 315
        foreach ($matches as $match) {
52
            // default values
53 315
            $tag       = strtolower(trim($match[1]));
54 315
            $operator  = '=';
55 315
            $key       = null;
56 315
            $value     = null;
57 315
            $noKey     = false;
58 315
            $alterNext = false;
59
60
            // check for elements that alter the behavior of the next element
61 315
            if ($tag == '>') {
62 3
                $alterNext = true;
63
            }
64
65
            // check for id selector
66 315
            if ( ! empty($match[2])) {
67 21
                $key   = 'id';
68 21
                $value = $match[2];
69
            }
70
71
            // check for class selector
72 315
            if ( ! empty($match[3])) {
73 54
                $key   = 'class';
74 54
                $value = explode('.', $match[3]);
75
            }
76
77
            // and final attribute selector
78 315
            if ( ! empty($match[4])) {
79 255
                $key = strtolower($match[4]);
80
            }
81 315
            if ( ! empty($match[5])) {
82 246
                $operator = $match[5];
83
            }
84 315
            if ( ! empty($match[6])) {
85 246
                $value = $match[6];
86 246
                if (strpos($value, '][') !== false) {
87
                    // we have multiple type selectors
88 3
                    $keys = [];
89 3
                    $keys[] = $key;
90 3
                    $key = $keys;
91 3
                    $parts = explode('][', $value);
92 3
                    $value = [];
93 3
                    foreach ($parts as $part) {
94 3
                        if (strpos($part, '=') !== false) {
95 3
                            list($first, $second) = explode('=', $part);
96 3
                            $key[] = $first;
97 3
                            $value[] = $second;
98
                        } else {
99 3
                            $value[] = $part;
100
                        }
101
                    }
102
                }
103
            }
104
105
            // check for elements that do not have a specified attribute
106 315
            if (is_string($key) && isset($key[0]) && $key[0] == '!') {
107 3
                $key   = substr($key, 1);
108 3
                $noKey = true;
109
            }
110
111 315
            $result[] = [
112 315
                'tag'       => $tag,
113 315
                'key'       => $key,
114 315
                'value'     => $value,
115 315
                'operator'  => $operator,
116 315
                'noKey'     => $noKey,
117 315
                'alterNext' => $alterNext,
118
            ];
119 315
            if (isset($match[7]) && is_string($match[7]) && trim($match[7]) == ',') {
120 3
                $selectors[] = $result;
121 107
                $result      = [];
122
            }
123
        }
124
125
        // save last results
126 315
        if (count($result) > 0) {
127 315
            $selectors[] = $result;
128
        }
129
130 315
        return $selectors;
131
    }
132
}
133