Completed
Push — master ( b6f561...db9bd8 )
by Neomerx
03:16
created

BaseQueryParser::getParameters()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php namespace Limoncello\Flute\Http\Query;
2
3
/**
4
 * Copyright 2015-2017 [email protected]
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 * http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 */
18
19
use Limoncello\Flute\Contracts\Http\Query\BaseQueryParserInterface;
20
use Neomerx\JsonApi\Document\Error;
21
use Neomerx\JsonApi\Exceptions\JsonApiException;
22
23
/**
24
 * @package Limoncello\Flute
25
 *
26
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
27
 * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
28
 */
29
class BaseQueryParser implements BaseQueryParserInterface
30
{
31
    /** Message */
32
    public const MSG_ERR_INVALID_PARAMETER = 'Invalid Parameter.';
33
34
    /**
35
     * @var array
36
     */
37
    private $parameters;
38
39
    /**
40
     * @var string[]|null
41
     */
42
    private $messages;
43
44
    /**
45
     * @param array         $parameters
46
     * @param string[]|null $messages
47
     */
48 35
    public function __construct(array $parameters = [], array $messages = null)
49
    {
50 35
        $this->setParameters($parameters);
51 35
        $this->messages   = $messages;
52
    }
53
54
    /**
55
     * @param array $parameters
56
     *
57
     * @return self
58
     */
59 35
    public function setParameters(array $parameters): self
60
    {
61 35
        $this->parameters = $parameters;
62
63 35
        return $this;
64
    }
65
66
    /**
67
     * @inheritdoc
68
     */
69 23
    public function getIncludes(): iterable
70
    {
71 23
        if (array_key_exists(static::PARAM_INCLUDE, $this->getParameters()) === true) {
72 11
            $splitByDot = function (string $path): iterable {
73 6
                foreach ($this->splitStringAndCheckNoEmpties(static::PARAM_INCLUDE, $path, '.') as $link) {
74 6
                    yield $link;
75
                }
76 11
            };
77
78 11
            $includes   = $this->getParameters()[static::PARAM_INCLUDE];
79 11
            foreach ($this->splitCommaSeparatedStringAndCheckNoEmpties(static::PARAM_INCLUDE, $includes) as $path) {
80 7
                yield $path => $splitByDot($path);
81
            }
82
        }
83
    }
84
85
    /**
86
     * @inheritdoc
87
     */
88 3
    public function getFields(): iterable
89
    {
90 3
        if (array_key_exists(static::PARAM_FIELDS, $this->getParameters()) === true) {
91 2
            $fields = $this->getParameters()[static::PARAM_FIELDS];
92 2
            if (is_array($fields) === false || empty($fields) === true) {
93 1
                throw new JsonApiException($this->createParameterError(static::PARAM_FIELDS));
94
            }
95
96 1
            foreach ($fields as $type => $fieldList) {
97 1
                yield $type => $this->splitCommaSeparatedStringAndCheckNoEmpties($type, $fieldList);
98
            }
99
        }
100
    }
101
102
    /**
103
     * @inheritdoc
104
     */
105 17
    public function getSorts(): iterable
106
    {
107 17
        if (array_key_exists(static::PARAM_SORT, $this->getParameters()) === true) {
108 7
            $sorts = $this->getParameters()[static::PARAM_SORT];
109 7
            foreach ($this->splitCommaSeparatedStringAndCheckNoEmpties(static::PARAM_SORT, $sorts) as $orderAndField) {
110 7
                switch ($orderAndField[0]) {
111 7
                    case '-':
112 3
                        $isAsc = false;
113 3
                        $field = substr($orderAndField, 1);
114 3
                        break;
115 6
                    case '+':
116 3
                        $isAsc = true;
117 3
                        $field = substr($orderAndField, 1);
118 3
                        break;
119
                    default:
120 4
                        $isAsc = true;
121 4
                        $field = $orderAndField;
122 4
                        break;
123
                }
124
125 7
                yield $field => $isAsc;
126
            }
127
        }
128
    }
129
130
    /**
131
     * @param string       $paramName
132
     * @param string|mixed $shouldBeString
133
     * @param string       $separator
134
     *
135
     * @return iterable
0 ignored issues
show
Documentation introduced by
Should the return type not be \Generator?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
136
     */
137 24
    protected function splitString(string $paramName, $shouldBeString, string $separator): iterable
138
    {
139 24
        if (is_string($shouldBeString) === false || empty($trimmed = trim($shouldBeString)) === true) {
140 4
            throw new JsonApiException($this->createParameterError($paramName));
141
        }
142
143 20
        foreach (explode($separator, $trimmed) as $value) {
144 20
            yield $value;
145
        }
146
    }
147
148
    /**
149
     * @param string       $paramName
150
     * @param string|mixed $shouldBeString
151
     * @param string       $separator
152
     *
153
     * @return iterable
0 ignored issues
show
Documentation introduced by
Should the return type not be \Generator?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
154
     */
155 24
    protected function splitStringAndCheckNoEmpties(string $paramName, $shouldBeString, string $separator): iterable
156
    {
157 24
        foreach ($this->splitString($paramName, $shouldBeString, $separator) as $value) {
158 20
            $trimmedValue = trim($value);
159 20
            if (empty($trimmedValue) === true) {
160 1
                throw new JsonApiException($this->createParameterError($paramName));
161
            }
162
163 20
            yield $trimmedValue;
164
        }
165
    }
166
167
    /**
168
     * @param string       $paramName
169
     * @param string|mixed $shouldBeString
170
     *
171
     * @return iterable
0 ignored issues
show
Documentation introduced by
Should the return type not be \Generator?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
172
     */
173 24
    protected function splitCommaSeparatedStringAndCheckNoEmpties(string $paramName, $shouldBeString): iterable
174
    {
175 24
        return $this->splitStringAndCheckNoEmpties($paramName, $shouldBeString, ',');
176
    }
177
178
    /**
179
     * @return array
180
     */
181 34
    protected function getParameters(): array
182
    {
183 34
        return $this->parameters;
184
    }
185
186
    /**
187
     * @param string $parameterName
188
     *
189
     * @return Error
190
     */
191 10
    protected function createParameterError(string $parameterName): Error
192
    {
193 10
        return $this->createQueryError($parameterName, static::MSG_ERR_INVALID_PARAMETER);
194
    }
195
196
    /**
197
     * @param string $name
198
     * @param string $title
199
     *
200
     * @return Error
201
     */
202 10
    protected function createQueryError(string $name, string $title): Error
203
    {
204 10
        $title  = $this->getMessage($title);
205 10
        $source = [Error::SOURCE_PARAMETER => $name];
206 10
        $error  = new Error(null, null, null, null, $title, null, $source);
207
208 10
        return $error;
209
    }
210
211
    /**
212
     * @param string $message
213
     *
214
     * @return string
215
     */
216 10
    protected function getMessage(string $message): string
217
    {
218 10
        $hasTranslation = $this->messages !== null && array_key_exists($message, $this->messages) === false;
219
220 10
        return $hasTranslation === true ? $this->messages[$message] : $message;
221
    }
222
}
223