Skip to content

Commit 7ca151c

Browse files
committed
Merge branch 'master' into zero-terminated-floats
2 parents 9bc877e + 77b7e38 commit 7ca151c

18 files changed

+335
-72
lines changed

.gitattributes

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/docs export-ignore
2+
/tests export-ignore
3+
.gitignore export-ignore
4+
.travis.yml export-ignore
5+
phpunit.dist.xml export-ignore

src/JsonSchema/Constraints/CollectionConstraint.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,12 @@ public function check($value, $schema = null, $path = null, $i = null)
2424
{
2525
// Verify minItems
2626
if (isset($schema->minItems) && count($value) < $schema->minItems) {
27-
$this->addError($path, "There must be a minimum of " . $schema->minItems . " items in the array");
27+
$this->addError($path, "There must be a minimum of " . $schema->minItems . " items in the array", 'minItems', array('minItems' => $schema->minItems,));
2828
}
2929

3030
// Verify maxItems
3131
if (isset($schema->maxItems) && count($value) > $schema->maxItems) {
32-
$this->addError($path, "There must be a maximum of " . $schema->maxItems . " items in the array");
32+
$this->addError($path, "There must be a maximum of " . $schema->maxItems . " items in the array", 'maxItems', array('maxItems' => $schema->maxItems,));
3333
}
3434

3535
// Verify uniqueItems
@@ -39,7 +39,7 @@ public function check($value, $schema = null, $path = null, $i = null)
3939
$unique = array_map(function($e) { return var_export($e, true); }, $value);
4040
}
4141
if (count(array_unique($unique)) != count($value)) {
42-
$this->addError($path, "There are no duplicates allowed in the array");
42+
$this->addError($path, "There are no duplicates allowed in the array", 'uniqueItems');
4343
}
4444
}
4545

