Completed
Push — master ( bc7d7f...7a9596 )
by Théo
02:46
created

Json   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 86
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 14
dl 0
loc 86
c 0
b 0
f 0
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A validate() 0 15 4
A decode() 0 16 4
A __construct() 0 4 1
A lint() 0 6 2
A decodeFile() 0 22 3
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the box project.
7
 *
8
 * (c) Kevin Herrera <[email protected]>
9
 *     Théo Fidry <[email protected]>
10
 *
11
 * This source file is subject to the MIT license that is bundled
12
 * with this source code in the file LICENSE.
13
 */
14
15
namespace KevinGH\Box\Json;
16
17
use InvalidArgumentException;
18
use JsonSchema\Validator;
19
use Seld\JsonLint\JsonParser;
20
use Seld\JsonLint\ParsingException;
21
use stdClass;
22
23
final class Json
24
{
25
    private $linter;
26
    private $validator;
27
28
    public function __construct()
29
    {
30
        $this->linter = new JsonParser();
31
        $this->validator = new Validator();
32
    }
33
34
    public function decode(string $json): stdClass
35
    {
36
        $data = json_decode($json);
37
38
        if (JSON_ERROR_NONE !== ($error = json_last_error())) {
39
            if (JSON_ERROR_UTF8 === $error) {
40
                throw JsonValidationException::createDecodeException($error);
41
            }
42
43
            $this->lint($json);
44
            if (($result = $this->linter->lint($json)) instanceof ParsingException) {
45
                throw $result;
46
            }
47
        }
48
49
        return $data;
50
    }
51
52
    public function decodeFile(string $file): stdClass
53
    {
54
        if (false === is_file($file)) {
55
            throw new InvalidArgumentException(
56
                sprintf(
57
                    'The file "%s" does not exist.',
58
                    $file
59
                )
60
            );
61
        }
62
63
        if (false === ($json = @file_get_contents($file))) {
64
            throw new InvalidArgumentException(
65
                sprintf(
66
                    'Could not read the file "%s": %s',
67
                    $file,
68
                    error_get_last()['message']
69
                )
70
            );
71
        }
72
73
        return $this->decode($json);
74
    }
75
76
    public function lint(string $json): void
77
    {
78
        $result = $this->linter->lint($json);
79
80
        if ($result instanceof ParsingException) {
81
            throw $result;
82
        }
83
    }
84
85
    /**
86
     * Validates the decoded JSON data.
87
     *
88
     * @param string   $file   The JSON file
89
     * @param stdClass $json   The decoded JSON data
90
     * @param stdClass $schema The JSON schema
91
     *
92
     * @throws JsonValidationException If the JSON data failed validation
93
     */
94
    public function validate(string $file, stdClass $json, stdClass $schema): void
95
    {
96
        $validator = new Validator();
97
        $validator->check($json, $schema);
98
99
        if (!$validator->isValid()) {
100
            $errors = [];
101
102
            foreach ((array) $validator->getErrors() as $error) {
103
                $errors[] = ($error['property'] ? $error['property'].' : ' : '').$error['message'];
104
            }
105
106
            throw new JsonValidationException(
107
                '"'.$file.'" does not match the expected JSON schema',
108
                $errors
109
            );
110
        }
111
    }
112
}
113