mirror of
https://github.com/retailcrm/graphql-php.git
synced 2024-11-21 20:36:05 +03:00
Better error messages for config validation
This commit is contained in:
parent
ee2ce29899
commit
5241c8a5d3
@ -41,7 +41,8 @@ class Config
|
||||
public static function validate(array $config, array $definition)
|
||||
{
|
||||
if (self::$enableValidation) {
|
||||
self::_validateMap($config, $definition);
|
||||
$name = isset($config['name']) ? $config['name'] : 'UnnamedType';
|
||||
self::_validateMap($name, $config, $definition);
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,29 +74,29 @@ class Config
|
||||
return $tmp;
|
||||
}
|
||||
|
||||
private static function _validateMap(array $map, array $definitions, $pathStr = null)
|
||||
private static function _validateMap($typeName, array $map, array $definitions, $pathStr = null)
|
||||
{
|
||||
$suffix = $pathStr ? " at $pathStr" : '';
|
||||
|
||||
// Make sure there are no unexpected keys in map
|
||||
$unexpectedKeys = array_keys(array_diff_key($map, $definitions));
|
||||
Utils::invariant(empty($unexpectedKeys), 'Unexpected keys "%s" ' . $suffix, implode(', ', $unexpectedKeys));
|
||||
Utils::invariant(empty($unexpectedKeys), 'Error in "'.$typeName.'" type definition: Unexpected keys "%s" ' . $suffix, implode(', ', $unexpectedKeys));
|
||||
|
||||
// Make sure that all required keys are present in map
|
||||
$requiredKeys = array_filter($definitions, function($def) {return (self::_getFlags($def) & self::REQUIRED) > 0;});
|
||||
$missingKeys = array_keys(array_diff_key($requiredKeys, $map));
|
||||
Utils::invariant(empty($missingKeys), 'Required keys missing: "%s"' . $suffix, implode(', ', $missingKeys));
|
||||
Utils::invariant(empty($missingKeys), 'Error in "'.$typeName.'" type definition: Required keys missing: "%s"' . $suffix, implode(', ', $missingKeys));
|
||||
|
||||
// Make sure that every map value is valid given the definition
|
||||
foreach ($map as $key => $value) {
|
||||
self::_validateEntry($key, $value, $definitions[$key], $pathStr ? "$pathStr:$key" : $key);
|
||||
self::_validateEntry($typeName, $key, $value, $definitions[$key], $pathStr ? "$pathStr:$key" : $key);
|
||||
}
|
||||
}
|
||||
|
||||
private static function _validateEntry($key, $value, $def, $pathStr)
|
||||
private static function _validateEntry($typeName, $key, $value, $def, $pathStr)
|
||||
{
|
||||
$type = Utils::getVariableType($value);
|
||||
$err = 'Expecting %s at "' . $pathStr . '", but got "' . $type . '"';
|
||||
$err = 'Error in "'.$typeName.'" type definition: expecting %s at "' . $pathStr . '", but got "' . $type . '"';
|
||||
|
||||
if ($def instanceof \stdClass) {
|
||||
if ($def->flags & self::REQUIRED === 0 && $value === null) {
|
||||
@ -107,14 +108,14 @@ class Config
|
||||
if ($def->flags & self::KEY_AS_NAME) {
|
||||
$value += ['name' => $key];
|
||||
}
|
||||
self::_validateMap($value, $def->definition, $pathStr);
|
||||
self::_validateMap($typeName, $value, $def->definition, $pathStr);
|
||||
} else if (!empty($def->isArray)) {
|
||||
|
||||
if ($def->flags & self::REQUIRED) {
|
||||
Utils::invariant(!empty($value), "Value at '$pathStr' cannot be empty array");
|
||||
Utils::invariant(!empty($value), 'Error in "'.$typeName.'" type definition: ' . "Value at '$pathStr' cannot be empty array");
|
||||
}
|
||||
|
||||
$err = "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)) {
|
||||
@ -123,21 +124,25 @@ class Config
|
||||
if ($def->flags & self::KEY_AS_NAME) {
|
||||
$arrValue += ['name' => $arrKey];
|
||||
}
|
||||
self::_validateMap($arrValue, $def->definition, "$pathStr:$arrKey");
|
||||
self::_validateMap($typeName, $arrValue, $def->definition, "$pathStr:$arrKey");
|
||||
} else {
|
||||
self::_validateEntry($arrKey, $arrValue, $def->definition, "$pathStr:$arrKey");
|
||||
self::_validateEntry($typeName, $arrKey, $arrValue, $def->definition, "$pathStr:$arrKey");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new \Exception("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), "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);
|
||||
}
|
||||
|
||||
if (null === $value) {
|
||||
return ; // Allow nulls for non-required fields
|
||||
}
|
||||
|
||||
switch (true) {
|
||||
case $def & self::ANY:
|
||||
break;
|
||||
|
@ -68,6 +68,8 @@ class ObjectType extends Type implements OutputType, CompositeType
|
||||
|
||||
public function __construct(array $config)
|
||||
{
|
||||
Utils::invariant(!empty($config['name']), 'Every type is expected to have name');
|
||||
|
||||
$this->name = $config['name'];
|
||||
$this->description = isset($config['description']) ? $config['description'] : null;
|
||||
$this->_config = $config;
|
||||
|
@ -335,7 +335,7 @@ class DefinitionTest extends \PHPUnit_Framework_TestCase
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (\Exception $e) {
|
||||
$this->assertSame(
|
||||
'Expecting callable or instance of GraphQL\Type\Definition\ObjectType at "types:0", but got "' . get_class($type) . '"',
|
||||
'Error in "BadUnion" type definition: expecting callable or instance of GraphQL\Type\Definition\ObjectType at "types:0", but got "' . get_class($type) . '"',
|
||||
$e->getMessage()
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user