Completed
Branch master (b39782)
by
unknown
07:19
created

QueryParametersParser   A

Complexity

Total Complexity 30

Size/Duplication

Total Lines 238
Duplicated Lines 9.24 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
dl 22
loc 238
c 0
b 0
f 0
wmc 30
lcom 1
cbo 6
ccs 84
cts 84
cp 1
rs 10

14 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A parse() 0 4 1
A parseQueryParameters() 0 11 1
A getIncludePaths() 0 7 2
B getFieldSets() 0 17 6
B getSortParameters() 0 21 5
A getPagingParameters() 0 4 1
A getFilteringParameters() 0 4 1
A getUnrecognizedParameters() 0 12 2
A getArrayParamOrNull() 11 11 3
A getStringParamOrNull() 11 11 3
A getParamOrNull() 0 4 2
A createInvalidQueryErrors() 0 11 1
A createParamErrors() 0 14 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php namespace Neomerx\JsonApi\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 \Psr\Log\LoggerAwareTrait;
20
use \Psr\Log\LoggerAwareInterface;
21
use \Neomerx\JsonApi\Document\Error;
22
use \Neomerx\JsonApi\I18n\Translator as T;
23
use \Psr\Http\Message\ServerRequestInterface;
24
use \Neomerx\JsonApi\Exceptions\JsonApiException as E;
25
use \Neomerx\JsonApi\Contracts\Http\HttpFactoryInterface;
26
use \Neomerx\JsonApi\Contracts\Encoder\Parameters\SortParameterInterface;
27
use \Neomerx\JsonApi\Contracts\Http\Query\QueryParametersParserInterface;
28
29
/**
30
 * @package Neomerx\JsonApi
31
 */
