Skip to content

Commit 9e30166

Browse files
committed
Add CHECK_MODE_REQUIRE_DEFAULTS
If CHECK_MODE_REQUIRE_DEFAULTS is set, then only apply defaults if they are marked as required.
1 parent f638716 commit 9e30166

File tree

3 files changed

+48
-0
lines changed

3 files changed

+48
-0
lines changed

src/JsonSchema/Constraints/Constraint.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ abstract class Constraint extends BaseConstraint implements ConstraintInterface
3030
const CHECK_MODE_COERCE_TYPES = 0x00000004;
3131
const CHECK_MODE_APPLY_DEFAULTS = 0x00000008;
3232
const CHECK_MODE_EXCEPTIONS = 0x00000010;
33+
const CHECK_MODE_REQUIRE_DEFAULTS = 0x00000020;
3334

3435
/**
3536
* Bubble down the path

src/JsonSchema/Constraints/UndefinedConstraint.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,23 @@ protected function validateCommonProperties(&$value, $schema = null, JsonPointer
113113
// Apply default values from schema
114114
if ($this->factory->getConfig(self::CHECK_MODE_APPLY_DEFAULTS)) {
115115
if (isset($schema->properties) && LooseTypeCheck::isObject($value)) {
116+
$v4Required = isset($schema->required) ? $schema->required : array();
116117
// $value is an object or assoc array, and properties are defined - treat as an object
117118
foreach ($schema->properties as $currentProperty => $propertyDefinition) {
118119
if (!LooseTypeCheck::propertyExists($value, $currentProperty) && isset($propertyDefinition->default)) {
120+
// Don't apply non-required defaults if running in required-only mode
121+
if (
122+
$this->factory->getConfig(self::CHECK_MODE_REQUIRE_DEFAULTS) &&
123+
!in_array($currentProperty, $v4Required, true) && // draft-04 required
124+
!(// draft-03 required
125+
isset($propertyDefinition->required) &&
126+
!is_array($propertyDefinition->required) &&
127+
$propertyDefinition->required
128+
)
129+
) {
130+
continue;
131+
}
132+
// assign default value
119133
if (is_object($propertyDefinition->default)) {
120134
LooseTypeCheck::propertySet($value, $currentProperty, clone $propertyDefinition->default);
121135
} else {

tests/Constraints/DefaultPropertiesTest.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,4 +164,37 @@ public function testLeaveBasicTypesAlone()
164164
$schema = json_decode('{"items":[{"type":"string","default":"valueOne"}]}');
165165
$this->assertEquals('"ThisIsAString"', json_encode($input));
166166
}
167+
168+
public function testRequiredOnlyDraft04()
169+
{
170+
$input = json_decode('{}');
171+
$schema = json_decode('{
172+
"properties": {
173+
"propertyOne": {"default": "valueOne"},
174+
"propertyTwo": {"default": "valueTwo"}
175+
},
176+
"required": ["propertyTwo"]
177+
}');
178+
179+
$validator = new Validator();
180+
$validator->validate($input, $schema, Constraint::CHECK_MODE_APPLY_DEFAULTS | Constraint::CHECK_MODE_REQUIRE_DEFAULTS);
181+
182+
$this->assertEquals('{"propertyTwo":"valueTwo"}', json_encode($input));
183+
}
184+
185+
public function testRequiredOnlyDraft03()
186+
{
187+
$input = json_decode('{}');
188+
$schema = json_decode('{
189+
"properties": {
190+
"propertyOne": {"default": "valueOne"},
191+
"propertyTwo": {"default": "valueTwo", "required": true}
192+
}
193+
}');
194+
195+
$validator = new Validator();
196+
$validator->validate($input, $schema, Constraint::CHECK_MODE_APPLY_DEFAULTS | Constraint::CHECK_MODE_REQUIRE_DEFAULTS);
197+
198+
$this->assertEquals('{"propertyTwo":"valueTwo"}', json_encode($input));
199+
}
167200
}

0 commit comments

Comments
 (0)