JsonSchema::getFile()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 1
1
<?php
2
3
namespace Abacaphiliac\Zend\Validator;
4
5
use JsonSchema\RefResolver;
6
use JsonSchema\Uri\UriResolver;
7
use JsonSchema\Uri\UriRetriever;
8
use JsonSchema\Validator;
9
use Zend\Json\Exception\RuntimeException;
10
use Zend\Json\Json;
11
use Zend\Validator\AbstractValidator;
12
use Zend\Validator\Exception;
13
14
class JsonSchema extends AbstractValidator
15
{
16
    /** @var string */
17
    private $file;
18
    
19
    /** @var string[] */
20
    private $messages = array();
21
22
    /** @var string[] */
23
    private $errorKeys = array();
24
    
25
    /** @var string */
26
    private $messagePrefix = '[';
27
    
28
    /** @var string */
29
    private $messageSuffix = ']';
30
    
31
    /** @var string */
32
    private $messageAttributeDelimiter = '] [';
33
34
    /**
35
     * JsonSchema constructor.
36
     * @param array|null|\Traversable $options
37
     */
38 13
    public function __construct($options = null)
39
    {
40 13
        $this->errorKeys = array(
41 13
            'property',
42 13
            'constraint',
43 13
            'message',
44
        );
45
        
46 13
        parent::__construct($options);
47 13
    }
48
49
    /**
50
     * Returns true if and only if $value meets the validation requirements
51
     *
52
     * If $value fails validation, then this method returns false, and
53
     * getMessages() will return an array of messages that explain why the
54
     * validation failed.
55
     *
56
     * @param  mixed $value
57
     * @return bool
58
     * @throws Exception\RuntimeException If validation of $value is impossible
59
     */
60 7
    public function isValid($value)
61
    {
62 7
        $schema = $this->getSchema();
63
        
64
        try {
65 5
            $decoded = $this->decodeValue($value);
66 5
        } catch (RuntimeException $e) {
67 1
            $this->messages = array(
68 1
                $e->getMessage(),
69
            );
70 1
            return false;
71
        }
72
        
73 4
        $validator = new Validator();
74 4
        $validator->check($decoded, $schema);
75
76 4
        if ($validator->isValid()) {
77 3
            return true;
78
        }
79
        
80 1
        $this->messages = array_map(array($this, 'formatError'), $validator->getErrors());
81
        
82 1
        return false;
83
    }
84
85
    /**
86
     * @param mixed[] $error
87
     * @return string
88
     */
89 2
    public function formatError(array $error)
90
    {
91
        // Get the error properties that should be returned to the user.
92 2
        $properties = array_intersect_key($error, array_flip($this->errorKeys));
93
94
        // Format error properties as bracket-delimited key-value-pairs.
95 2
        $message = urldecode(http_build_query($properties, null, $this->messageAttributeDelimiter));
96
97
        // Validation error may be returned as JSON. Replace quotes so that the message looks nice.
98 2
        return str_replace('"', "'", $this->messagePrefix . $message . $this->messageSuffix);
99
    }
100
101
    /**
102
     * @return \stdClass
103
     * @throws \Zend\Validator\Exception\RuntimeException
104
     */
105 7
    private function getSchema()
106
    {
107 7
        $file = $this->file;
108 7
        if (!$file) {
109 1
            throw new Exception\RuntimeException('Validator option `file` is required and cannot be empty.');
110
        }
111
112 6
        $url = parse_url($file);
113 6
        if (!array_key_exists('scheme', $url)) {
114 1
            $file = 'file://' . realpath($file);
115 1
        }
116
117 6
        $refResolver = new RefResolver(new UriRetriever(), new UriResolver());
118
119
        try {
120 6
            return $refResolver->resolve($file);
121 1
        } catch (\Exception $e) {
122 1
            throw new Exception\RuntimeException(
123 1
                sprintf('Could not load JSON Schema: %s', $e->getMessage()),
124 1
                $e->getCode(),
125
                $e
126 1
            );
127
        }
128
    }
129
130
    /**
131
     * @param mixed $value
132
     * @return \stdClass
133
     * @throws \Zend\Json\Exception\RuntimeException
134
     */
135 5
    private function decodeValue($value)
136
    {
137 5
        if ($value instanceof \stdClass) {
138 1
            return $value;
139
        }
140
        
141 4
        $encoded = $value;
142 4
        if (is_array($value)) {
143 1
            $encoded = Json::encode($value);
144 1
        }
145
146 4
        return Json::decode($encoded);
147
    }
148
149
    /**
150
     * @return string[]
151
     */
152 2
    public function getMessages()
153
    {
154 2
        return $this->messages;
155
    }
156
157
    /**
158
     * @return string
159
     */
160 1
    public function getFile()
161
    {
162 1
        return $this->file;
163
    }
164
165
    /**
166
     * @param string $file
167
     */
168 13
    public function setFile($file)
169
    {
170 13
        $this->file = $file;
171 13
    }
172
173
    /**
174
     * @return string[]
175
     */
176 1
    public function getErrorKeys()
177
    {
178 1
        return $this->errorKeys;
179
    }
180
181
    /**
182
     * @param string[] $errorKeys
183
     */
184 1
    public function setErrorKeys(array $errorKeys)
185
    {
186 1
        $this->errorKeys = $errorKeys;
187 1
    }
188
189
    /**
190
     * @return string
191
     */
192 1
    public function getMessagePrefix()
193
    {
194 1
        return $this->messagePrefix;
195
    }
196
197
    /**
198
     * @param string $messagePrefix
199
     */
200 1
    public function setMessagePrefix($messagePrefix)
201
    {
202 1
        $this->messagePrefix = $messagePrefix;
203 1
    }
204
205
    /**
206
     * @return string
207
     */
208 1
    public function getMessageSuffix()
209
    {
210 1
        return $this->messageSuffix;
211
    }
212
213
    /**
214
     * @param string $messageSuffix
215
     */
216 1
    public function setMessageSuffix($messageSuffix)
217
    {
218 1
        $this->messageSuffix = $messageSuffix;
219 1
    }
220
221
    /**
222
     * @return string
223
     */
224 1
    public function getMessageAttributeDelimiter()
225
    {
226 1
        return $this->messageAttributeDelimiter;
227
    }
228
229
    /**
230
     * @param string $messageAttributeDelimiter
231
     */
232 1
    public function setMessageAttributeDelimiter($messageAttributeDelimiter)
233
    {
234 1
        $this->messageAttributeDelimiter = $messageAttributeDelimiter;
235 1
    }
236
}
237