32
class QueryParametersParser implements QueryParametersParserInterface, LoggerAwareInterface
33
{
34
    use LoggerAwareTrait;
35
36
    /**
37
     * @var HttpFactoryInterface
38
     */
39
    private $factory;
40
41
    /**
42
     * @param HttpFactoryInterface $factory
43
     */
44 27
    public function __construct(HttpFactoryInterface $factory)
45
    {
46 27
        $this->factory = $factory;
47 27
    }
48
49
    /**
50
     * @inheritdoc
51
     */
52 26
    public function parse(ServerRequestInterface $request)
53
    {
54 26
        return $this->parseQueryParameters($request->getQueryParams());
55
    }
56
57
    /**
58
     * @inheritdoc
59
     */
60 26
    public function parseQueryParameters(array $parameters)
61
    {
62 26
        return $this->factory->createQueryParameters(
63 26
            $this->getIncludePaths($parameters),
64 25
            $this->getFieldSets($parameters),
65 24
            $this->getSortParameters($parameters),
66 21
            $this->getPagingParameters($parameters),
67 20
            $this->getFilteringParameters($parameters),
68 19
            $this->getUnrecognizedParameters($parameters)
69 19
        );
70
    }
71
72
    /**
73
     * @param array $parameters
74
     *
75
     * @return array|null
76
     */
77 26
    private function getIncludePaths(array $parameters)
78
    {
79 26
        $paths  = $this->getStringParamOrNull($parameters, self::PARAM_INCLUDE);
80 25
        $result = empty($paths) === false ? explode(',', rtrim($paths, ',')) : null;
81
82 25
        return $result;
83
    }
84
85
    /**
86
     * @param array $parameters
87
     *
88
     * @return array|null
89
     *
90
     * @SuppressWarnings(PHPMD.StaticAccess)
91
     */
92 25
    private function getFieldSets(array $parameters)
93
    {
94 25
        $result = null;
95 25
        $fieldSets = $this->getParamOrNull($parameters, self::PARAM_FIELDS);
96 25
        if (empty($fieldSets) === false && is_array($fieldSets)) {
97 16
            foreach ($fieldSets as $type => $fields) {
98
                // We expect fields to be comma separated or empty strings. Multi-dimension arrays are not allowed.
99 16
                if (is_string($fields) === false) {
100 1
                    $detail = T::t(self::PARAM_FIELDS . ' parameter values should be comma separated strings.');
101 1
                    throw new E($this->createInvalidQueryErrors($detail), E::HTTP_CODE_BAD_REQUEST);
102
                }
103 15
                $result[$type] = (empty($fields) === true ? [] : explode(',', $fields));
104 15
            }
105 15
        }
106
107 24
        return $result;
108
    }
109
110
    /**
111
     * @param array $parameters
112
     *
113
     * @return SortParameterInterface[]|null
114
     *
115
     * @SuppressWarnings(PHPMD.StaticAccess)
116
     */
117 24
    protected function getSortParameters(array $parameters)
118
    {
119 24
        $sortParams = null;
120 24
        $sortParam  = $this->getStringParamOrNull($parameters, self::PARAM_SORT);
121 23
        if ($sortParam !== null) {
122 17
            foreach (explode(',', $sortParam) as $param) {
123 17
                if (empty($param) === true) {
124 1
                    $detail = T::t('Parameter ' . self::PARAM_SORT . ' should have valid value specified.');
125 1
                    throw new E($this->createInvalidQueryErrors($detail), E::HTTP_CODE_BAD_REQUEST);
126
                }
127 17
                $isDesc = $isDesc = ($param[0] === '-');
128 17
                $sortField = ltrim($param, '+-');
129 17
                if (empty($sortField) === true) {
130 1
                    $detail = T::t('Parameter ' . self::PARAM_SORT . ' should have valid name specified.');
131 1
                    throw new E($this->createInvalidQueryErrors($detail), E::HTTP_CODE_BAD_REQUEST);
132
                }
133 17
                $sortParams[] = $this->factory->createSortParam($sortField, $isDesc === false);
134 17
            }
135 15
        }
136 21
        return $sortParams;
137
    }
138
139
    /**
140
     * @param array $parameters
141
     *
142
     * @return array|null
143
     */
144 21
    private function getPagingParameters(array $parameters)
145
    {
146 21
        return $this->getArrayParamOrNull($parameters, self::PARAM_PAGE);
147
    }
148
149
    /**
150
     * @param array $parameters
151
     *
152
     * @return array|null
153
     */
154 20
    private function getFilteringParameters(array $parameters)
155
    {
156 20
        return $this->getArrayParamOrNull($parameters, self::PARAM_FILTER);
157
    }
158
159
    /**
160
     * @param array $parameters
161
     *
162
     * @return array|null
163
     */
164 19
    private function getUnrecognizedParameters(array $parameters)
165
    {
166
        $supported = [
167 19
            self::PARAM_INCLUDE => 0,
168 19
            self::PARAM_FIELDS  => 0,
169 19
            self::PARAM_PAGE    => 0,
170 19
            self::PARAM_FILTER  => 0,
171 19
            self::PARAM_SORT    => 0,
172 19
        ];
173 19
        $unrecognized = array_diff_key($parameters, $supported);
174 19
        return empty($unrecognized) === true ? null : $unrecognized;
175
    }
176
177
    /**
178
     * @param array $parameters
179
     * @param string $name
180
     *
181
     * @return array|null
182
     *
183
     * @SuppressWarnings(PHPMD.StaticAccess)
184
     */
185 21 View Code Duplication
    private function getArrayParamOrNull(array $parameters, $name)
186
    {
187 21
        $value = $this->getParamOrNull($parameters, $name);
188
189 21
        if ($value !== null && is_array($value) === false) {
190 2
            $detail = T::t('Value should be either an array or null.');
191 2
            throw new E($this->createParamErrors($name, $detail), E::HTTP_CODE_BAD_REQUEST);
192
        }
193
194 20
        return $value;
195
    }
196
197
    /**
198
     * @param array $parameters
199
     * @param string $name
200
     *
201
     * @return string|null
202
     *
203
     * @SuppressWarnings(PHPMD.StaticAccess)
204
     */
205 26 View Code Duplication
    private function getStringParamOrNull(array $parameters, $name)
206
    {
207 26
        $value = $this->getParamOrNull($parameters, $name);
208
209 26
        if ($value !== null && is_string($value) === false) {
210 2
            $detail = T::t('Value should be either a string or null.');
211 2
            throw new E($this->createParamErrors($name, $detail), E::HTTP_CODE_BAD_REQUEST);
212
        }
213
214 25
        return $value;
215
    }
216
217
    /**
218
     * @param array  $parameters
219
     * @param string $name
220
     *
221
     * @return mixed
222
     */
223 26
    private function getParamOrNull(array $parameters, $name)
224
    {
225 26
        return isset($parameters[$name]) === true ? $parameters[$name] : null;
226
    }
227
228
    /**
229
     * @param string $detail
230
     *
231
     * @return Error[]
232
     *
233
     * @SuppressWarnings(PHPMD.StaticAccess)
234
     */
235 3
    protected function createInvalidQueryErrors($detail)
236
    {
237
        // NOTE: external libraries might expect this method to exist and have certain signature
238
        // @see https://github.com/neomerx/json-api/issues/185#issuecomment-329135390
239
240 3
        $title = T::t('Invalid query.');
241
242
        return [
243 3
            new Error(null, null, null, null, $title, $detail),
244 3
        ];
245
    }
246
247
    /**
248
     * @param string $name
249
     * @param string $detail
250
     *
251
     * @return Error[]
252
     *
253
     * @SuppressWarnings(PHPMD.StaticAccess)
254
     */
255 4
    protected function createParamErrors($name, $detail)
256
    {
257
        // NOTE: external libraries might expect this method to exist and have certain signature
258
        // @see https://github.com/neomerx/json-api/issues/185#issuecomment-329135390
259
260 4
        $title  = T::t('Invalid query parameter.');
261
        $source = [
262 4
            Error::SOURCE_PARAMETER => $name,
263 4
        ];
264
265
        return [
266 4
            new Error(null, null, null, null, $title, $detail, $source),
267 4
        ];
268
    }
269
}
270