Completed
Push — master ( 904fb3...48b549 )
by Sebastian
07:01
created

Parser   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 137
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
dl 0
loc 137
ccs 57
cts 57
cp 1
rs 10
c 0
b 0
f 0
wmc 16

6 Methods

Rating   Name   Duplication   Size   Complexity  
A parse() 0 9 1
A strtonum() 0 7 2
A castTypes() 0 13 3
B extractParams() 0 27 4
A applyTypes() 0 11 2
A normalizeParam() 0 18 4
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
use OutOfBoundsException;
15
16
/**
17
 * Parser
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 77
    public function parse(array $array, array $rules): array
32
    {
33 77
        $this->rules = $rules;
34
        
35 77
        $this->extractParams($array);
36 70
        $this->applyTypes($array);
37 70
        $this->normalizeParam($array);
38
        
39 70
        return $array;
40
    }
41
    
42
    /**
43
     * Separate keywords from parameters.
44
     *
45
     * @param array $words
46
     */
47 77
    private function extractParams(array &$words): void
48
    {
49 77
        $array = [];
50 77
        $actualWord = '';
51 77
        $field = $words[0];
52 77
        $count = count($words);
53
54 77
        $arguments = -1;
55
        
56 77
        for ($i = 1; $i < $count; $i++) {
57 77
            $word = strtolower($words[$i]);
58
59 77
            if (isset($this->rules[$word])) {
60 73
                $arguments = $this->rules[$word]['args_count'];
61 73
                $actualWord = $word;
62 73
                $array[$field][$word] = [];
63 73
                continue;
64
            }
65
66 60
            if (--$arguments < 0){
67 7
                throw new OutOfBoundsException("{$word} isn't a valid filter");
68
            }
69
70 53
            $array[$field][$actualWord][] = $words[$i]; 
71
        }
72
73 70
        $words = $array;
74 70
    }
75
    
76
    /**
77
     * Apply types to rules parameters.
78
     *
79
     * @param array $words
80
     */
81 70
    private function applyTypes(array &$words): void
82
    {
83 70
        $rules = $this->rules;
84 70
        $field = key($words);
85
86 70
        foreach ($words[$field] as $key => $word) {
87 70
            $rule = $rules[$key];
88 70
            $keyword = $rule['keyword'];
89
            
90
            //first param passed as reference
91 70
            $this->castTypes($words[$field][$keyword], $rule['args_type']);
92
        }
93 70
    }
94
    
95
    /**
96
     * Organize rules' array.
97
     *
98
     * @param array $words
99
     */
100 70
    private function normalizeParam(array &$words): void
101
    {
102 70
        $field = array_keys($words)[0];
103 70
        $temp = [];
104
105 70
        foreach ($words[$field] as $key => $word) {
106 70
            if (count($word) === 0) {
107 34
                $words[$field][$key] = true;
108
            }
109
110 70
            if (count($word) === 1) {
111 42
                $words[$field][$key] = $word[0];
112
            }
113
114 70
            $temp[] = [$field, $key, $this->rules[$key], $words[$field][$key]];
115
        }
116
117 70
        $words = $temp;
118 70
    }
119
120
    /**
121
     * Apply types when there is one parameter.
122
     *
123
     * @param array $params
124
     * @param array $types
125
     */
126 70
    private function castTypes(array &$params, array $types): void
127
    {
128 70
        $count = count($params);
129 70
        for ($i = 0; $i < $count; $i++) {
130 53
            $type = &$types[$i];
131 53
            $param = &$params[$i];
132
            
133 53
            if ($type === 'number') {
134 47
                settype($param, $this->strtonum($param));
135 47
                continue;
136
            }
137
138 8
            settype($param, $type);
139
        }
140 70
    }
141
142
    /**
143
     * Identify correct number type.
144
     *
145
     * @param string $number
146
     *
147
     * @return string
148
     */
149 47
    private function strtonum(string $number): string
150
    {
151 47
        if (fmod((float) $number, 1.0) !== 0.0) {
152 6
            return 'float';
153
        }
154
155 41
        return 'integer';
156
    }
157
}
158