Skip to content

Commit ddabcf8

Browse files
authored
Merge pull request #286 from boekkooi-fresh/array-as-object
Support json_decode assoc
2 parents c269bda + dd5717a commit ddabcf8

19 files changed

+333
-76
lines changed

src/JsonSchema/Constraints/CollectionConstraint.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ protected function validateItems($value, $schema = null, $path = null, $i = null
7676
// Reset errors if needed
7777
if (isset($secondErrors) && count($secondErrors) < count($this->getErrors())) {
7878
$this->errors = $secondErrors;
79-
} else if (isset($secondErrors) && count($secondErrors) === count($this->getErrors())) {
79+
} elseif (isset($secondErrors) && count($secondErrors) === count($this->getErrors())) {
8080
$this->errors = $initErrors;
8181
}
8282
}
@@ -102,7 +102,7 @@ protected function validateItems($value, $schema = null, $path = null, $i = null
102102
}
103103

104104
// Treat when we have more schema definitions than values, not for empty arrays
105-
if(count($value) > 0) {
105+
if (count($value) > 0) {
106106
for ($k = count($value); $k < count($schema->items); $k++) {
107107
$this->checkUndefined(new UndefinedConstraint(), $schema->items[$k], $path, $k);
108108
}

src/JsonSchema/Constraints/Constraint.php

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
namespace JsonSchema\Constraints;
1111

1212
use JsonSchema\Uri\UriRetriever;
13+
use JsonSchema\Validator;
1314

1415
/**
1516
* The Base Constraints, all Validators should extend this class
@@ -49,8 +50,7 @@ public function __construct($checkMode = self::CHECK_MODE_NORMAL, UriRetriever $
4950
*/
5051
public function getUriRetriever()
5152
{
52-
if (is_null($this->uriRetriever))
53-
{
53+
if (is_null($this->uriRetriever)) {
5454
$this->setUriRetriever(new UriRetriever);
5555
}
5656

@@ -63,7 +63,7 @@ public function getUriRetriever()
6363
public function getFactory()
6464
{
6565
if (!$this->factory) {
66-
$this->factory = new Factory($this->getUriRetriever());
66+
$this->factory = new Factory($this->getUriRetriever(), $this->checkMode);
6767
}
6868

6969
return $this->factory;
@@ -288,4 +288,14 @@ protected function retrieveUri($uri)
288288
// TODO validate using schema
289289
return $jsonSchema;
290290
}
291+
292+
/**
293+
* Get the type check based on the set check mode.
294+
*
295+
* @return TypeCheck\TypeCheckInterface
296+
*/
297+
protected function getTypeCheck()
298+
{
299+
return $this->getFactory()->getTypeCheck();
300+
}
291301
}

src/JsonSchema/Constraints/EnumConstraint.php

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
*/
99

1010
namespace JsonSchema\Constraints;
11+
use JsonSchema\Validator;
1112

1213
/**
1314
* The EnumConstraint Constraints, validates an element against a given set of possibilities
@@ -26,17 +27,23 @@ public function check($element, $schema = null, $path = null, $i = null)
2627
if ($element instanceof UndefinedConstraint && (!isset($schema->required) || !$schema->required)) {
2728
return;
2829
}
30+
$type = gettype($element);
2931

3032
foreach ($schema->enum as $enum) {
31-
$type = gettype($element);
33+
$enumType = gettype($enum);
34+
if ($this->checkMode === self::CHECK_MODE_TYPE_CAST && $type == "array" && $enumType == "object") {
35+
if ((object)$element == $enum) {
36+
return;
37+
}
38+
}
39+
3240
if ($type === gettype($enum)) {
3341
if ($type == "object") {
34-
if ($element == $enum)
42+
if ($element == $enum) {
3543
return;
36-
} else {
37-
if ($element === $enum)
38-
return;
39-
44+
}
45+
} elseif ($element === $enum) {
46+
return;
4047
}
4148
}
4249
}

src/JsonSchema/Constraints/Factory.php

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
use JsonSchema\Exception\InvalidArgumentException;
1313
use JsonSchema\Uri\UriRetriever;
14-
use JsonSchema\Validator;
1514

1615
/**
1716
* Factory for centralize constraint initialization.
@@ -23,6 +22,16 @@ class Factory
2322
*/
2423
protected $uriRetriever;
2524

25+
/**
26+
* @var int
27+
*/
28+
private $checkMode;
29+
30+
/**
31+
* @var TypeCheck\TypeCheckInterface[]
32+
*/
33+
private $typeCheck = array();
34+
2635
/**
2736
* @var array $constraintMap
2837
*/
@@ -43,13 +52,14 @@ class Factory
4352
/**
4453
* @param UriRetriever $uriRetriever
4554
*/
46-
public function __construct(UriRetriever $uriRetriever = null)
55+
public function __construct(UriRetriever $uriRetriever = null, $checkMode = Constraint::CHECK_MODE_NORMAL)
4756
{
4857
if (!$uriRetriever) {
4958
$uriRetriever = new UriRetriever();
5059
}
5160

5261
$this->uriRetriever = $uriRetriever;
62+
$this->checkMode = $checkMode;
5363
}
5464

5565
/**
@@ -60,23 +70,36 @@ public function getUriRetriever()
6070
return $this->uriRetriever;
6171
}
6272

73+
public function getTypeCheck()
74+
{
75+
if (!isset($this->typeCheck[$this->checkMode])) {
76+
if ($this->checkMode === Constraint::CHECK_MODE_TYPE_CAST) {
77+
$this->typeCheck[Constraint::CHECK_MODE_TYPE_CAST] = new TypeCheck\LooseTypeCheck();
78+
} else {
79+
$this->typeCheck[$this->checkMode] = new TypeCheck\StrictTypeCheck();
80+
}
81+
}
82+
83+
return $this->typeCheck[$this->checkMode];
84+
}
85+
6386
/**
6487
* @param string $name
6588
* @param string $class
6689
* @return Factory
6790
*/
6891
public function setConstraintClass($name, $class)
6992
{
70-
// Ensure class exists
71-
if (!class_exists($class)) {
72-
throw new InvalidArgumentException('Unknown constraint ' . $name);
73-
}
74-
// Ensure class is appropriate
75-
if (!in_array('JsonSchema\Constraints\ConstraintInterface', class_implements($class))) {
76-
throw new InvalidArgumentException('Invalid class ' . $name);
77-
}
78-
$this->constraintMap[$name] = $class;
79-
return $this;
93+
// Ensure class exists
94+
if (!class_exists($class)) {
95+
throw new InvalidArgumentException('Unknown constraint ' . $name);
96+
}
97+
// Ensure class is appropriate
98+
if (!in_array('JsonSchema\Constraints\ConstraintInterface', class_implements($class))) {
99+
throw new InvalidArgumentException('Invalid class ' . $name);
100+
}
101+
$this->constraintMap[$name] = $class;
102+
return $this;
80103
}
81104

82105
/**
@@ -89,7 +112,7 @@ public function setConstraintClass($name, $class)
89112
public function createInstanceFor($constraintName)
90113
{
91114
if (array_key_exists($constraintName, $this->constraintMap)) {
92-
return new $this->constraintMap[$constraintName](Constraint::CHECK_MODE_NORMAL, $this->uriRetriever, $this);
115+
return new $this->constraintMap[$constraintName]($this->checkMode, $this->uriRetriever, $this);
93116
}
94117
throw new InvalidArgumentException('Unknown constraint ' . $constraintName);
95118
}

src/JsonSchema/Constraints/NumberConstraint.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,13 @@ public function check($element, $schema = null, $path = null, $i = null)
2727
if (isset($schema->minimum)) {
2828
if ($schema->exclusiveMinimum && $element <= $schema->minimum) {
2929
$this->addError($path, "Must have a minimum value of " . $schema->minimum, 'exclusiveMinimum', array('minimum' => $schema->minimum,));
30-
} else if ($element < $schema->minimum) {
30+
} elseif ($element < $schema->minimum) {
3131
$this->addError($path, "Must have a minimum value of " . $schema->minimum, 'minimum', array('minimum' => $schema->minimum,));
3232
}
3333
} else {
3434
$this->addError($path, "Use of exclusiveMinimum requires presence of minimum", 'missingMinimum');
3535
}
36-
} else if (isset($schema->minimum) && $element < $schema->minimum) {
36+
} elseif (isset($schema->minimum) && $element < $schema->minimum) {
3737
$this->addError($path, "Must have a minimum value of " . $schema->minimum, 'minimum', array('minimum' => $schema->minimum,));
3838
}
3939

@@ -42,13 +42,13 @@ public function check($element, $schema = null, $path = null, $i = null)
4242
if (isset($schema->maximum)) {
4343
if ($schema->exclusiveMaximum && $element >= $schema->maximum) {
4444
$this->addError($path, "Must have a maximum value of " . $schema->maximum, 'exclusiveMaximum', array('maximum' => $schema->maximum,));
45-
} else if ($element > $schema->maximum) {
45+
} elseif ($element > $schema->maximum) {
4646
$this->addError($path, "Must have a maximum value of " . $schema->maximum, 'maximum', array('maximum' => $schema->maximum,));
4747
}
4848
} else {
4949
$this->addError($path, "Use of exclusiveMaximum requires presence of maximum", 'missingMaximum');
5050
}
51-
} else if (isset($schema->maximum) && $element > $schema->maximum) {
51+
} elseif (isset($schema->maximum) && $element > $schema->maximum) {
5252
$this->addError($path, "Must have a maximum value of " . $schema->maximum, 'maximum', array('maximum' => $schema->maximum,));
5353
}
5454

src/JsonSchema/Constraints/ObjectConstraint.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class ObjectConstraint extends Constraint
2020
/**
2121
* {@inheritDoc}
2222
*/
23-
function check($element, $definition = null, $path = null, $additionalProp = null, $patternProperties = null)
23+
public function check($element, $definition = null, $path = null, $additionalProp = null, $patternProperties = null)
2424
{
2525
if ($element instanceof UndefinedConstraint) {
2626
return;
@@ -161,13 +161,13 @@ protected function getProperty($element, $property, $fallback = null)
161161
protected function validateMinMaxConstraint($element, $objectDefinition, $path) {
162162
// Verify minimum number of properties
163163
if (isset($objectDefinition->minProperties) && !is_object($objectDefinition->minProperties)) {
164-
if (count(get_object_vars($element)) < $objectDefinition->minProperties) {
164+
if ($this->getTypeCheck()->propertyCount($element) < $objectDefinition->minProperties) {
165165
$this->addError($path, "Must contain a minimum of " . $objectDefinition->minProperties . " properties", 'minProperties', array('minProperties' => $objectDefinition->minProperties,));
166166
}
167167
}
168168
// Verify maximum number of properties
169169
if (isset($objectDefinition->maxProperties) && !is_object($objectDefinition->maxProperties)) {
170-
if (count(get_object_vars($element)) > $objectDefinition->maxProperties) {
170+
if ($this->getTypeCheck()->propertyCount($element) > $objectDefinition->maxProperties) {
171171
$this->addError($path, "Must contain no more than " . $objectDefinition->maxProperties . " properties", 'maxProperties', array('maxProperties' => $objectDefinition->maxProperties,));
172172
}
173173
}

src/JsonSchema/Constraints/SchemaConstraint.php

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,16 @@ public function check($element, $schema = null, $path = null, $i = null)
2727
if ($schema !== null) {
2828
// passed schema
2929
$this->checkUndefined($element, $schema, '', '');
30-
} elseif (property_exists($element, $this->inlineSchemaProperty)) {
30+
} elseif ($this->getTypeCheck()->propertyExists($element, $this->inlineSchemaProperty)) {
31+
$inlineSchema = $this->getTypeCheck()->propertyGet($element, $this->inlineSchemaProperty);
32+
if (is_array($inlineSchema)) {
33+
$inlineSchema = json_decode(json_encode($inlineSchema));
34+
}
35+
3136
// inline schema
32-
$this->checkUndefined($element, $element->{$this->inlineSchemaProperty}, '', '');
37+
$this->checkUndefined($element, $inlineSchema, '', '');
3338
} else {
3439
throw new InvalidArgumentException('no schema found to verify against');
3540
}
3641
}
37-
}
42+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
3+
namespace JsonSchema\Constraints\TypeCheck;
4+
5+
class LooseTypeCheck implements TypeCheckInterface
6+
{
7+
public static function isObject($value)
8+
{
9+
return
10+
is_object($value) ||
11+
(is_array($value) && (count($value) == 0 || self::isAssociativeArray($value)));
12+
}
13+
14+
public static function isArray($value)
15+
{
16+
return
17+
is_array($value) &&
18+
(count($value) == 0 || !self::isAssociativeArray($value));
19+
}
20+
21+
public static function propertyGet($value, $property)
22+
{
23+
if (is_object($value)) {
24+
return $value->{$property};
25+
}
26+
27+
return $value[$property];
28+
}
29+
30+
public static function propertyExists($value, $property)
31+
{
32+
if (is_object($value)) {
33+
return property_exists($value, $property);
34+
}
35+
36+
return array_key_exists($property, $value);
37+
}
38+
39+
public static function propertyCount($value)
40+
{
41+
if (is_object($value)) {
42+
return count(get_object_vars($value));
43+
}
44+
45+
return count($value);
46+
}
47+
48+
/**
49+
* Check if the provided array is associative or not
50+
*
51+
* @param array $arr
52+
*
53+
* @return bool
54+
*/
55+
private static function isAssociativeArray($arr)
56+
{
57+
return (array_keys($arr) !== range(0, count($arr) - 1));
58+
}
59+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
namespace JsonSchema\Constraints\TypeCheck;
4+
5+
class StrictTypeCheck implements TypeCheckInterface
6+
{
7+
public static function isObject($value)
8+
{
9+
return is_object($value);
10+
}
11+
12+
public static function isArray($value)
13+
{
14+
return is_array($value);
15+
}
16+
17+
public static function propertyGet($value, $property)
18+
{
19+
return $value->{$property};
20+
}
21+
22+
public static function propertyExists($value, $property)
23+
{
24+
return property_exists($value, $property);
25+
}
26+
27+
public static function propertyCount($value)
28+
{
29+
return count(get_object_vars($value));
30+
}
31+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace JsonSchema\Constraints\TypeCheck;
4+
5+
interface TypeCheckInterface
6+
{
7+
public static function isObject($value);
8+
9+
public static function isArray($value);
10+
11+
public static function propertyGet($value, $property);
12+
13+
public static function propertyExists($value, $property);
14+
15+
public static function propertyCount($value);
16+
}

src/JsonSchema/Constraints/TypeConstraint.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,12 +116,11 @@ protected function validateType($value, $type)
116116
}
117117

118118
if ('object' === $type) {
119-
return is_object($value);
120-
//return ($this::CHECK_MODE_TYPE_CAST == $this->checkMode) ? is_array($value) : is_object($value);
119+
return $this->getTypeCheck()->isObject($value);
121120
}
122121

123122
if ('array' === $type) {
124-
return is_array($value);
123+
return $this->getTypeCheck()->isArray($value);
125124
}
126125

127126
if ('string' === $type) {

0 commit comments

Comments
 (0)