@@ -92,7 +92,7 @@ protected function validateItems($value, $schema = null, $path = null, $i = null
9292
$this->checkUndefined($v, $schema->additionalItems, $path, $k);
9393
} else {
9494
$this->addError(
95-
$path, 'The item ' . $i . '[' . $k . '] is not defined and the definition does not allow additional items');
95+
$path, 'The item ' . $i . '[' . $k . '] is not defined and the definition does not allow additional items', 'additionalItems', array('additionalItems' => $schema->additionalItems,));
9696
}
9797
} else {
9898
// Should be valid against an empty schema

src/JsonSchema/Constraints/Constraint.php

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,21 @@ abstract class Constraint implements ConstraintInterface
2727
const CHECK_MODE_NORMAL = 1;
2828
const CHECK_MODE_TYPE_CAST = 2;
2929

30+
/**
31+
* @var null|Factory
32+
*/
33+
private $factory;
34+
3035
/**
3136
* @param int $checkMode
3237
* @param UriRetriever $uriRetriever
38+
* @param Factory $factory
3339
*/
34-
public function __construct($checkMode = self::CHECK_MODE_NORMAL, UriRetriever $uriRetriever = null)
40+
public function __construct($checkMode = self::CHECK_MODE_NORMAL, UriRetriever $uriRetriever = null, Factory $factory = null)
3541
{
3642
$this->checkMode = $checkMode;
3743
$this->uriRetriever = $uriRetriever;
44+
$this->factory = $factory;
3845
}
3946

4047
/**
@@ -50,6 +57,18 @@ public function getUriRetriever()
5057
return $this->uriRetriever;
5158
}
5259

60+
/**
61+
* @return Factory
62+
*/
63+
public function getFactory()
64+
{
65+
if (!$this->factory) {
66+
$this->factory = new Factory($this->getUriRetriever());
67+
}
68+
69+
return $this->factory;
70+
}
71+
5372
/**
5473
* @param UriRetriever $uriRetriever
5574
*/
@@ -61,12 +80,20 @@ public function setUriRetriever(UriRetriever $uriRetriever)
6180
/**
6281
* {@inheritDoc}
6382
*/
64-
public function addError($path, $message)
83+
public function addError($path, $message, $constraint='', array $more=null)
6584
{
66-
$this->errors[] = array(
85+
$error = array(
6786
'property' => $path,
68-
'message' => $message
87+
'message' => $message,
88+
'constraint' => $constraint,
6989
);
90+
91+
if (is_array($more) && count($more) > 0)
92+
{
93+
$error += $more;
94+
}
95+
96+
$this->errors[] = $error;
7097
}
7198

7299
/**
@@ -137,7 +164,7 @@ protected function incrementPath($path, $i)
137164
*/
138165
protected function checkArray($value, $schema = null, $path = null, $i = null)
139166
{
140-
$validator = new CollectionConstraint($this->checkMode, $this->uriRetriever);
167+
$validator = $this->getFactory()->createInstanceFor('collection');
141168
$validator->check($value, $schema, $path, $i);
142169

143170
$this->addErrors($validator->getErrors());
@@ -154,7 +181,7 @@ protected function checkArray($value, $schema = null, $path = null, $i = null)
154181
*/
155182
protected function checkObject($value, $schema = null, $path = null, $i = null, $patternProperties = null)
156183
{
157-
$validator = new ObjectConstraint($this->checkMode, $this->uriRetriever);
184+
$validator = $this->getFactory()->createInstanceFor('object');
158185
$validator->check($value, $schema, $path, $i, $patternProperties);
159186

160187
$this->addErrors($validator->getErrors());
@@ -170,7 +197,7 @@ protected function checkObject($value, $schema = null, $path = null, $i = null,
170197
*/
171198
protected function checkType($value, $schema = null, $path = null, $i = null)
172199
{
173-
$validator = new TypeConstraint($this->checkMode, $this->uriRetriever);
200+
$validator = $this->getFactory()->createInstanceFor('type');
174201
$validator->check($value, $schema, $path, $i);
175202

176203
$this->addErrors($validator->getErrors());
@@ -186,7 +213,7 @@ protected function checkType($value, $schema = null, $path = null, $i = null)
186213
*/
187214
protected function checkUndefined($value, $schema = null, $path = null, $i = null)
188215
{
189-
$validator = new UndefinedConstraint($this->checkMode, $this->uriRetriever);
216+
$validator = $this->getFactory()->createInstanceFor('undefined');
190217
$validator->check($value, $schema, $path, $i);
191218

192219
$this->addErrors($validator->getErrors());
@@ -202,7 +229,7 @@ protected function checkUndefined($value, $schema = null, $path = null, $i = nul
202229
*/
203230
protected function checkString($value, $schema = null, $path = null, $i = null)
204231
{
205-
$validator = new StringConstraint($this->checkMode, $this->uriRetriever);
232+
$validator = $this->getFactory()->createInstanceFor('string');
206233
$validator->check($value, $schema, $path, $i);
207234

208235
$this->addErrors($validator->getErrors());
@@ -218,7 +245,7 @@ protected function checkString($value, $schema = null, $path = null, $i = null)
218245
*/
219246
protected function checkNumber($value, $schema = null, $path = null, $i = null)
220247
{
221-
$validator = new NumberConstraint($this->checkMode, $this->uriRetriever);
248+
$validator = $this->getFactory()->createInstanceFor('number');
222249
$validator->check($value, $schema, $path, $i);
223250

224251
$this->addErrors($validator->getErrors());
@@ -234,15 +261,15 @@ protected function checkNumber($value, $schema = null, $path = null, $i = null)
234261
*/
235262
protected function checkEnum($value, $schema = null, $path = null, $i = null)
236263
{
237-
$validator = new EnumConstraint($this->checkMode, $this->uriRetriever);
264+
$validator = $this->getFactory()->createInstanceFor('enum');
238265
$validator->check($value, $schema, $path, $i);
239266

240267
$this->addErrors($validator->getErrors());
241268
}
242269

243270
protected function checkFormat($value, $schema = null, $path = null, $i = null)
244271
{
245-
$validator = new FormatConstraint($this->checkMode, $this->uriRetriever);
272+
$validator = $this->getFactory()->createInstanceFor('format');
246273
$validator->check($value, $schema, $path, $i);
247274

248275
$this->addErrors($validator->getErrors());

src/JsonSchema/Constraints/ConstraintInterface.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,12 @@ public function addErrors(array $errors);
3333
/**
3434
* adds an error
3535
*
36-
* @param $path
37-
* @param $message
36+
* @param string $path
37+
* @param string $message
38+
* @param string $constraint the constraint/rule that is broken, e.g.: 'minLength'
39+
* @param array $more more array elements to add to the error
3840
*/
39-
public function addError($path, $message);
41+
public function addError($path, $message, $constraint='', array $more=null);
4042

4143
/**
4244
* checks if the validator has not raised errors

src/JsonSchema/Constraints/EnumConstraint.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,6 @@ public function check($element, $schema = null, $path = null, $i = null)
4141
}
4242
}
4343

44-
$this->addError($path, "Does not have a value in the enumeration " . print_r($schema->enum, true));
44+
$this->addError($path, "Does not have a value in the enumeration " . print_r($schema->enum, true), 'enum', array('enum' => $schema->enum,));
4545
}
4646
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the JsonSchema package.
5+
*
6+
* For the full copyright and license information, please view the LICENSE
7+
* file that was distributed with this source code.
8+
*/
9+
10+
namespace JsonSchema\Constraints;
11+
12+
use JsonSchema\Exception\InvalidArgumentException;
13+
use JsonSchema\Uri\UriRetriever;
14+
use JsonSchema\Validator;
15+
16+
/**
17+
* Factory for centralize constraint initialization.
18+
*/
19+
class Factory
20+
{
21+
/**
22+
* @var UriRetriever
23+
*/
24+
protected $uriRetriever;
25+
26+
/**
27+
* @param UriRetriever $uriRetriever
28+
*/
29+
public function __construct(UriRetriever $uriRetriever = null)
30+
{
31+
if (!$uriRetriever) {
32+
$uriRetriever = new UriRetriever();
33+
}
34+
35+
$this->uriRetriever = $uriRetriever;
36+
}
37+
38+
/**
39+
* @return UriRetriever
40+
*/
41+
public function getUriRetriever()
42+
{
43+
return $this->uriRetriever;
44+
}
45+
46+
/**
47+
* Create a constraint instance for the given constraint name.
48+
*
49+
* @param string $constraintName
50+
* @return ConstraintInterface|ObjectConstraint
51+
* @throws InvalidArgumentException if is not possible create the constraint instance.
52+
*/
53+
public function createInstanceFor($constraintName)
54+
{
55+
switch ($constraintName) {
56+
case 'array':
57+
case 'collection':
58+
return new CollectionConstraint(Constraint::CHECK_MODE_NORMAL, $this->uriRetriever, $this);
59+
case 'object':
60+
return new ObjectConstraint(Constraint::CHECK_MODE_NORMAL, $this->uriRetriever, $this);
61+
case 'type':
62+
return new TypeConstraint(Constraint::CHECK_MODE_NORMAL, $this->uriRetriever, $this);
63+
case 'undefined':
64+
return new UndefinedConstraint(Constraint::CHECK_MODE_NORMAL, $this->uriRetriever, $this);
65+
case 'string':
66+
return new StringConstraint(Constraint::CHECK_MODE_NORMAL, $this->uriRetriever, $this);
67+
case 'number':
68+
return new NumberConstraint(Constraint::CHECK_MODE_NORMAL, $this->uriRetriever, $this);
69+
case 'enum':
70+
return new EnumConstraint(Constraint::CHECK_MODE_NORMAL, $this->uriRetriever, $this);
71+
case 'format':
72+
return new FormatConstraint(Constraint::CHECK_MODE_NORMAL, $this->uriRetriever, $this);
73+
case 'schema':
74+
return new SchemaConstraint(Constraint::CHECK_MODE_NORMAL, $this->uriRetriever, $this);
75+
case 'validator':
76+
return new Validator(Constraint::CHECK_MODE_NORMAL, $this->uriRetriever, $this);
77+
}
78+
79+
throw new InvalidArgumentException('Unknown constraint ' . $constraintName);
80+
}
81+
}

src/JsonSchema/Constraints/FormatConstraint.php

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,13 @@ public function check($element, $schema = null, $path = null, $i = null)
2929
switch ($schema->format) {
3030
case 'date':
3131
if (!$date = $this->validateDateTime($element, 'Y-m-d')) {
32-
$this->addError($path, sprintf('Invalid date %s, expected format YYYY-MM-DD', json_encode($element)));
32+
$this->addError($path, sprintf('Invalid date %s, expected format YYYY-MM-DD', json_encode($element)), 'format', array('format' => $schema->format,));
3333
}
3434
break;
3535

3636
case 'time':
3737
if (!$this->validateDateTime($element, 'H:i:s')) {
38-
$this->addError($path, sprintf('Invalid time %s, expected format hh:mm:ss', json_encode($element)));
38+
$this->addError($path, sprintf('Invalid time %s, expected format hh:mm:ss', json_encode($element)), 'format', array('format' => $schema->format,));
3939
}
4040
break;
4141

@@ -45,74 +45,79 @@ public function check($element, $schema = null, $path = null, $i = null)
4545
!$this->validateDateTime($element, 'Y-m-d\TH:i:sP') &&
4646
!$this->validateDateTime($element, 'Y-m-d\TH:i:sO')
4747
) {
48-
$this->addError($path, sprintf('Invalid date-time %s, expected format YYYY-MM-DDThh:mm:ssZ or YYYY-MM-DDThh:mm:ss+hh:mm', json_encode($element)));
48+
$this->addError($path, sprintf('Invalid date-time %s, expected format YYYY-MM-DDThh:mm:ssZ or YYYY-MM-DDThh:mm:ss+hh:mm', json_encode($element)), 'format', array('format' => $schema->format,));
4949
}
5050
break;
5151

5252
case 'utc-millisec':
5353
if (!$this->validateDateTime($element, 'U')) {
54-
$this->addError($path, sprintf('Invalid time %s, expected integer of milliseconds since Epoch', json_encode($element)));
54+
$this->addError($path, sprintf('Invalid time %s, expected integer of milliseconds since Epoch', json_encode($element)), 'format', array('format' => $schema->format,));
5555
}
5656
break;
5757

5858
case 'regex':
5959
if (!$this->validateRegex($element)) {
60-
$this->addError($path, 'Invalid regex format ' . $element);
60+
$this->addError($path, 'Invalid regex format ' . $element, 'format', array('format' => $schema->format,));
6161
}
6262
break;
6363

6464
case 'color':
6565
if (!$this->validateColor($element)) {
66-
$this->addError($path, "Invalid color");
66+
$this->addError($path, "Invalid color", 'format', array('format' => $schema->format,));
6767
}
6868
break;
6969

7070
case 'style':
7171
if (!$this->validateStyle($element)) {
72-
$this->addError($path, "Invalid style");
72+
$this->addError($path, "Invalid style", 'format', array('format' => $schema->format,));
7373
}
7474
break;
7575

7676
case 'phone':
7777
if (!$this->validatePhone($element)) {
78-
$this->addError($path, "Invalid phone number");
78+
$this->addError($path, "Invalid phone number", 'format', array('format' => $schema->format,));
7979
}
8080
break;
8181

8282
case 'uri':
8383
if (null === filter_var($element, FILTER_VALIDATE_URL, FILTER_NULL_ON_FAILURE)) {
84-
$this->addError($path, "Invalid URL format");
84+
$this->addError($path, "Invalid URL format", 'format', array('format' => $schema->format,));
8585
}
8686
break;
8787

8888
case 'email':
8989
if (null === filter_var($element, FILTER_VALIDATE_EMAIL, FILTER_NULL_ON_FAILURE)) {
90-
$this->addError($path, "Invalid email");
90+
$this->addError($path, "Invalid email", 'format', array('format' => $schema->format,));
9191
}
9292
break;
9393

9494
case 'ip-address':
9595
case 'ipv4':
9696
if (null === filter_var($element, FILTER_VALIDATE_IP, FILTER_NULL_ON_FAILURE | FILTER_FLAG_IPV4)) {
97-
$this->addError($path, "Invalid IP address");
97+
$this->addError($path, "Invalid IP address", 'format', array('format' => $schema->format,));
9898
}
9999
break;
100100

101101
case 'ipv6':
102102
if (null === filter_var($element, FILTER_VALIDATE_IP, FILTER_NULL_ON_FAILURE | FILTER_FLAG_IPV6)) {
103-
$this->addError($path, "Invalid IP address");
103+
$this->addError($path, "Invalid IP address", 'format', array('format' => $schema->format,));
104104
}
105105
break;
106106

107107
case 'host-name':
108108
case 'hostname':
109109
if (!$this->validateHostname($element)) {
110-
$this->addError($path, "Invalid hostname");
110+
$this->addError($path, "Invalid hostname", 'format', array('format' => $schema->format,));
111111
}
112112
break;
113113

114114
default:
115-
// Do nothing so that custom formats can be used.
115+
// Empty as it should be:
116+
// The value of this keyword is called a format attribute. It MUST be a string.
117+
// A format attribute can generally only validate a given set of instance types.
118+
// If the type of the instance to validate is not in this set, validation for
119+
// this format attribute and instance SHOULD succeed.
120+
// http://json-schema.org/latest/json-schema-validation.html#anchor105
116121
break;
117122
}
118123
}

0 commit comments

Comments
 (0)