Passed
Push — master ( 106168...60dab9 )
by Jeroen
01:14
created

CssFilterParser::parseString()   C

Complexity

Conditions 12
Paths 18

Size

Total Lines 58
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 12
eloc 32
nc 18
nop 1
dl 0
loc 58
rs 6.9666
c 0
b 0
f 0

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
namespace Jerodev\Diglett;
4
5
use Jerodev\Diglett\CssFilters\ICssFilter;
6
7
class CssFilterParser {
8
9
    /**
10
     *  The css filters to parse
11
     * 
12
     *  @var array
13
     */
14
    private $cssFilters;
15
16
    /**
17
     *  Create CssFilterParser and set the chosen css filters
18
     * 
19
     *  @param array $cssFilters An array of css filters to use
20
     */
21
    public function __construct(array $cssFilters = [])
22
    {
23
        $this->cssFilters = [];
24
        $this->addCssFilters([
25
            CssFilters\FirstFilter::class,
26
            CssFilters\NthFilter::class
27
        ]);
28
29
        if (!empty($cssFilters))
30
        {
31
            $this->addCssFilters($cssFilters);
32
        }
33
    }
34
35
    /**
36
     *  Add extra css filters
37
     * 
38
     *  @param array|string $cssFilter
39
     */
40
    public function addCssFilters($cssFilter): void 
41
    {
42
        if (is_array($cssFilter))
43
        {
44
            foreach ($cssFilter as $filter)
45
            {
46
                $this->addCssFilters($filter);
47
            }
48
        }
49
        else
50
        {
51
            if (!class_exists($cssFilter) || !in_array(ICssFilter::class, class_implements($cssFilter)))
52
                throw new \ErrorException("`$cssFilter` does not implement ICssFilter.");
53
54
            $this->cssFilters[$cssFilter::getFunctionName()] = $cssFilter;
55
        }
56
    }
57
58
    /**
59
     *  Parse a string to an array containing selectors and special functions
60
     *
61
     *  @param string $line The filter to parser
62
     *  @return array
63
     */
64
    public function parse(string $line): array 
65
    {
66
        $line = trim($line);
67
68
        $parts = [];
69
        $selector = null;
70
        $functions = [];
71
        for ($i = 0; $i < strlen($line); $i++)
72
        {
73
            $char = $line[$i];
74
            if (empty(trim($char)) && empty(trim($selector)))
75
                continue;
76
77
            if ($char !== ':')
78
            {
79
                $selector .= $char;
80
            }
81
            else
82
            {
83
                do
84
                {
85
                    $brackets = 0;
86
                    $functionLine = '';
87
                    for (;++$i < strlen($line);)
88
                    {
89
                        $char = $line[$i];
90
                        $functionLine .= $char;
91
                        if ($char === '(')
92
                        {
93
                            $brackets++;
94
                        }
95
                        elseif ($char === ')' && --$brackets === 0)
96
                        {
97
                            break;
98
                        }
99
                    }
100
101
                    $functions[] = $this->parseFunctionString($functionLine);
102
                }
103
                while (++$i < strlen($line) && $line[$i] === ':');
104
105
                $parts[] = ['selector' => $selector, 'functions' => $functions];
106
                $selector = null;
107
                $functions = [];
108
            }
109
        }
110
111
        if (!empty(trim($selector)))
112
            $parts[] = ['selector' => $selector, 'functions' => $functions];
113
114
        return $parts;
115
    }
116
117
    /**
118
     *  Parse a string to a CssFilter object
119
     * 
120
     *  @param string $line The part of the selector presenting the filter function
121
     */
122
    private function parseFunctionString(string $line): ICssFilter 
123
    {
124
        if (!preg_match('/^([^\(]+)\(([^\)]*)\)$/', $line, $matches))
125
        {
126
            throw new \ErrorException("`$line` is not a valid function string.");
127
        }
128
129
        $functionName = $matches[1];
130
        if (!array_key_exists($functionName, $this->cssFilters))
131
        {
132
            throw new \ErrorException("The ICssFilter `$functionName` does not exist.");
133
        }
134
135
        return new $this->cssFilters[$functionName](preg_split('/,/', $matches[2]));
136
    }
137
138
}