Completed
Push — master ( 4fa802...7f958e )
by Bernhard
08:14
created

ValidatingConverter::fromJson()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 6
ccs 3
cts 3
cp 1
rs 9.4285
cc 1
eloc 3
nc 1
nop 2
crap 1
1
<?php
2
3
/*
4
 * This file is part of the webmozart/json package.
5
 *
6
 * (c) Bernhard Schussek <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Webmozart\Json\Validation;
13
14
use Webmozart\Json\Conversion\ConversionException;
15
use Webmozart\Json\Conversion\JsonConverter;
16
use Webmozart\Json\InvalidSchemaException;
17
use Webmozart\Json\JsonValidator;
18
19
/**
20
 * A decorator for a {@link JsonCoverter} that validates the JSON data.
21
 *
22
 * Pass the path to the schema to the constructor:
23
 *
24
 * ~~~php
25
 * $converter = ConfigFileConverter();
26
 *
27
 * // Decorate the converter
28
 * $converter = new ValidatingConverter($converter, __DIR__.'/schema.json');
29
 * ~~~
30
 *
31
 * Whenever you load or dump data as JSON, the JSON structure is validated
32
 * against the schema:
33
 *
34
 * ~~~php
35
 * $jsonDecoder = new JsonDecoder();
36
 * $configFile = $converter->fromJson($jsonDecoder->decode($json));
37
 *
38
 * $jsonEncoder = new JsonEncoder();
39
 * $jsonEncoder->encode($converter->toJson($configFile));
40
 * ~~~
41
 *
42
 * If you want to dynamically determine the path to the schema file, pass a
43
 * callable instead of the string. This is especially useful when versioning
44
 * your JSON data:
45
 *
46
 * ~~~php
47
 * $converter = ConfigFileConverter();
48
 *
49
 * // Calculate the schema path based on the "version" key in the JSON object
50
 * $getSchemaPath = function ($jsonData) {
51
 *     return __DIR__.'/schema-'.$jsonData->version.'.json';
52
 * }
53
 *
54
 * // Decorate the converter
55
 * $converter = new ValidatingConverter($converter, $getSchemaPath);
56
 * ~~~
57
 *
58
 * @since  1.3
59
 *
60
 * @author Bernhard Schussek <[email protected]>
61
 */
62
class ValidatingConverter implements JsonConverter
63
{
64
    /**
65
     * @var JsonConverter
66
     */
67
    private $innerConverter;
68
69
    /**
70
     * @var mixed
71
     */
72
    private $schema;
73
74
    /**
75
     * @var JsonValidator
76
     */
77
    private $jsonValidator;
78
79
    /**
80
     * Creates the converter.
81
     *
82
     * @param JsonConverter   $innerConverter The decorated converter.
83
     * @param string|callable $schema         The path to the schema file or a
84
     *                                        callable for calculating the path
85
     *                                        dynamically for a given JSON data.
86
     * @param JsonValidator   $jsonValidator  The JSON validator (optional).
0 ignored issues
show
Documentation introduced by
Should the type for parameter $jsonValidator not be null|JsonValidator?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
87
     */
88 6
    public function __construct(JsonConverter $innerConverter, $schema, JsonValidator $jsonValidator = null)
89
    {
90 6
        $this->innerConverter = $innerConverter;
91 6
        $this->schema = $schema;
92 6
        $this->jsonValidator = $jsonValidator ?: new JsonValidator();
93 6
    }
94
95
    /**
96
     * {@inheritdoc}
97
     */
98 4
    public function toJson($data, array $options = array())
99
    {
100 4
        $jsonData = $this->innerConverter->toJson($data, $options);
101
102 4
        $this->validate($jsonData);
103
104 2
        return $jsonData;
105
    }
106
107
    /**
108
     * {@inheritdoc}
109
     */
110 2
    public function fromJson($jsonData, array $options = array())
111
    {
112 2
        $this->validate($jsonData);
113
114 2
        return $this->innerConverter->fromJson($jsonData, $options);
115
    }
116
117 6
    private function validate($jsonData)
118
    {
119 6
        $schema = $this->schema;
120
121 6
        if (is_callable($schema)) {
122 2
            $schema = $schema($jsonData);
123
        }
124
125
        try {
126 6
            $errors = $this->jsonValidator->validate($jsonData, $schema);
127 1
        } catch (InvalidSchemaException $e) {
128 1
            throw new ConversionException(sprintf(
129 1
                'An error occurred while loading the JSON schema (%s): %s',
130 1
                is_string($schema) ? '"'.$schema.'"' : gettype($schema),
131 1
                $e->getMessage()
132 1
            ), 0, $e);
133
        }
134
135 5
        if (count($errors) > 0) {
136 1
            throw new ConversionException(sprintf(
137 1
                "The passed JSON did not match the schema:\n%s",
138 1
                implode("\n", $errors)
139
            ));
140
        }
141 4
    }
142
}
143