Passed
Push — master ( fadf79...5a8e38 )
by Sebastian
03:53
created

Parser::parse()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 5
nc 1
nop 2
dl 0
loc 9
ccs 6
cts 6
cp 1
crap 1
rs 9.6666
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Linna Filter
5
 *
6
 * @author Sebastian Rapetti <[email protected]>
7
 * @copyright (c) 2018, Sebastian Rapetti
8
 * @license http://opensource.org/licenses/MIT MIT License
9
 */
10
declare(strict_types = 1);
11
12
namespace Linna\Filter;
13
14
/**
15
 * Description of Parser
16
 *
17
 * @author Sebastian
18
 */
19
class Parser
20
{
21
    /**
22
     * @var array Parsing rules.
23
     */
24
    private $rules;
25
    
26
    /**
27
     * Parser.
28
     *
29
     * @param array $array
30
     */
31 50
    public function parse(array $array, array $rules) : array
32
    {
33 50
        $this->rules = $rules;
34
        
35 50
        $this->extractParams($array);
36 50
        $this->applyTypes($array);
37 50
        $this->normalizeParam($array);
38
        
39 50
        return $array;
40
    }
41
    
42
    /**
43
     * Separate keywords from parameters.
44
     *
45
     * @param array $words
46
     */
47 50
    private function extractParams(array &$words)
48
    {
49
        //intervenire qui per fare in modo che funzioni anche in modalità anonima.
50
        
51 50
        $array = [];
52 50
        $actualWord = '';
53 50
        $field = $words[0];
54 50
        $count = count($words);
55
56 50
        for ($i = 1; $i < $count; $i++) {
57 50
            $word = strtolower($words[$i]);
58
59 50
            if (isset($this->rules[$word])) {
60 50
                $actualWord = $word;
61 50
                $array[$field][$word] = [];
62 50
                continue;
63
            }
64
65 33
            $array[$field][$actualWord][] = $words[$i];
66
        }
67
        
68 50
        $words = $array;
69 50
    }
70
    
71
    /**
72
     * Apply types to rules parameters.
73
     *
74
     * @param array $words
75
     *
76
     * @throws InvalidArgumentException If unknown keyword is provided.
77
     */
78 50
    private function applyTypes(array &$words)
79
    {
80 50
        $rules = $this->rules;
81 50
        $field = key($words);
82
83 50
        foreach ($words[$field] as $key => $word) {
84 50
            if (!isset($rules[$key])) {
85
                throw new InvalidArgumentException("Unknown rule provided ({$field})");
0 ignored issues
show
Bug introduced by
The type Linna\Filter\InvalidArgumentException was not found. Did you mean InvalidArgumentException? If so, make sure to prefix the type with \.
Loading history...
86
            }
87
            
88 50
            $rule = $rules[$key];
89 50
            $keyword = $rule['keyword'];
90
            
91
            //first param passed as reference
92 50
            $this->castTypes($words[$field][$keyword], $rule['args_type']);
93
        }
94 50
    }
95
    
96
    /**
97
     * Organize rules' array.
98
     *
99
     * @param array $words
100
     */
101 50
    private function normalizeParam(array &$words)
102
    {
103 50
        $field = array_keys($words)[0];
104 50
        $temp = [];
105
106 50
        foreach ($words[$field] as $key => $word) {
107 50
            if (count($word) === 0) {
108 31
                $words[$field][$key] = true;
109
            }
110
111 50
            if (count($word) === 1) {
112 28
                $words[$field][$key] = $word[0];
113
            }
114
115 50
            $temp[] = [$field, $key, $this->rules[$key], $words[$field][$key]];
116
        }
117
118 50
        $words = $temp;
119 50
    }
120
121
    /**
122
     * Apply types when there is one parameter.
123
     *
124
     * @param array $params
125
     * @param array $types
126
     *
127
     * @return mixed
128
     */
129 50
    private function castTypes(array &$params, array $types)
130
    {
131 50
        for ($i = 0; $i < count($params); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
132 33
            $type = &$types[$i];
133 33
            $param = &$params[$i];
134
            
135 33
            if ($type === 'number') {
136 30
                settype($param, $this->strtonum($param));
137 30
                continue;
138
            }
139
140 5
            settype($param, $type);
141
        }
142 50
    }
143
144
    /**
145
     * Identify correct number type.
146
     *
147
     * @param string $number
148
     *
149
     * @return string
150
     */
151 30
    private function strtonum(string $number): string
152
    {
153 30
        if (fmod((float) $number, 1.0) !== 0.0) {
154 6
            return 'float';
155
        }
156
157 24
        return 'integer';
158
    }
159
}
160