Passed
Branch master (3615e8)
by Timothy
03:00
created

JsonSchema::setMessageAttributeDelimiter()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

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 4
ccs 3
cts 3
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 1
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 12
    public function __construct($options = null)
39
    {
40 12
        $this->errorKeys = array(
41 12
            'property',
42 12
            'constraint',
43 12
            'message',
44
        );
45
        
46 12
        parent::__construct($options);
47 12
    }
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 6
    public function isValid($value)
61
    {
62 6
        $schema = $this->getSchema();
63
        
64
        try {
65 4
            $decoded = $this->decodeValue($value);
66 4
        } catch (RuntimeException $e) {
67 1
            $this->messages = array(
68 1
                $e->getMessage(),
69
            );
70 1
            return false;
71
        }
72
        
73 3
        $validator = new Validator();
74 3
        $validator->check($decoded, $schema);
75
76 3
        if ($validator->isValid()) {
77 2
            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 6
    private function getSchema()
106
    {
107 6
        $file = $this->file;
108 6
        if (!$file) {
109 1
            throw new Exception\RuntimeException('Validator option `file` is required and cannot be empty.');
110
        }
111
112 5
        $url = parse_url($file);
113 5
        if (!array_key_exists('scheme', $url)) {
114 1
            $file = 'file://' . realpath($file);
115 1
        }
116
117 5
        $refResolver = new RefResolver(new UriRetriever(), new UriResolver());
118
119
        try {
120 5
            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 4
    private function decodeValue($value)
136
    {
137 4
        $encoded = $value;
138 4
        if (!is_scalar($value)) {
139 1
            $encoded = Json::encode($value);
140 1
        }
141
142 4
        return Json::decode($encoded);
143
    }
144
145
    /**
146
     * @return string[]
147
     */
148 2
    public function getMessages()
149
    {
150 2
        return $this->messages;
151
    }
152
153
    /**
154
     * @return string
155
     */
156 1
    public function getFile()
157
    {
158 1
        return $this->file;
159
    }
160
161
    /**
162
     * @param string $file
163
     */
164 12
    public function setFile($file)
165
    {
166 12
        $this->file = $file;
167 12
    }
168
169
    /**
170
     * @return string[]
171
     */
172 1
    public function getErrorKeys()
173
    {
174 1
        return $this->errorKeys;
175
    }
176
177
    /**
178
     * @param string[] $errorKeys
179
     */
180 1
    public function setErrorKeys(array $errorKeys)
181
    {
182 1
        $this->errorKeys = $errorKeys;
183 1
    }
184
185
    /**
186
     * @return string
187
     */
188 1
    public function getMessagePrefix()
189
    {
190 1
        return $this->messagePrefix;
191
    }
192
193
    /**
194
     * @param string $messagePrefix
195
     */
196 1
    public function setMessagePrefix($messagePrefix)
197
    {
198 1
        $this->messagePrefix = $messagePrefix;
199 1
    }
200
201
    /**
202
     * @return string
203
     */
204 1
    public function getMessageSuffix()
205
    {
206 1
        return $this->messageSuffix;
207
    }
208
209
    /**
210
     * @param string $messageSuffix
211
     */
212 1
    public function setMessageSuffix($messageSuffix)
213
    {
214 1
        $this->messageSuffix = $messageSuffix;
215 1
    }
216
217
    /**
218
     * @return string
219
     */
220 1
    public function getMessageAttributeDelimiter()
221
    {
222 1
        return $this->messageAttributeDelimiter;
223
    }
224
225
    /**
226
     * @param string $messageAttributeDelimiter
227
     */
228 1
    public function setMessageAttributeDelimiter($messageAttributeDelimiter)
229
    {
230 1
        $this->messageAttributeDelimiter = $messageAttributeDelimiter;
231 1
    }
232
}
233