ValidateService::dataIsRequired()   A
last analyzed

Complexity

Conditions 5
Paths 7

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 5

Importance

Changes 0
Metric Value
cc 5
eloc 5
nc 7
nop 0
dl 0
loc 7
ccs 5
cts 5
cp 1
crap 5
rs 9.6111
c 0
b 0
f 0
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
/**
25
 * Main class to validate documents using the JSON:API specification
26
 */
27
class ValidateService
28
{
29 1
    use CanThrowInvalidArgumentException;
30 1
    use HaveBitwiseFlag;
31
32 1
    use ValidateArrays;
33 1
    use ValidateAttributesObject;
34 1
    use ValidateErrorsObject;
35 1
    use ValidateJsonapiObject;
36 1
    use ValidateLinksObject;
37 1
    use ValidateMembers;
38 1
    use ValidateMetaObject;
39 1
    use ValidateRelationshipsObject;
40 1
    use ValidateResourceLinkage;
41 1
    use ValidateResourceObject;
42 1
    use ValidateStructure;
43
44
    public const ROUTE_MAIN = 1;
45
    public const ROUTE_RELATED = 2;
46
    public const ROUTE_RELATIONSHIP = 4;
47
    public const SINGLE_RESOURCE = 8;
48
    public const RESOURCE_COLLECTION = 16;
49
    public const TO_ONE_RELATIONSHIP = 32;
50
    public const TO_MANY_RELATIONSHIP = 64;
51
52
    /**
53
     * Undocumented variable
54
     *
55
     * @var VersionService
56
     */
57
    protected $version;
58
59
    /**
60
     * Activate the strict mode when checking members names.
61
     *
62
     * @var bool
63
     */
64
    protected $strict = true;
65
66
    /**
67
     * The HTTP method of the request
68
     *
69
     * @var string
70
     */
71
    private $method;
72
73
    /**
74
     * Create a new instance
75
     *
76
     * @param string|null $method  The HTTP method of the request
77
     * @param string|null $version The version of the JSON:API specification
78
     * @param bool        $strict  If true, activate the strict mode when checking members names
79
     *
80
     * @return void
81
     */
82 777
    public function __construct(string $method = null, string $version = null, bool $strict = true)
83
    {
84 777
        if ($method !== null) {
85 144
            $this->setMethod($method);
86
        }
87
88 777
        $this->version = new VersionService($version);
89 777
        $this->setStrictMode($strict);
90 777
    }
91
92
    /**
93
     * Set the strict mode
94
     *
95
     * @param bool $strict
96
     *
97
     * @return static
98
     */
99 777
    public function setStrictMode(bool $strict)
100
    {
101 777
        $this->strict = $strict;
102
103 777
        return $this;
104
    }
105
106
    /**
107
     * Set the version of the JSON:API specification
108
     *
109
     * @param string $version
110
     *
111
     * @return static
112
     */
113
    public function setVersion(string $version)
114
    {
115
        $this->version->setVersion($version);
116
117
        return $this;
118
    }
119
120
    /**
121
     * Set the HTTP method
122
     *
123
     * @param string $method
124
     *
125
     * @return static
126
     */
127 156
    public function setMethod(string $method)
128
    {
129 156
        $this->method = \strtoupper($method);
130
131 156
        return $this;
132
    }
133
134
    /**
135
     * Undocumented function
136
     *
137
     * @return boolean
138
     */
139 48
    public function isPost(): bool
140
    {
141 48
        return $this->method === 'POST';
142
    }
143
144
    /**
145
     * Undocumented function
146
     *
147
     * @return boolean
148
     */
149 18
    public function isUpdate(): bool
150
    {
151 18
        return \in_array($this->method, ['PATCH', 'PUT']);
152
    }
153
154
    /**
155
     * Undocumented function
156
     *
157
     * @return boolean
158
     */
159 18
    public function isDelete(): bool
160
    {
161 18
        return $this->method === 'DELETE';
162
    }
163
164
    /**
165
     * Undocumented function
166
     *
167
     * @param int $routeType
168
     *
169
     * @return static
170
     */
171 138
    public function setRouteType(int $routeType)
172
    {
173 138
        return $this->selectFlag($routeType, [self::ROUTE_MAIN, self::ROUTE_RELATED, self::ROUTE_RELATIONSHIP]);
174
    }
175
176
    /**
177
     * Undocumented function
178
     *
179
     * @return boolean
180
     */
181 18
    public function isMainRoute(): bool
182
    {
183 18
        return $this->isFlagSet(self::ROUTE_MAIN);
184
    }
185
186
    /**
187
     * Undocumented function
188
     *
189
     * @return boolean
190
     */
191 12
    public function isRelatedRoute(): bool
192
    {
193 12
        return $this->isFlagSet(self::ROUTE_RELATED);
194
    }
195
196
    /**
197
     * Undocumented function
198
     *
199
     * @return boolean
200
     */
201 93
    public function isRelationshipRoute(): bool
202
    {
203 93
        return $this->isFlagSet(self::ROUTE_RELATIONSHIP);
204
    }
205
206
    /**
207
     * Undocumented function
208
     *
209
     * @param bool $isCollection
210
     *
211
     * @return static
212
     */
213 63
    public function setCollection(bool $isCollection = true)
214
    {
215 63
        return $this->selectFlag(
216 63
            $isCollection ? self::RESOURCE_COLLECTION : self::SINGLE_RESOURCE,
217 63
            [self::RESOURCE_COLLECTION, self::SINGLE_RESOURCE]
218
        );
219
    }
220
221
    /**
222
     * Undocumented function
223
     *
224
     * @return bool
225
     */
226 51
    public function isCollection(): bool
227
    {
228 51
        return $this->isFlagSet(self::RESOURCE_COLLECTION);
229
    }
230
231
    /**
232
     * Undocumented function
233
     *
234
     * @param bool $isSingle
235
     *
236
     * @return static
237
     */
238 72
    public function setSingle(bool $isSingle = true)
239
    {
240 72
        return $this->selectFlag(
241 72
            $isSingle ? self::SINGLE_RESOURCE : self::RESOURCE_COLLECTION,
242 72
            [self::RESOURCE_COLLECTION, self::SINGLE_RESOURCE]
243
        );
244
    }
245
246
    /**
247
     * Undocumented function
248
     *
249
     * @return bool
250
     */
251 27
    public function isSingle(): bool
252
    {
253 27
        return $this->isFlagSet(self::SINGLE_RESOURCE);
254
    }
255
256
    /**
257
     * Undocumented function
258
     *
259
     * @param int $relationship
260
     *
261
     * @return static
262
     */
263 84
    public function setRelationship(int $relationship)
264
    {
265 84
        $this->setRouteType(ValidateService::ROUTE_RELATIONSHIP);
266 84
        $this->selectFlag($relationship, [self::TO_MANY_RELATIONSHIP, self::TO_ONE_RELATIONSHIP]);
267
268 84
        return $this->isFlagSet(self::TO_ONE_RELATIONSHIP) ? $this->setSingle() : $this->setCollection();
269
    }
270
271
    /**
272
     * Undocumented function
273
     *
274
     * @return bool
275
     */
276 12
    public function isToMany(): bool
277
    {
278 12
        return $this->isFlagSet(self::TO_MANY_RELATIONSHIP);
279
    }
280
281
    /**
282
     * Undocumented function
283
     *
284
     * @return bool
285
     */
286 12
    public function isToOne(): bool
287
    {
288 12
        return $this->isFlagSet(self::TO_ONE_RELATIONSHIP);
289
    }
290
291
    /**
292
     * Undocumented function
293
     *
294
     * @param array   $expected
295
     * @param array   $json
296
     * @param string  $description
297
     * @param integer $code
298
     *
299
     * @return void
300
     */
301 258
    public function containsAtLeastOneMember(
302
        array $expected,
303
        array $json,
304
        string $description = '',
305
        int $code = 403
306
    ): void {
307 258
        $this->constraint(
308 258
            ContainsAtLeastOne::class,
309 258
            [$expected],
310
            $json,
311
            $description,
312
            $code
313
        );
314 240
    }
315
316
    /**
317
     * Undocumented function
318
     *
319
     * @param array   $allowed
320
     * @param array   $json
321
     * @param string  $description
322
     * @param integer $code
323
     *
324
     * @return void
325
     */
326 369
    public function containsOnlyAllowedMembers(
327
        array $allowed,
328
        array $json,
329
        string $description = '',
330
        int $code = 403
331
    ): void {
332 369
        $this->constraint(
333 369
            ContainsOnlyAllowedMembers::class,
334 369
            [$allowed],
335
            $json,
336
            $description,
337
            $code
338
        );
339 321
    }
340
341
    /**
342
     * Undocumented function
343
     *
344
     * @param string  $name
345
     * @param boolean $strict
346
     * @param string  $description
347
     * @param integer $code
348
     *
349
     * @return void
350
     */
351 198
    public function validateMemberName(
352
        $name,
353
        bool $strict,
354
        string $description = '',
355
        int $code = 403
356
    ): void {
357 198
        $this->constraint(
358 198
            MemberName::class,
359 198
            [$strict],
360
            $name,
361
            $description,
362
            $code
363
        );
364 153
    }
365
366
    /**
367
     * Undocumented function
368
     *
369
     * @param string $path
370
     *
371
     * @return mixed
372
     * @throws \VGirol\JsonApiStructure\Exception\DotPathException
373
     */
374 441
    protected function getRule(string $path)
375
    {
376 441
        return $this->version->getRule($path);
377
    }
378
379
    /**
380
     * Undocumented function
381
     *
382
     * @param string $message
383
     * @param int    $code
384
     *
385
     * @return void
386
     * @throws \VGirol\JsonApiStructure\Exception\ValidationException
387
     */
388 363
    protected function throw(string $message, int $code)
389
    {
390 363
        throw new ValidationException($message, $code);
391
    }
392
393
    /**
394
     * Undocumented function
395
     *
396
     * @param integer $argument
397
     * @param string  $type
398
     * @param mixed  $value
399
     *
400
     * @return void
401
     */
402 444
    protected function isValidArgument(int $argument, string $type, $value): void
403
    {
404 444
        switch ($type) {
405 444
            case 'array':
406 417
                $function = '\\is_array';
407 417
                break;
408 186
            case 'string':
409
            default:
410 186
                $function = '\\is_string';
411 186
                break;
412
        }
413
414 444
        if (call_user_func($function, $value) == false) {
415 45
            static::invalidArgument($argument, $type, $value);
416
        }
417 414
    }
418
419
    /**
420
     * Undocumented function
421
     *
422
     * @return boolean
423
     */
424 18
    protected function dataIsRequired(): bool
425
    {
426
        return (
427 18
            (($this->isMainRoute() || $this->isRelatedRoute())
428 6
                && \in_array($this->method, ['POST', 'PATCH', 'PUT']))
429 12
            || (($this->isRelationshipRoute())
430 18
                && \in_array($this->method, ['POST', 'PATCH', 'PUT', 'DELETE']))
431
            );
432
    }
433
434
    /**
435
     * Undocumented function
436
     *
437
     * @return boolean
438
     */
439 177
    protected function isAutomatic(): bool
440
    {
441 177
        return (($this->flags === null) || ($this->flags === 0));
442
    }
443
444
    /**
445
     * Undocumented function
446
     *
447
     * @param string $class
448
     * @param array  $consructorArgs
449
     * @param mixed  $inspected
450
     * @param string $description
451
     * @param int    $code
452
     *
453
     * @return void
454
     */
455 432
    private function constraint(
456
        string $class,
457
        array $consructorArgs,
458
        $inspected,
459
        string $description,
460
        int $code
461
    ): void {
462 432
        (new $class(...$consructorArgs))->evaluate($inspected, $description, $code);
463 372
    }
464
}
465