Improved error reporting for invalid field definitions

This commit is contained in:
vladar 2016-10-21 18:17:20 +07:00
parent 927997a705
commit 7f1d74f980
4 changed files with 48 additions and 15 deletions

View File

@ -65,11 +65,30 @@ class Config
public static function validate(array $config, array $definition)
{
if (self::$enableValidation) {
$name = isset($config['name']) ? $config['name'] : 'UnnamedType';
$name = isset($config['name']) ? $config['name'] : '(Unnamed Type)';
self::validateMap($name, $config, $definition);
}
}
/**
* @param $typeName
* @param array $config
* @param array $definition
*/
public static function validateField($typeName, array $config, array $definition)
{
if (self::$enableValidation) {
if (!isset($config['name'])) {
$pathStr = isset($config['type'])
? '(Unknown Field of type: ' . Utils::printSafe($config['type']) . ')'
: '(Unknown Field)';
} else {
$pathStr = '';
}
self::validateMap($typeName ?: '(Unnamed Type)', $config, $definition, $pathStr);
}
}
/**
* @param $definition
* @param int $flags
@ -121,7 +140,10 @@ class Config
// 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), 'Error in "'.$typeName.'" type definition: 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) {
@ -226,28 +248,28 @@ class Config
Utils::invariant(
is_callable($value) || $value instanceof InputType,
$err,
'callable or instance of GraphQL\Type\Definition\InputType'
'callable or InputType definition'
);
break;
case $def & self::OUTPUT_TYPE:
Utils::invariant(
is_callable($value) || $value instanceof OutputType,
$err,
'callable or instance of GraphQL\Type\Definition\OutputType'
'callable or OutputType definition'
);
break;
case $def & self::INTERFACE_TYPE:
Utils::invariant(
is_callable($value) || $value instanceof InterfaceType,
$err,
'callable or instance of GraphQL\Type\Definition\InterfaceType'
'callable or InterfaceType definition'
);
break;
case $def & self::OBJECT_TYPE:
Utils::invariant(
is_callable($value) || $value instanceof ObjectType,
$err,
'callable or instance of GraphQL\Type\Definition\ObjectType'
'callable or ObjectType definition'
);
break;
default:

View File

@ -1,5 +1,7 @@
<?php
namespace GraphQL\Type\Definition;
use GraphQL\Error\InvariantViolation;
use GraphQL\Utils;
/**
* Class FieldDefinition
@ -89,30 +91,39 @@ class FieldDefinition
/**
* @param array|Config $fields
* @param string $typeName
* @return array
*/
public static function createMap(array $fields)
public static function createMap(array $fields, $typeName = null)
{
$map = [];
foreach ($fields as $name => $field) {
if (!is_array($field)) {
$field = ['type' => $field];
}
if (!isset($field['name'])) {
if (is_string($name)) {
$field = ['name' => $name, 'type' => $field];
} else {
throw new InvariantViolation(
"Unexpected field definition for type $typeName at key $name: " . Utils::printSafe($field)
);
}
} elseif (!isset($field['name']) && is_string($name)) {
$field['name'] = $name;
}
$map[$name] = self::create($field);
$map[$name] = self::create($field, $typeName);
}
return $map;
}
/**
* @param array|Config $field
* @param string $typeName
* @return FieldDefinition
*/
public static function create($field)
public static function create($field, $typeName = null)
{
Config::validate($field, self::getDefinition());
if ($typeName) {
Config::validateField($typeName, $field, self::getDefinition());
}
return new self($field);
}

View File

@ -60,7 +60,7 @@ class InterfaceType extends Type implements AbstractType, OutputType, CompositeT
$this->fields = [];
$fields = isset($this->config['fields']) ? $this->config['fields'] : [];
$fields = is_callable($fields) ? call_user_func($fields) : $fields;
$this->fields = FieldDefinition::createMap($fields);
$this->fields = FieldDefinition::createMap($fields, $this->name);
}
return $this->fields;
}

View File

@ -112,7 +112,7 @@ class ObjectType extends Type implements OutputType, CompositeType
if (null === $this->fields) {
$fields = isset($this->config['fields']) ? $this->config['fields'] : [];
$fields = is_callable($fields) ? call_user_func($fields) : $fields;
$this->fields = FieldDefinition::createMap($fields);
$this->fields = FieldDefinition::createMap($fields, $this->name);
}
return $this->fields;
}