Completed
Branch master (fea354)
by
unknown
07:44
created

RestrictiveQueryChecker::checkFieldSets()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 5
ccs 4
cts 4
cp 1
rs 9.4285
cc 2
eloc 3
nc 2
nop 1
crap 2
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 \Neomerx\JsonApi\Exceptions\JsonApiException as E;
20
use \Neomerx\JsonApi\Contracts\Http\Query\QueryCheckerInterface;
21
use \Neomerx\JsonApi\Contracts\Encoder\Parameters\SortParameterInterface;
22
use \Neomerx\JsonApi\Contracts\Encoder\Parameters\EncodingParametersInterface;
23
24
/**
25
 * @package Neomerx\JsonApi
26
 */
27
class RestrictiveQueryChecker implements QueryCheckerInterface
28
{
29
    /**
30
     * @var bool
31
     */
32
    private $allowUnrecognized;
33
34
    /**
35
     * @var array|null
36
     */
37
    private $includePaths;
38
39
    /**
40
     * @var array|null
41
     */
42
    private $fieldSetTypes;
43
44
    /**
45
     * @var array|null
46
     */
47
    private $pagingParameters;
48
49
    /**
50
     * @var array|null
51
     */
52
    private $sortParameters;
53
54
    /**
55
     * @var array|null
56
     */
57
    private $filteringParameters;
58
59
    /**
60
     * @param bool       $allowUnrecognized
61
     * @param array|null $includePaths
62
     * @param array|null $fieldSetTypes
63
     * @param array|null $sortParameters
64
     * @param array|null $pagingParameters
65
     * @param array|null $filteringParameters
66
     */
67 12
    public function __construct(
68
        $allowUnrecognized = true,
69
        array $includePaths = null,
70
        array $fieldSetTypes = null,
71
        array $sortParameters = null,
72
        array $pagingParameters = null,
73
        array $filteringParameters = null
74
    ) {
75 12
        $this->includePaths        = $includePaths;
76 12
        $this->allowUnrecognized   = $allowUnrecognized;
77 12
        $this->fieldSetTypes       = $fieldSetTypes;
78 12
        $this->sortParameters      = $this->flip($sortParameters);
79 12
        $this->pagingParameters    = $this->flip($pagingParameters);
80 12
        $this->filteringParameters = $this->flip($filteringParameters);
81 12
    }
82
83
    /**
84
     * @inheritdoc
85
     */
86 11
    public function checkQuery(EncodingParametersInterface $parameters)
87
    {
88 11
        $this->checkIncludePaths($parameters);
89 10
        $this->checkFieldSets($parameters);
90 8
        $this->checkFiltering($parameters);
91 8
        $this->checkSorting($parameters);
92 7
        $this->checkPaging($parameters);
93 7
        $this->checkUnrecognized($parameters);
94 6
    }
95
96
    /**
97
     * @param EncodingParametersInterface $parameters
98
     */
99 11
    protected function checkIncludePaths(EncodingParametersInterface $parameters)
100
    {
101 11
        $withinAllowed = $this->valuesWithinAllowed($parameters->getIncludePaths(), $this->includePaths);
102 11
        $withinAllowed === true ?: E::throwException(new E([], E::HTTP_CODE_BAD_REQUEST));
103 10
    }
104
105
    /**
106
     * @param EncodingParametersInterface $parameters
107
     */
108 10
    protected function checkFieldSets(EncodingParametersInterface $parameters)
109
    {
110 10
        $withinAllowed = $this->isFieldsAllowed($parameters->getFieldSets());
111 10
        $withinAllowed === true ?: E::throwException(new E([], E::HTTP_CODE_BAD_REQUEST));
112 8
    }
113
114
    /**
115
     * @param EncodingParametersInterface $parameters
116
     */
117 8
    protected function checkFiltering(EncodingParametersInterface $parameters)
118
    {
119 8
        $withinAllowed = $this->keysWithinAllowed($parameters->getFilteringParameters(), $this->filteringParameters);
120 8
        $withinAllowed === true ?: E::throwException(new E([], E::HTTP_CODE_BAD_REQUEST));
121 8
    }
122
123
    /**
124
     * @param EncodingParametersInterface $parameters
125
     */
126 8
    protected function checkSorting(EncodingParametersInterface $parameters)
127
    {
128 8
        if ($parameters->getSortParameters() !== null && $this->sortParameters !== null) {
129 2
            foreach ($parameters->getSortParameters() as $sortParameter) {
130
                /** @var SortParameterInterface $sortParameter */
131 2
                if (array_key_exists($sortParameter->getField(), $this->sortParameters) === false) {
132 1
                    throw new E([], E::HTTP_CODE_BAD_REQUEST);
133
                }
134 2
            }
135 1
        }
136 7
    }
137
138
    /**
139
     * @param EncodingParametersInterface $parameters
140
     */
141 7
    protected function checkPaging(EncodingParametersInterface $parameters)
142
    {
143 7
        $withinAllowed = $this->keysWithinAllowed($parameters->getPaginationParameters(), $this->pagingParameters);
144 7
        $withinAllowed === true ?: E::throwException(new E([], E::HTTP_CODE_BAD_REQUEST));
145 7
    }
146
147
    /**
148
     * @param EncodingParametersInterface $parameters
149
     */
150 7
    protected function checkUnrecognized(EncodingParametersInterface $parameters)
151
    {
152 7
        $this->allowUnrecognized === true || empty($parameters->getUnrecognizedParameters()) === true ?:
153 1
            E::throwException(new E([], E::HTTP_CODE_BAD_REQUEST));
154 6
    }
155
156
    /**
157
     * @param array|null $toCheck
158
     * @param array|null $allowed
159
     *
160
     * @return bool
161
     */
162 8
    private function keysWithinAllowed(array $toCheck = null, array $allowed = null)
163
    {
164 8
        return $toCheck === null || $allowed === null || empty(array_diff_key($toCheck, $allowed));
165
    }
166
167
    /**
168
     * @param array|null $toCheck
169
     * @param array|null $allowed
170
     *
171
     * @return bool
172
     */
173 11
    private function valuesWithinAllowed(array $toCheck = null, array $allowed = null)
174
    {
175 11
        return $toCheck === null || $allowed === null || empty(array_diff($toCheck, $allowed));
176
    }
177
178
    /**
179
     * @param array|null $array
180
     *
181
     * @return array|null
182
     */
183 12
    private function flip(array $array = null)
184
    {
185 12
        return $array === null ? null : array_flip($array);
186
    }
187
188
    /**
189
     * Check input fields against allowed.
190
     *
191
     * @param array|null $fields
192
     *
193
     * @return bool
194
     */
195 10
    private function isFieldsAllowed(array $fields = null)
196
    {
197 10
        if ($this->fieldSetTypes === null || $fields === null) {
198 6
            return true;
199
        }
200
201 4
        foreach ($fields as $type => $requestedFields) {
202 4
            if (array_key_exists($type, $this->fieldSetTypes) === false) {
203 1
                return false;
204
            }
205
206 3
            $allowedFields = $this->fieldSetTypes[$type];
207
208
            // if not all fields are allowed and requested more fields than allowed
209 3
            if ($allowedFields !== null && empty(array_diff($requestedFields, $allowedFields)) === false) {
210 1
                return false;
211
            }
212 2
        }
213
214 2
        return true;
215
    }
216
}
217