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 KEY_AS_NAME = 131072;
const MAYBE_THUNK = 262144; const MAYBE_THUNK = 262144;
const MAYBE_TYPE = 524288; const MAYBE_TYPE = 524288;
const MAYBE_NAME = 1048576;
/** /**
* @var bool * @var bool
*/ */
private static $enableValidation = false; private static $enableValidation = false;
/**
* @var bool
*/
private static $allowCustomOptions = true;
/** /**
* Disables config validation * Disables config validation
*/ */
@ -45,9 +51,10 @@ class Config
* Enable deep config validation (disabled by default because it creates significant performance overhead). * Enable deep config validation (disabled by default because it creates significant performance overhead).
* Useful only at development to catch type definition errors quickly. * Useful only at development to catch type definition errors quickly.
*/ */
public static function enableValidation() public static function enableValidation($allowCustomOptions = true)
{ {
self::$enableValidation = true; self::$enableValidation = true;
self::$allowCustomOptions = $allowCustomOptions;
} }
/** /**
@ -102,8 +109,11 @@ class Config
// Make sure there are no unexpected keys in map // Make sure there are no unexpected keys in map
$unexpectedKeys = array_keys(array_diff_key($map, $definitions)); $unexpectedKeys = array_keys(array_diff_key($map, $definitions));
if (!empty($unexpectedKeys)) { 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); $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"); 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) { foreach ($value as $arrKey => $arrValue) {
if (is_array($def->definition)) { if (is_array($def->definition)) {
if ($def->flags & self::MAYBE_TYPE) { if ($def->flags & self::MAYBE_TYPE && $arrValue instanceof Type) {
Utils::invariant(is_array($arrValue) || $arrValue instanceof Type, $err, $arrKey, Utils::getVariableType($arrValue)); $arrValue = ['type' => $arrValue];
} else {
Utils::invariant(is_array($arrValue), $err, $arrKey, Utils::getVariableType($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) { if ($def->flags & self::KEY_AS_NAME) {
$arrValue += ['name' => $arrKey]; $arrValue += ['name' => $arrKey];
} }
self::validateMap($typeName, $arrValue, $def->definition, "$pathStr:$arrKey"); self::validateMap($typeName, $arrValue, $def->definition, "$pathStr: $arrKey");
} else { } else {
self::validateEntry($typeName, $arrKey, $arrValue, $def->definition, "$pathStr:$arrKey"); self::validateEntry($typeName, $arrKey, $arrValue, $def->definition, "$pathStr: $arrKey");
} }
} }
} else { } 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 { } 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) { if ($def & self::REQUIRED) {
Utils::invariant($value !== null, 'Value at "%s" can not be null', $pathStr); 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, 'value' => Config::ANY,
'deprecationReason' => Config::STRING, 'deprecationReason' => Config::STRING,
'description' => Config::STRING 'description' => Config::STRING
], Config::KEY_AS_NAME), ], Config::KEY_AS_NAME | Config::MAYBE_NAME),
'description' => Config::STRING 'description' => Config::STRING
]); ]);

View File

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

View File

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