Test Setup Failed
Push — master ( 2d8834...88c29c )
by noitran
02:56
created

RequestParser::getQueryParameter()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Noitran\RQL\Parsers\Request\Illuminate;
6
7
use Illuminate\Http\Request;
8
use Illuminate\Support\Collection;
9
use Illuminate\Support\Str;
10
use Noitran\RQL\Exceptions\RuntimeException;
11
use Noitran\RQL\Parsers\AbstractParser;
12
use Noitran\RQL\Parsers\Model;
13
14
/**
15
 * Class RequestParser.
16
 */
17
class RequestParser extends AbstractParser
18
{
19
    /**
20
     * @var string
21
     */
22
    protected $queryParameterName;
23
24
    /**
25
     * @var Request
26
     */
27
    protected $request;
28
29
    /**
30
     * RequestParser constructor.
31
     *
32
     * @param Request $request
33
     */
34
    public function __construct(Request $request)
35
    {
36
        $this->request = $request;
37
38
        $this->init();
39
    }
40
41
    /**
42
     * @return RequestParser
43
     */
44
    public function init(): self
45
    {
46
        $this->setQueryParameterName();
47
48
        return $this;
49
    }
50
51
    /**
52
     * @return array
53
     */
54
    public function getAttributes(): array
55
    {
56
        return $this->request->toArray();
57
    }
58
59
    /**
60
     * @return RequestParser
61
     */
62
    public function setQueryParameterName(): self
63
    {
64
        $this->queryParameterName = config('rql.parsers.default_query_parameter', 'filter');
65
66
        return $this;
67
    }
68
69
    /**
70
     * @return string
71
     */
72
    public function getQueryParameterName(): string
73
    {
74
        return $this->queryParameterName;
75
    }
76
77
    /**
78
     * @return string|array|null
79
     */
80
    public function getQueryValue()
81
    {
82
        return $this->request->input($this->queryParameterName);
83
    }
84
85
    /**
86
     * @return mixed
87
     */
88
    public function parse(): Collection
89
    {
90
        $input = $this->getQueryValue();
91
        $collection = collect();
92
93
        foreach ($input as $key => $item) {
94
            $model = new Model();
95
96
            $model->setRelation($this->parseRelation($key))
97
                ->setField($this->parseColumn($key))
98
                ->setExpression($this->parseExpression($item))
99
                ->setDataType($this->parseDataType($item))
100
                ->setValue($this->parseValue($item))
101
            ;
102
103
            $collection->push($model);
104
        }
105
106
        return $collection;
107
    }
108
109
    /**
110
     * @param $filterParameter
111
     *
112
     * @return string|null
113
     */
114
    protected function parseRelation($filterParameter): ?string
115
    {
116
        if (false !== strpos($filterParameter, '.')) {
117
            $lastDotPosition = strrpos($filterParameter, '.');
118
119
            return substr($filterParameter, 0, $lastDotPosition);
120
        }
121
122
        return null;
123
    }
124
125
    /**
126
     * @param $filterParameter
127
     *
128
     * @return string
129
     */
130
    protected function parseColumn($filterParameter): string
131
    {
132
        if (false !== strpos($filterParameter, '.')) {
133
            $lastDotPosition = strrpos($filterParameter, '.');
134
135
            return substr($filterParameter, $lastDotPosition + 1);
136
        }
137
138
        return $filterParameter;
139
    }
140
141
    /**
142
     * @param $filterValue
143
     *
144
     * @return string
145
     */
146
    protected function parseExpression($filterValue): string
147
    {
148
        if (! \is_array($filterValue)) {
149
            return config('rql.filtering.default_expression', '$eq');
150
        }
151
152
        return key($filterValue);
0 ignored issues
show
Bug Best Practice introduced by
The expression return key($filterValue) could return the type null which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
153
    }
154
155
    /**
156
     * @param $filterValue
157
     *
158
     * @throws RuntimeException
159
     *
160
     * @return string
161
     */
162
    protected function parseDataType($filterValue): string
163
    {
164
        $value = $this->extractValue($filterValue);
165
166
        if (false !== strpos($value, ':')) {
167
            $lastColonPosition = strpos($value, ':');
168
169
            $parsedDataType = substr($value, 0, $lastColonPosition);
170
171
            if (! $this->isValidDataType($parsedDataType)) {
172
                return config('rql.filtering.default_data_type', '$string');
173
            }
174
175
            return $parsedDataType;
176
        }
177
178
        return config('rql.filtering.default_data_type', '$string');
179
    }
180
181
    /**
182
     * @param $filterValue
183
     *
184
     * @return string
185
     */
186
    protected function parseValue($filterValue): string
187
    {
188
        $value = $this->extractValue($filterValue);
189
190
        if (Str::startsWith($value, ['$']) && false !== strpos($value, ':')) {
191
            $lastColonPosition = strpos($value, ':');
192
193
            return substr($value, $lastColonPosition + 1);
194
        }
195
196
        return $value;
197
    }
198
199
    /**
200
     * @param $filterValue
201
     *
202
     * @return string
203
     */
204
    private function extractValue($filterValue): string
205
    {
206
        if (! \is_array($filterValue)) {
207
            return $filterValue;
208
        }
209
210
        return array_shift($filterValue);
211
    }
212
213
    /**
214
     * @param $dataType
215
     * @param bool $strict
216
     *
217
     * @throws RuntimeException
218
     *
219
     * @return bool
220
     */
221
    private function isValidDataType($dataType, $strict = false): bool
222
    {
223
        if (! \in_array($dataType, config('rql.filtering.allowed_data_types', ['$string']), true)) {
224
            if ($strict) {
225
                throw new RuntimeException('Invalid/Not allowed data type passed.');
226
            }
227
228
            return false;
229
        }
230
231
        return true;
232
    }
233
}
234