Updated config validation rules

This commit is contained in:
vladar 2016-10-21 15:52:58 +07:00
parent 6d7a4a4f34
commit 2b305ad6e2
4 changed files with 27 additions and 14 deletions

View File

@ -27,12 +27,18 @@ class Config
const KEY_AS_NAME = 131072;
const MAYBE_THUNK = 262144;
const MAYBE_TYPE = 524288;
const MAYBE_NAME = 1048576;
/**
* @var bool
*/
private static $enableValidation = false;
/**
* @var bool
*/
private static $allowCustomOptions = true;
/**
* Disables config validation
*/
@ -45,9 +51,10 @@ class Config
* Enable deep config validation (disabled by default because it creates significant performance overhead).
* Useful only at development to catch type definition errors quickly.
*/
public static function enableValidation()
public static function enableValidation($allowCustomOptions = true)
{
self::$enableValidation = true;
self::$allowCustomOptions = $allowCustomOptions;
}
/**
@ -102,8 +109,11 @@ class Config
// Make sure there are no unexpected keys in map
$unexpectedKeys = array_keys(array_diff_key($map, $definitions));
if (!empty($unexpectedKeys)) {
trigger_error(sprintf('"%s" type definition: Unexpected keys "%s" ' . $suffix, $typeName, implode(', ', $unexpectedKeys)));
if (!self::$allowCustomOptions) {
trigger_error(sprintf('"%s" type definition: Non-standard keys "%s" ' . $suffix, $typeName, implode(', ', $unexpectedKeys)));
}
$map = array_intersect_key($map, $definitions);
}
@ -152,29 +162,32 @@ class Config
Utils::invariant(!empty($value), 'Error in "'.$typeName.'" type definition: ' . "Value at '$pathStr' cannot be empty array");
}
$err = 'Error in "'.$typeName.'" type definition:' . "Each entry at '$pathStr' must be an array, but '%s' is '%s'";
$err = 'Error in "'.$typeName.'" type definition: ' . "Each entry at '$pathStr' must be an array, but '%s' is '%s'";
foreach ($value as $arrKey => $arrValue) {
if (is_array($def->definition)) {
if ($def->flags & self::MAYBE_TYPE) {
Utils::invariant(is_array($arrValue) || $arrValue instanceof Type, $err, $arrKey, Utils::getVariableType($arrValue));
} else {
Utils::invariant(is_array($arrValue), $err, $arrKey, Utils::getVariableType($arrValue));
if ($def->flags & self::MAYBE_TYPE && $arrValue instanceof Type) {
$arrValue = ['type' => $arrValue];
}
if ($def->flags & self::MAYBE_NAME && is_string($arrValue)) {
$arrValue = ['name' => $arrValue];
}
Utils::invariant(is_array($arrValue), $err, $arrKey, Utils::getVariableType($arrValue));
if ($def->flags & self::KEY_AS_NAME) {
$arrValue += ['name' => $arrKey];
}
self::validateMap($typeName, $arrValue, $def->definition, "$pathStr:$arrKey");
self::validateMap($typeName, $arrValue, $def->definition, "$pathStr: $arrKey");
} else {
self::validateEntry($typeName, $arrKey, $arrValue, $def->definition, "$pathStr:$arrKey");
self::validateEntry($typeName, $arrKey, $arrValue, $def->definition, "$pathStr: $arrKey");
}
}
} else {
throw new \Exception('Error in "'.$typeName.'" type definition:' . "unexpected definition: " . print_r($def, true));
throw new \Exception('Error in "'.$typeName.'" type definition: ' . "unexpected definition: " . print_r($def, true));
}
} else {
Utils::invariant(is_int($def), 'Error in "'.$typeName.'" type definition:' . "Definition for '$pathStr' is expected to be single integer value");
Utils::invariant(is_int($def), 'Error in "'.$typeName.'" type definition: ' . "Definition for '$pathStr' is expected to be single integer value");
if ($def & self::REQUIRED) {
Utils::invariant($value !== null, 'Value at "%s" can not be null', $pathStr);

View File

@ -34,7 +34,7 @@ class EnumType extends Type implements InputType, OutputType, LeafType
'value' => Config::ANY,
'deprecationReason' => Config::STRING,
'description' => Config::STRING
], Config::KEY_AS_NAME),
], Config::KEY_AS_NAME | Config::MAYBE_NAME),
'description' => Config::STRING
]);

View File

@ -78,7 +78,7 @@ class FieldDefinition
'type' => Config::INPUT_TYPE | Config::REQUIRED,
'description' => Config::STRING,
'defaultValue' => Config::ANY
], Config::KEY_AS_NAME),
], Config::KEY_AS_NAME | Config::MAYBE_TYPE),
'resolve' => Config::CALLBACK,
'map' => Config::CALLBACK,
'description' => Config::STRING,

View File

@ -39,7 +39,7 @@ class InterfaceType extends Type implements AbstractType, OutputType, CompositeT
'name' => Config::STRING,
'fields' => Config::arrayOf(
FieldDefinition::getDefinition(),
Config::KEY_AS_NAME | Config::MAYBE_THUNK
Config::KEY_AS_NAME | Config::MAYBE_THUNK | Config::MAYBE_TYPE
),
'resolveType' => Config::CALLBACK, // function($value, $context, ResolveInfo $info) => ObjectType
'description' => Config::STRING