Various tools for better error reporting / formatting

This commit is contained in:
vladar 2016-10-21 17:42:27 +07:00
parent 2675b65095
commit 927997a705
4 changed files with 125 additions and 3 deletions

View File

@ -2,7 +2,15 @@
namespace GraphQL\Error;
use GraphQL\Language\SourceLocation;
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\WrappingType;
use GraphQL\Utils;
/**
* Class FormattedError
* @todo move this class to Utils/ErrorUtils
* @package GraphQL\Error
*/
class FormattedError
{
/**
@ -23,4 +31,101 @@ class FormattedError
return $formatted;
}
/**
* @param \ErrorException $e
* @return array
*/
public static function createFromPHPError(\ErrorException $e)
{
return [
'message' => $e->getMessage(),
'severity' => $e->getSeverity(),
'trace' => self::toSafeTrace($e->getTrace())
];
}
/**
* @param \Exception $e
* @return array
*/
public static function createFromException(\Exception $e)
{
return [
'message' => $e->getMessage(),
'trace' => self::toSafeTrace($e->getTrace())
];
}
/**
* Converts error trace to serializable array
*
* @param array $trace
* @return array
*/
private static function toSafeTrace(array $trace)
{
// Remove invariant entries as they don't provide much value:
if (
isset($trace[0]['function']) && isset($trace[0]['class']) &&
('GraphQL\Utils::invariant' === $trace[0]['class'].'::'.$trace[0]['function'])) {
array_shift($trace);
}
return array_map(function($err) {
$safeErr = array_intersect_key($err, ['file' => true, 'line' => true]);
if (isset($err['function'])) {
$func = $err['function'];
$args = !empty($err['args']) ? array_map([__CLASS__, 'printVar'], $err['args']) : [];
$funcStr = $func . '(' . implode(", ", $args) . ')';
if (isset($err['class'])) {
$safeErr['call'] = $err['class'] . '::' . $funcStr;
} else {
$safeErr['function'] = $funcStr;
}
}
return $safeErr;
}, $trace);
}
/**
* @param $var
* @return string
*/
public static function printVar($var)
{
if ($var instanceof Type) {
// FIXME: Replace with schema printer call
if ($var instanceof WrappingType) {
$var = $var->getWrappedType(true);
}
return 'GraphQLType: ' . $var->name;
}
if (is_object($var)) {
return 'instance of ' . get_class($var) . ($var instanceof \Countable ? '(' . count($var) . ')' : '');
}
if (is_array($var)) {
return 'array(' . count($var) . ')';
}
if ('' === $var) {
return '(empty string)';
}
if (is_string($var)) {
return "'" . addcslashes($var, "'") . "'";
}
if (is_bool($var)) {
return $var ? 'true' : 'false';
}
if (is_scalar($var)) {
return $var;
}
if (null === $var) {
return 'null';
}
return gettype($var);
}
}

View File

@ -0,0 +1,15 @@
<?php
namespace GraphQL\Error;
/**
* Class InvariantVoilation
*
* Note:
* This exception should not inherit base Error exception as it is raised when there is an error somewhere in
* user-land code
*
* @package GraphQL\Error
*/
class InvariantViolation extends \LogicException
{
}

View File

@ -1,6 +1,7 @@
<?php
namespace GraphQL\Type\Definition;
use GraphQL\Error\InvariantViolation;
use GraphQL\Utils;
/**
@ -184,7 +185,7 @@ class Config
}
}
} else {
throw new \Exception('Error in "'.$typeName.'" type definition: ' . "unexpected definition: " . print_r($def, true));
throw new InvariantViolation('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");
@ -250,7 +251,7 @@ class Config
);
break;
default:
throw new \Exception("Unexpected validation rule: " . $def);
throw new InvariantViolation("Unexpected validation rule: " . $def);
}
}
}

View File

@ -1,6 +1,7 @@
<?php
namespace GraphQL;
use GraphQL\Error\InvariantViolation;
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\WrappingType;
use GraphQL\Utils\SchemaUtils;
@ -201,7 +202,7 @@ class Utils
array_shift($args);
$message = call_user_func_array('sprintf', $args);
}
throw new \Exception($message);
throw new InvariantViolation($message);
}
}