AbstractParser::parseInput()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 18
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

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