Passed
Push — master ( 1ec89a...1818e9 )
by Vincent
06:54 queued 04:35
created

ValidateService   A

Complexity

Total Complexity 36

Size/Duplication

Total Lines 303
Duplicated Lines 0 %

Test Coverage

Coverage 96.63%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 87
dl 0
loc 303
ccs 86
cts 89
cp 0.9663
rs 9.52
c 1
b 0
f 0
wmc 36

26 Methods

Rating   Name   Duplication   Size   Complexity  
A isCollection() 0 3 1
A containsOnlyAllowedMembers() 0 14 1
A isToOne() 0 3 1
A setRelationship() 0 6 2
A isToMany() 0 3 1
A __construct() 0 7 2
A isUpdate() 0 3 1
A setRouteType() 0 3 1
A isDelete() 0 3 1
A isRelatedRoute() 0 3 1
A isValidArgument() 0 14 4
A isAutomatic() 0 3 2
A isPost() 0 3 1
A isMainRoute() 0 3 1
A throw() 0 3 1
A containsAtLeastOneMember() 0 14 1
A setSingle() 0 3 1
A dataIsRequired() 0 7 5
A isSingle() 0 3 1
A setVersion() 0 5 1
A setMethod() 0 5 1
A constraint() 0 9 1
A setCollection() 0 3 1
A isRelationshipRoute() 0 3 1
A validateMemberName() 0 14 1
A getRule() 0 3 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace VGirol\JsonApiStructure;
6
7
use VGirol\JsonApiStructure\Concern\ValidateArrays;
8
use VGirol\JsonApiStructure\Concern\ValidateAttributesObject;
9
use VGirol\JsonApiStructure\Concern\ValidateErrorsObject;
10
use VGirol\JsonApiStructure\Concern\ValidateJsonapiObject;
11
use VGirol\JsonApiStructure\Concern\ValidateLinksObject;
12
use VGirol\JsonApiStructure\Concern\ValidateMembers;
13
use VGirol\JsonApiStructure\Concern\ValidateMetaObject;
14
use VGirol\JsonApiStructure\Concern\ValidateRelationshipsObject;
15
use VGirol\JsonApiStructure\Concern\ValidateResourceLinkage;
16
use VGirol\JsonApiStructure\Concern\ValidateResourceObject;
17
use VGirol\JsonApiStructure\Concern\ValidateStructure;
18
use VGirol\JsonApiStructure\Constraint\ContainsAtLeastOne;
19
use VGirol\JsonApiStructure\Constraint\ContainsOnlyAllowedMembers;
20
use VGirol\JsonApiStructure\Constraint\MemberName;
21
use VGirol\JsonApiStructure\Exception\CanThrowInvalidArgumentException;
22
use VGirol\JsonApiStructure\Exception\ValidationException;
23
24
class ValidateService
25
{
26
    use CanThrowInvalidArgumentException;
27
    use HaveBitwiseFlag;
28
29
    use ValidateArrays;
30
    use ValidateAttributesObject;
31
    use ValidateErrorsObject;
32
    use ValidateJsonapiObject;
33
    use ValidateLinksObject;
34
    use ValidateMembers;
35
    use ValidateMetaObject;
36
    use ValidateRelationshipsObject;
37
    use ValidateResourceLinkage;
38
    use ValidateResourceObject;
39
    use ValidateStructure;
40
41
    public const ROUTE_MAIN = 1;
42
    public const ROUTE_RELATED = 2;
43
    public const ROUTE_RELATIONSHIP = 4;
44
    public const SINGLE_RESOURCE = 8;
45
    public const RESOURCE_COLLECTION = 16;
46
    public const TO_ONE_RELATIONSHIP = 32;
47
    public const TO_MANY_RELATIONSHIP = 64;
48
49
    /**
50
     * Undocumented variable
51
     *
52
     * @var VersionService
53
     */
54
    protected $version;
55
56
    /**
57
     * The HTTP method of the request
58
     *
59
     * @var string
60
     */
61
    private $method;
62
63
    /**
64
     * Create a new instance
65
     *
66
     * @param string|null $method  The HTTP method of the request
67
     * @param string|null $version The version of the JSON:API specification
68
     *
69
     * @return void
70
     */
71 768
    public function __construct(string $method = null, string $version = null)
72
    {
73 768
        if ($method !== null) {
74 144
            $this->setMethod($method);
75
        }
76
77 768
        $this->version = new VersionService($version);
78 768
    }
79
80
    /**
81
     * Set the version of the JSON:API specification
82
     *
83
     * @param string $version
84
     *
85
     * @return static
86
     */
87
    public function setVersion(string $version)
88
    {
89
        $this->version->setVersion($version);
90
91
        return $this;
92
    }
93
94
    /**
95
     * Set the HTTP method
96
     *
97
     * @param string $method
98
     *
99
     * @return static
100
     */
101 156
    public function setMethod(string $method)
102
    {
103 156
        $this->method = \strtoupper($method);
104
105 156
        return $this;
106
    }
107
108 48
    public function isPost(): bool
109
    {
110 48
        return $this->method === 'POST';
111
    }
112
113 18
    public function isUpdate(): bool
114
    {
115 18
        return \in_array($this->method, ['PATCH', 'PUT']);
116
    }
117
118 18
    public function isDelete(): bool
119
    {
120 18
        return $this->method === 'DELETE';
121
    }
122
123
    /**
124
     * Undocumented function
125
     *
126
     * @param int $routeType
127
     *
128
     * @return static
129
     */
130 138
    public function setRouteType(int $routeType)
131
    {
132 138
        return $this->selectFlag($routeType, [self::ROUTE_MAIN, self::ROUTE_RELATED, self::ROUTE_RELATIONSHIP]);
133
    }
134
135 18
    public function isMainRoute(): bool
136
    {
137 18
        return $this->isFlagSet(self::ROUTE_MAIN);
138
    }
139
140 12
    public function isRelatedRoute(): bool
141
    {
142 12
        return $this->isFlagSet(self::ROUTE_RELATED);
143
    }
144
145 93
    public function isRelationshipRoute(): bool
146
    {
147 93
        return $this->isFlagSet(self::ROUTE_RELATIONSHIP);
148
    }
149
150
    /**
151
     * Undocumented function
152
     *
153
     * @return static
154
     */
155 63
    public function setCollection()
156
    {
157 63
        return $this->selectFlag(self::RESOURCE_COLLECTION, [self::RESOURCE_COLLECTION, self::SINGLE_RESOURCE]);
158
    }
159
160
    /**
161
     * Undocumented function
162
     *
163
     * @return bool
164
     */
165 51
    public function isCollection(): bool
166
    {
167 51
        return $this->isFlagSet(self::RESOURCE_COLLECTION);
168
    }
169
170
    /**
171
     * Undocumented function
172
     *
173
     * @return static
174
     */
175 72
    public function setSingle()
176
    {
177 72
        return $this->selectFlag(self::SINGLE_RESOURCE, [self::RESOURCE_COLLECTION, self::SINGLE_RESOURCE]);
178
    }
179
180
    /**
181
     * Undocumented function
182
     *
183
     * @return bool
184
     */
185 27
    public function isSingle(): bool
186
    {
187 27
        return $this->isFlagSet(self::SINGLE_RESOURCE);
188
    }
189
190
    /**
191
     * Undocumented function
192
     *
193
     * @param int $relationship
194
     *
195
     * @return static
196
     */
197 84
    public function setRelationship(int $relationship)
198
    {
199 84
        $this->setRouteType(ValidateService::ROUTE_RELATIONSHIP);
200 84
        $this->selectFlag($relationship, [self::TO_MANY_RELATIONSHIP, self::TO_ONE_RELATIONSHIP]);
201
202 84
        return $this->isFlagSet(self::TO_ONE_RELATIONSHIP) ? $this->setSingle() : $this->setCollection();
203
    }
204
205
    /**
206
     * Undocumented function
207
     *
208
     * @return bool
209
     */
210 12
    public function isToMany(): bool
211
    {
212 12
        return $this->isFlagSet(self::TO_MANY_RELATIONSHIP);
213
    }
214
215
    /**
216
     * Undocumented function
217
     *
218
     * @return bool
219
     */
220 12
    public function isToOne(): bool
221
    {
222 12
        return $this->isFlagSet(self::TO_ONE_RELATIONSHIP);
223
    }
224
225 258
    public function containsAtLeastOneMember(
226
        array $expected,
227
        array $json,
228
        string $description = '',
229
        bool $returnResult = false,
230
        $code = 403
231
    ): bool {
232 258
        return $this->constraint(
233 258
            ContainsAtLeastOne::class,
234 258
            [$expected],
235 86
            $json,
236 86
            $description,
237 86
            $returnResult,
238 86
            $code
239
        );
240
    }
241
242 369
    public function containsOnlyAllowedMembers(
243
        array $allowed,
244
        array $json,
245
        string $description = '',
246
        bool $returnResult = false,
247
        $code = 403
248
    ): bool {
249 369
        return $this->constraint(
250 369
            ContainsOnlyAllowedMembers::class,
251 369
            [$allowed],
252 123
            $json,
253 123
            $description,
254 123
            $returnResult,
255 123
            $code
256
        );
257
    }
258
259 198
    public function validateMemberName(
260
        $name,
261
        bool $strict,
262
        string $description = '',
263
        bool $returnResult = false,
264
        $code = 403
265
    ): bool {
266 198
        return $this->constraint(
267 198
            MemberName::class,
268 198
            [$strict],
269 66
            $name,
270 66
            $description,
271 66
            $returnResult,
272 66
            $code
273
        );
274
    }
275
276 441
    protected function getRule(string $path)
277
    {
278 441
        return $this->version->getRule($path);
279
    }
280
281 360
    protected function throw(string $message, $code)
282
    {
283 360
        throw new ValidationException($message, $code);
284
    }
285
286 435
    protected function isValidArgument(int $argument, string $type, $value): void
287
    {
288 435
        switch ($type) {
289 435
            case 'array':
290 408
                $function = '\\is_array';
291 408
                break;
292 186
            case 'string':
293
            default:
294 186
                $function = '\\is_string';
295 186
                break;
296
        }
297
298 435
        if (call_user_func($function, $value) == false) {
299 45
            static::invalidArgument($argument, $type, $value);
300
        }
301 405
    }
302
303 18
    protected function dataIsRequired(): bool
304
    {
305
        return (
306 18
            (($this->isMainRoute() || $this->isRelatedRoute())
307 6
                && \in_array($this->method, ['POST', 'PATCH', 'PUT']))
308 12
            || (($this->isRelationshipRoute())
309 18
                && \in_array($this->method, ['POST', 'PATCH', 'PUT', 'DELETE']))
310
            );
311
    }
312
313 177
    protected function isAutomatic(): bool
314
    {
315 177
        return (($this->flags === null) || ($this->flags === 0));
316
    }
317
318 432
    private function constraint(
319
        string $class,
320
        array $consructorArgs,
321
        $inspected,
322
        string $description,
323
        bool $returnResult,
324
        $code
325
    ): bool {
326 432
        return (new $class(...$consructorArgs))->evaluate($inspected, $description, $returnResult, $code);
327
    }
328
}
329