示例#1
0
 /**
  * Given a type and a value AST node known to match this type, build a
  * runtime value.
  *
  * @param TypeInterface $type
  * @param $ast
  * @param null $variables
  *
  * @return array|mixed|null|string
  */
 protected static function coerceValueAST(TypeInterface $type, $ast, $variables = NULL)
 {
     if ($type instanceof NonNullModifier) {
         // Note: we're not checking that the result of coerceValueAST is non-null.
         // We're assuming that this query has been validated and the value used
         // here is of the correct type.
         return self::coerceValueAST($type->getWrappedType(), $ast, $variables);
     }
     if (!$ast) {
         return NULL;
     }
     if ($ast::KIND === Node::KIND_VARIABLE) {
         $variableName = $ast->get('name')->get('value');
         if (!isset($variables, $variables[$variableName])) {
             return NULL;
         }
         // Note: we're not doing any checking that this variable is correct. We're
         // assuming that this query has been validated and the variable usage here
         // is of the correct type.
         return $variables[$variableName];
     }
     if ($type instanceof ListModifier) {
         $itemType = $type->getWrappedType();
         if ($ast::KIND === Node::KIND_ARRAY_VALUE) {
             $tmp = [];
             foreach ($ast->get('values') as $itemAST) {
                 $tmp[] = self::coerceValueAST($itemType, $itemAST, $variables);
             }
             return $tmp;
         } else {
             return [self::coerceValueAST($itemType, $ast, $variables)];
         }
     }
     if ($type instanceof InputObjectType) {
         $fields = $type->getFields();
         if ($ast::KIND !== Node::KIND_OBJECT_VALUE) {
             return NULL;
         }
         $asts = array_reduce($ast->get('fields'), function ($carry, $field) {
             $carry[$field->get('name')->get('value')] = $field;
             return $carry;
         }, []);
         $object = [];
         foreach ($fields as $name => $item) {
             $field = $asts[$name];
             $fieldValue = self::coerceValueAST($item->getType(), $field ? $field->get('value') : NULL, $variables);
             $object[$name] = $fieldValue === NULL ? $item->getDefaultValue() : $fieldValue;
         }
         return $object;
     }
     if ($type instanceof ScalarType || $type instanceof EnumType) {
         $coerced = $type->coerceLiteral($ast);
         if (isset($coerced)) {
             return $coerced;
         }
     }
     return NULL;
 }
示例#2
0
 /**
  * Implements the instructions for completeValue as defined in the
  * "Field entries" section of the spec.
  *
  * If the field type is Non-Null, then this recursively completes the value
  * for the inner type. It throws a field error if that completion returns null,
  * as per the "Nullability" section of the spec.
  *
  * If the field type is a List, then this recursively completes the value
  * for the inner type on each item in the list.
  *
  * If the field type is a Scalar or Enum, ensures the completed value is a legal
  * value of the type by calling the `coerce` method of GraphQL type definition.
  *
  * Otherwise, the field type expects a sub-selection set, and will complete the
  * value by evaluating all sub-selections.
  *
  * @param ExecutionContext $context
  * @param TypeInterface $type
  * @param $asts
  * @param $result
  *
  * @return array|mixed|null|string
  *
  * @throws \Exception
  */
 protected static function completeField(ExecutionContext $context, TypeInterface $type, $asts, &$result)
 {
     // If field type is NonNullModifier, complete for inner type, and throw field error
     // if result is null.
     if ($type instanceof NonNullModifier) {
         $completed = self::completeField($context, $type->getWrappedType(), $asts, $result);
         if ($completed === NULL) {
             throw new \Exception('Cannot return null for non-nullable type.');
         }
         return $completed;
     }
     // If result is null-like, return null.
     if (!isset($result)) {
         return NULL;
     }
     // If field type is List, complete each item in the list with the inner type
     if ($type instanceof ListModifier) {
         $itemType = $type->getWrappedType();
         if (!(is_array($result) || $result instanceof \ArrayObject)) {
             throw new \Exception('User Error: expected iterable, but did not find one.');
         }
         $tmp = [];
         foreach ($result as $item) {
             $tmp[] = self::completeField($context, $itemType, $asts, $item);
         }
         return $tmp;
     }
     // If field type is Scalar or Enum, coerce to a valid value, returning
     // null if coercion is not possible.
     if ($type instanceof ScalarType || $type instanceof EnumType) {
         if (!method_exists($type, 'coerce')) {
             throw new \Exception('Missing coerce method on type.');
         }
         return $type->coerce($result);
     }
     // Field type must be Object, Interface or Union and expect
     // sub-selections.
     $objectType = $type instanceof ObjectType ? $type : ($type instanceof InterfaceType || $type instanceof UnionType ? $type->resolveType($result) : NULL);
     if (!$objectType) {
         return NULL;
     }
     // Collect sub-fields to execute to complete this value.
     $subFieldASTs = new \ArrayObject();
     $visitedFragmentNames = new \ArrayObject();
     $count = count($asts);
     for ($i = 0; $i < $count; $i++) {
         $selectionSet = $asts[$i]->get('selectionSet');
         if ($selectionSet) {
             $subFieldASTs = self::collectFields($context, $objectType, $selectionSet, $subFieldASTs, $visitedFragmentNames);
         }
     }
     return self::executeFields($context, $objectType, $result, $subFieldASTs);
 }