Minor executor refactoring related to handling "resolve" errors

This commit is contained in:
vladar 2015-10-23 15:45:40 +06:00
parent 83f42825f8
commit 965c3ff743

View File

@ -324,7 +324,13 @@ class Executor
*/ */
private static function doesFragmentConditionMatch(ExecutionContext $exeContext,/* FragmentDefinition | InlineFragment*/ $fragment, ObjectType $type) private static function doesFragmentConditionMatch(ExecutionContext $exeContext,/* FragmentDefinition | InlineFragment*/ $fragment, ObjectType $type)
{ {
$conditionalType = Utils\TypeInfo::typeFromAST($exeContext->schema, $fragment->typeCondition); $typeConditionAST = $fragment->typeCondition;
if (!$typeConditionAST) {
return true;
}
$conditionalType = Utils\TypeInfo::typeFromAST($exeContext->schema, $typeConditionAST);
if ($conditionalType === $type) { if ($conditionalType === $type) {
return true; return true;
} }
@ -394,22 +400,9 @@ class Executor
'variableValues' => $exeContext->variableValues, 'variableValues' => $exeContext->variableValues,
]); ]);
// If an error occurs while calling the field `resolve` function, ensure that // Get the resolve function, regardless of if its result is normal
// it is wrapped as a GraphQLError with locations. Log this error and return // or abrupt (error).
// null if allowed, otherwise throw the error so the parent field can handle $result = self::resolveOrError($resolveFn, $source, $args, $info);
// it.
try {
$result = call_user_func($resolveFn, $source, $args, $info);
} catch (\Exception $error) {
$reportedError = Error::createLocatedError($error, $fieldASTs);
if ($returnType instanceof NonNull) {
throw $reportedError;
}
$exeContext->addError($reportedError);
return null;
}
return self::completeValueCatchingError( return self::completeValueCatchingError(
$exeContext, $exeContext,
@ -420,6 +413,16 @@ class Executor
); );
} }
// Isolates the "ReturnOrAbrupt" behavior to not de-opt the `resolveField`
// function. Returns the result of resolveFn or the abrupt-return Error object.
private static function resolveOrError($resolveFn, $source, $args, $info)
{
try {
return call_user_func($resolveFn, $source, $args, $info);
} catch (\Exception $error) {
return $error;
}
}
public static function completeValueCatchingError( public static function completeValueCatchingError(
ExecutionContext $exeContext, ExecutionContext $exeContext,
@ -440,6 +443,8 @@ class Executor
try { try {
return self::completeValue($exeContext, $returnType, $fieldASTs, $info, $result); return self::completeValue($exeContext, $returnType, $fieldASTs, $info, $result);
} catch (Error $err) { } catch (Error $err) {
// If `completeValue` returned abruptly (threw an error), log the error
// and return null.
$exeContext->addError($err); $exeContext->addError($err);
return null; return null;
} }
@ -465,6 +470,10 @@ class Executor
*/ */
private static function completeValue(ExecutionContext $exeContext, Type $returnType,/* Array<Field> */ $fieldASTs, ResolveInfo $info, &$result) private static function completeValue(ExecutionContext $exeContext, Type $returnType,/* Array<Field> */ $fieldASTs, ResolveInfo $info, &$result)
{ {
if ($result instanceof \Exception) {
throw Error::createLocatedError($result, $fieldASTs);
}
// If field type is NonNull, complete for inner type, and throw field error // If field type is NonNull, complete for inner type, and throw field error
// if result is null. // if result is null.
if ($returnType instanceof NonNull) { if ($returnType instanceof NonNull) {
@ -514,29 +523,29 @@ class Executor
// Field type must be Object, Interface or Union and expect sub-selections. // Field type must be Object, Interface or Union and expect sub-selections.
if ($returnType instanceof ObjectType) { if ($returnType instanceof ObjectType) {
$objectType = $returnType; $runtimeType = $returnType;
} else if ($returnType instanceof AbstractType) { } else if ($returnType instanceof AbstractType) {
$objectType = $returnType->getObjectType($result, $info); $runtimeType = $returnType->getObjectType($result, $info);
if ($objectType && !$returnType->isPossibleType($objectType)) { if ($runtimeType && !$returnType->isPossibleType($runtimeType)) {
throw new Error( throw new Error(
"Runtime Object type \"$objectType\" is not a possible type for \"$returnType\"." "Runtime Object type \"$runtimeType\" is not a possible type for \"$returnType\"."
); );
} }
} else { } else {
$objectType = null; $runtimeType = null;
} }
if (!$objectType) { if (!$runtimeType) {
return null; return null;
} }
// If there is an isTypeOf predicate function, call it with the // If there is an isTypeOf predicate function, call it with the
// current result. If isTypeOf returns false, then raise an error rather // current result. If isTypeOf returns false, then raise an error rather
// than continuing execution. // than continuing execution.
if (false === $objectType->isTypeOf($result, $info)) { if (false === $runtimeType->isTypeOf($result, $info)) {
throw new Error( throw new Error(
"Expected value of type $objectType but got: $result.", "Expected value of type $runtimeType but got: $result.",
$fieldASTs $fieldASTs
); );
} }
@ -549,7 +558,7 @@ class Executor
if ($selectionSet) { if ($selectionSet) {
$subFieldASTs = self::collectFields( $subFieldASTs = self::collectFields(
$exeContext, $exeContext,
$objectType, $runtimeType,
$selectionSet, $selectionSet,
$subFieldASTs, $subFieldASTs,
$visitedFragmentNames $visitedFragmentNames
@ -557,7 +566,7 @@ class Executor
} }
} }
return self::executeFields($exeContext, $objectType, $result, $subFieldASTs); return self::executeFields($exeContext, $runtimeType, $result, $subFieldASTs);
} }