ValidatingConverter   A
last analyzed

Complexity

Total Complexity 9

Size/Duplication

Total Lines 85
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 100%

Importance

Changes 4
Bugs 1 Features 2
Metric Value
c 4
b 1
f 2
dl 0
loc 85
wmc 9
lcom 1
cbo 3
ccs 28
cts 28
cp 1
rs 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 2
A toJson() 0 8 1
A fromJson() 0 6 1
B validate() 0 25 5
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\ConversionFailedException;
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|null $schema         The path to the schema file
84
     *                                             or a callable for calculating
85
     *                                             the path dynamically for a
86
     *                                             given JSON data. If `null`,
87
     *                                             the schema is taken from the
88
     *                                             `$schema` property of the
89
     *                                             JSON data
90
     * @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...
91
     */
92 8
    public function __construct(JsonConverter $innerConverter, $schema = null, JsonValidator $jsonValidator = null)
93
    {
94 8
        $this->innerConverter = $innerConverter;
95 8
        $this->schema = $schema;
96 8
        $this->jsonValidator = $jsonValidator ?: new JsonValidator();
97 8
    }
98
99
    /**
100
     * {@inheritdoc}
101
     */
102 5
    public function toJson($data, array $options = array())
103
    {
104 5
        $jsonData = $this->innerConverter->toJson($data, $options);
105
106 5
        $this->validate($jsonData);
107
108 3
        return $jsonData;
109
    }
110
111
    /**
112
     * {@inheritdoc}
113
     */
114 3
    public function fromJson($jsonData, array $options = array())
115
    {
116 3
        $this->validate($jsonData);
117
118 3
        return $this->innerConverter->fromJson($jsonData, $options);
119
    }
120
121 8
    private function validate($jsonData)
122
    {
123 8
        $schema = $this->schema;
124
125 8
        if (is_callable($schema)) {
126 2
            $schema = $schema($jsonData);
127
        }
128
129
        try {
130 8
            $errors = $this->jsonValidator->validate($jsonData, $schema);
131 1
        } catch (InvalidSchemaException $e) {
132 1
            throw new ConversionFailedException(sprintf(
133 1
                'An error occurred while loading the JSON schema (%s): %s',
134 1
                is_string($schema) ? '"'.$schema.'"' : gettype($schema),
135 1
                $e->getMessage()
136 1
            ), 0, $e);
137
        }
138
139 7
        if (count($errors) > 0) {
140 1
            throw new ConversionFailedException(sprintf(
141 1
                "The passed JSON did not match the schema:\n%s",
142 1
                implode("\n", $errors)
143
            ));
144
        }
145 6
    }
146
}
147