Completed
Pull Request — master (#161)
by
unknown
13:26
created

QueryParametersParser::getSortParameters()   C

Complexity

Conditions 8
Paths 2

Size

Total Lines 27
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 24
CRAP Score 8

Importance

Changes 0
Metric Value
dl 0
loc 27
c 0
b 0
f 0
ccs 24
cts 24
cp 1
rs 5.3846
cc 8
eloc 22
nc 2
nop 1
crap 8
1
<?php namespace Neomerx\JsonApi\Http\Query;
2
3
/**
4
 * Copyright 2015 [email protected] (www.neomerx.com)
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 \Psr\Http\Message\ServerRequestInterface;
22
use \Neomerx\JsonApi\Exceptions\JsonApiException as E;
23
use \Neomerx\JsonApi\Contracts\Http\HttpFactoryInterface;
24
use \Neomerx\JsonApi\Contracts\Encoder\Parameters\SortParameterInterface;
25
use \Neomerx\JsonApi\Contracts\Http\Query\QueryParametersParserInterface;
26
27
/**
28
 * @package Neomerx\JsonApi
29
 */
30
class QueryParametersParser implements QueryParametersParserInterface, LoggerAwareInterface
31
{
32
    use LoggerAwareTrait;
33
34
    /**
35
     * @var HttpFactoryInterface
36
     */
37
    private $factory;
38
39
    /**
40
     * @param HttpFactoryInterface $factory
41
     */
42 26
    public function __construct(HttpFactoryInterface $factory)
43
    {
44 26
        $this->factory = $factory;
45 26
    }
46
47
    /**
48
     * @inheritdoc
49
     */
50 25
    public function parse(ServerRequestInterface $request)
51
    {
52 25
        $parameters = $request->getQueryParams();
53
54 25
        return $this->factory->createQueryParameters(
55 25
            $this->getIncludePaths($parameters),
0 ignored issues
show
Bug introduced by
It seems like $this->getIncludePaths($parameters) targeting Neomerx\JsonApi\Http\Que...rser::getIncludePaths() can also be of type array; however, Neomerx\JsonApi\Contract...createQueryParameters() does only seem to accept array<integer,string>|null, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
56 24
            $this->getFieldSets($parameters),
57 23
            $this->getSortParameters($parameters),
58 21
            $this->getPagingParameters($parameters),
59 20
            $this->getFilteringParameters($parameters),
60 19
            $this->getUnrecognizedParameters($parameters)
61 19
        );
62
    }
63
64
    /**
65
     * @param array $parameters
66
     *
67
     * @return array|null
68
     */
69 25
    private function getIncludePaths(array $parameters)
70
    {
71 25
        $paths  = $this->getStringParamOrNull($parameters, self::PARAM_INCLUDE);
72 24
        $result = empty($paths) === false ? explode(',', rtrim($paths, ',')) : null;
73
74 24
        return $result;
75
    }
76
77
    /**
78
     * @param array $parameters
79
     *
80
     * @return array|null
81
     */
82 24
    private function getFieldSets(array $parameters)
83
    {
84 24
        $result    = [];
85 24
        $fieldSets = $this->getParamOrNull($parameters, self::PARAM_FIELDS);
86 24
        if (empty($fieldSets) === false && is_array($fieldSets)) {
87 16
            foreach ($fieldSets as $type => $fields) {
88
                // We expect fields to be comma separated or empty strings. Multi-dimension arrays are not allowed.
89 16
                is_string($fields) ?: E::throwException(new E([], E::HTTP_CODE_BAD_REQUEST));
90 15
                $result[$type] = (empty($fields) === true ? [] : explode(',', $fields));
91 15
            }
92 15
        } else {
93 8
            $result = null;
94
        }
95
96 23
        return $result;
97
    }
98
99
    /**
100
     * @param array $parameters
101
     *
102
     * @return SortParameterInterface[]|null
103
     */
104 23
    protected function getSortParameters(array $parameters)
105
    {
106 23
        $sortParams = null;
107 23
        $sortParam = $this->getStringParamOrNull($parameters, self::PARAM_SORT);
108 22
        if ($sortParam !== null) {
109 16
            foreach (explode(',', $sortParam) as $param) {
110 16
                if (strpos($param, '.') === false) {
111 16
                    $isDesc = false;
112 16
                    empty($param) === false ?
113 16
                        $isDesc = ($param[0] === '-') : E::throwException(new E([], E::HTTP_CODE_BAD_REQUEST));
114 16
                    $sortField = ltrim($param, '+-');
115 16
                    empty($sortField) === false ?: E::throwException(new E([], E::HTTP_CODE_BAD_REQUEST));
116 16
                    $sortParams[] = $this->factory->createSortParam($sortField, $isDesc === false);
117 16
                } else {
118 13
                    $isDesc = false;
119 13
                    list($relationship, $relationshipAttribute) = explode('.', $param);
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $relationshipAttribute exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
120 13
                    empty($relationship) === false ?
121 13
                        $isDesc = ($relationship[0] === '-') : E::throwException(new E([], E::HTTP_CODE_BAD_REQUEST));
122 13
                    $sortField = ltrim($relationship, '+-');
123 13
                    $sortRelationshipAttribute = $relationshipAttribute;
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $sortRelationshipAttribute exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
124 13
                    empty($sortField === false) ?: E::throwException(new E([], E::HTTP_CODE_BAD_REQUEST));
125 13
                    $sortParams[] = $this->factory->createSortParam($sortField, $isDesc === false, $sortRelationshipAttribute);
0 ignored issues
show
Unused Code introduced by
The call to HttpFactoryInterface::createSortParam() has too many arguments starting with $sortRelationshipAttribute.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
126
                }
127 16
            }
128 15
        }
129 21
        return $sortParams;
130
    }
131
132
    /**
133
     * @param array $parameters
134
     *
135
     * @return array|null
136
     */
137 21
    private function getPagingParameters(array $parameters)
138
    {
139 21
        return $this->getArrayParamOrNull($parameters, self::PARAM_PAGE);
140
    }
141
142
    /**
143
     * @param array $parameters
144
     *
145
     * @return array|null
146
     */
147 20
    private function getFilteringParameters(array $parameters)
148
    {
149 20
        return $this->getArrayParamOrNull($parameters, self::PARAM_FILTER);
150
    }
151
152
    /**
153
     * @param array $parameters
154
     *
155
     * @return array|null
156
     */
157 19
    private function getUnrecognizedParameters(array $parameters)
158
    {
159
        $supported = [
160 19
            self::PARAM_INCLUDE => 0,
161 19
            self::PARAM_FIELDS  => 0,
162 19
            self::PARAM_PAGE    => 0,
163 19
            self::PARAM_FILTER  => 0,
164 19
            self::PARAM_SORT    => 0,
165 19
        ];
166 19
        $unrecognized = array_diff_key($parameters, $supported);
167 19
        return empty($unrecognized) === true ? null : $unrecognized;
168
    }
169
170
    /**
171
     * @param array $parameters
172
     * @param string $name
173
     *
174
     * @return array|null
175
     */
176 21
    private function getArrayParamOrNull(array $parameters, $name)
177
    {
178 21
        $value = $this->getParamOrNull($parameters, $name);
179
180 21
        $isArrayOrNull = ($value === null || is_array($value) === true);
181 21
        $isArrayOrNull === true ?: E::throwException(new E([], E::HTTP_CODE_BAD_REQUEST));
182
183 20
        return $value;
184
    }
185
186
    /**
187
     * @param array $parameters
188
     * @param string $name
189
     *
190
     * @return string|null
191
     */
192 25
    private function getStringParamOrNull(array $parameters, $name)
193
    {
194 25
        $value = $this->getParamOrNull($parameters, $name);
195
196 25
        $isStringOrNull = ($value === null || is_string($value) === true);
197 25
        $isStringOrNull === true ?: E::throwException(new E([], E::HTTP_CODE_BAD_REQUEST));
198
199 24
        return $value;
200
    }
201
202
    /**
203
     * @param array  $parameters
204
     * @param string $name
205
     *
206
     * @return mixed
207
     */
208 25
    private function getParamOrNull(array $parameters, $name)
209
    {
210 25
        return isset($parameters[$name]) === true ? $parameters[$name] : null;
211
    }
212
}
213