/** * Provided a type and a super type, return true if the first type is either * equal or a subset of the second super type (covariant). */ static function isTypeSubTypeOf(Schema $schema, Type $maybeSubType, Type $superType) { // Equivalent type is a valid subtype if ($maybeSubType === $superType) { return true; } // If superType is non-null, maybeSubType must also be nullable. if ($superType instanceof NonNull) { if ($maybeSubType instanceof NonNull) { return self::isTypeSubTypeOf($schema, $maybeSubType->getWrappedType(), $superType->getWrappedType()); } return false; } else { if ($maybeSubType instanceof NonNull) { // If superType is nullable, maybeSubType may be non-null. return self::isTypeSubTypeOf($schema, $maybeSubType->getWrappedType(), $superType); } } // If superType type is a list, maybeSubType type must also be a list. if ($superType instanceof ListOfType) { if ($maybeSubType instanceof ListOfType) { return self::isTypeSubTypeOf($schema, $maybeSubType->getWrappedType(), $superType->getWrappedType()); } return false; } else { if ($maybeSubType instanceof ListOfType) { // If superType is not a list, maybeSubType must also be not a list. return false; } } // If superType type is an abstract type, maybeSubType type may be a currently // possible object type. if (Type::isAbstractType($superType) && $maybeSubType instanceof ObjectType && $schema->isPossibleType($superType, $maybeSubType)) { return true; } // Otherwise, the child type is not a valid subtype of the parent type. return false; }
/** * 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 `serialize` method of GraphQL type * definition. * * If the field is an abstract type, determine the runtime type of the value * and then complete based on that type * * Otherwise, the field type expects a sub-selection set, and will complete the * value by evaluating all sub-selections. * * @param ExecutionContext $exeContext * @param Type $returnType * @param Field[] $fieldASTs * @param ResolveInfo $info * @param array $path * @param $result * @return array|null * @throws Error * @throws \Exception */ private static function completeValue(ExecutionContext $exeContext, Type $returnType, $fieldASTs, ResolveInfo $info, $path, &$result) { if ($result instanceof \Exception) { throw $result; } // If field type is NonNull, complete for inner type, and throw field error // if result is null. if ($returnType instanceof NonNull) { $completed = self::completeValue($exeContext, $returnType->getWrappedType(), $fieldASTs, $info, $path, $result); if ($completed === null) { throw new InvariantViolation('Cannot return null for non-nullable field ' . $info->parentType . '.' . $info->fieldName . '.'); } return $completed; } // If result is null-like, return null. if (null === $result) { return null; } // If field type is List, complete each item in the list with the inner type if ($returnType instanceof ListOfType) { return self::completeListValue($exeContext, $returnType, $fieldASTs, $info, $path, $result); } // If field type is Scalar or Enum, serialize to a valid value, returning // null if serialization is not possible. if ($returnType instanceof LeafType) { return self::completeLeafValue($returnType, $result); } if ($returnType instanceof AbstractType) { return self::completeAbstractValue($exeContext, $returnType, $fieldASTs, $info, $path, $result); } // Field type must be Object, Interface or Union and expect sub-selections. if ($returnType instanceof ObjectType) { return self::completeObjectValue($exeContext, $returnType, $fieldASTs, $info, $path, $result); } throw new \RuntimeException("Cannot complete value of unexpected type \"{$returnType}\"."); }
/** * 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 `serialize` method of GraphQL type * definition. * * Otherwise, the field type expects a sub-selection set, and will complete the * value by evaluating all sub-selections. */ private static function completeValue(ExecutionContext $exeContext, Type $returnType, $fieldASTs, ResolveInfo $info, &$result) { // If field type is NonNull, complete for inner type, and throw field error // if result is null. if ($returnType instanceof NonNull) { $completed = self::completeValue($exeContext, $returnType->getWrappedType(), $fieldASTs, $info, $result); if ($completed === null) { throw new Error('Cannot return null for non-nullable type.', $fieldASTs instanceof \ArrayObject ? $fieldASTs->getArrayCopy() : $fieldASTs); } return $completed; } // If result is null-like, return null. if (null === $result) { return null; } // If field type is List, complete each item in the list with the inner type if ($returnType instanceof ListOfType) { $itemType = $returnType->getWrappedType(); Utils::invariant(is_array($result) || $result instanceof \Traversable, 'User Error: expected iterable, but did not find one.'); $tmp = []; foreach ($result as $item) { $tmp[] = self::completeValueCatchingError($exeContext, $itemType, $fieldASTs, $info, $item); } return $tmp; } // If field type is Scalar or Enum, serialize to a valid value, returning // null if serialization is not possible. if ($returnType instanceof ScalarType || $returnType instanceof EnumType) { Utils::invariant(method_exists($returnType, 'serialize'), 'Missing serialize method on type'); return $returnType->serialize($result); } // Field type must be Object, Interface or Union and expect sub-selections. if ($returnType instanceof ObjectType) { $objectType = $returnType; } else { if ($returnType instanceof AbstractType) { $objectType = $returnType->getObjectType($result, $info); if ($objectType && !$returnType->isPossibleType($objectType)) { throw new Error("Runtime Object type \"{$objectType}\" is not a possible type for \"{$returnType}\"."); } } else { $objectType = null; } } if (!$objectType) { return null; } // If there is an isTypeOf predicate function, call it with the // current result. If isTypeOf returns false, then raise an error rather // than continuing execution. if (false === $objectType->isTypeOf($result, $info)) { throw new Error("Expected value of type {$objectType} but got: {$result}.", $fieldASTs); } // Collect sub-fields to execute to complete this value. $subFieldASTs = new \ArrayObject(); $visitedFragmentNames = new \ArrayObject(); for ($i = 0; $i < count($fieldASTs); $i++) { $selectionSet = $fieldASTs[$i]->selectionSet; if ($selectionSet) { $subFieldASTs = self::collectFields($exeContext, $objectType, $selectionSet, $subFieldASTs, $visitedFragmentNames); } } return self::executeFields($exeContext, $objectType, $result, $subFieldASTs); }
/** * Given a type and any value, return a runtime value coerced to match the type. */ private static function coerceValue(Type $type, $value) { if ($type instanceof NonNull) { // Note: we're not checking that the result of coerceValue is non-null. // We only call this function after calling isValidValue. return self::coerceValue($type->getWrappedType(), $value); } if (null === $value) { return null; } if ($type instanceof ListOfType) { $itemType = $type->getWrappedType(); // TODO: support iterable input if (is_array($value)) { return array_map(function ($item) use($itemType) { return Values::coerceValue($itemType, $item); }, $value); } else { return [self::coerceValue($itemType, $value)]; } } if ($type instanceof InputObjectType) { $fields = $type->getFields(); $obj = []; foreach ($fields as $fieldName => $field) { $fieldValue = self::coerceValue($field->getType(), isset($value[$fieldName]) ? $value[$fieldName] : null); if (null === $fieldValue) { $fieldValue = $field->defaultValue; } if (null !== $fieldValue) { $obj[$fieldName] = $fieldValue; } } return $obj; } Utils::invariant($type instanceof ScalarType || $type instanceof EnumType, 'Must be input type'); return $type->parseValue($value); }
/** * Check if value is valid using GraphQL Type * * @param array $value * @param Type $type * * @return boolean */ private function isValidValue($value, Type $type) { if ($type instanceof NonNull) { if (null === $value) { return false; } return $this->isValidValue($value, $type->getWrappedType()); } if ($value === null) { return true; } if ($type instanceof ListOfType) { $itemType = $type->getWrappedType(); if (is_array($value)) { foreach ($value as $item) { if (!$this->isValidValue($item, $itemType)) { return false; } } return true; } else { return $this->isValidValue($value, $itemType); } } if ($type instanceof InputObjectType) { if (!is_array($value)) { return false; } $fields = $type->getFields(); $fieldMap = []; foreach ($fields as $fieldName => $field) { if (!$this->isValidValue(isset($value[$fieldName]) ? $value[$fieldName] : null, $field->getType())) { return false; } $fieldMap[$field->name] = $field; } $diff = array_diff_key($value, $fieldMap); if (!empty($diff)) { return false; } return true; } Utils::invariant($type instanceof ScalarType || $type instanceof EnumType, 'Must be input type'); return null !== $type->parseValue($value); }
static function isValidLiteralValue($valueAST, Type $type) { // A value can only be not provided if the type is nullable. if (!$valueAST) { return !$type instanceof NonNull; } // Unwrap non-null. if ($type instanceof NonNull) { return self::isValidLiteralValue($valueAST, $type->getWrappedType()); } // This function only tests literals, and assumes variables will provide // values of the correct type. if ($valueAST instanceof Variable) { return true; } if (!$valueAST instanceof Value) { return false; } // Lists accept a non-list value as a list of one. if ($type instanceof ListOfType) { $itemType = $type->getWrappedType(); if ($valueAST instanceof ListValue) { foreach ($valueAST->values as $itemAST) { if (!self::isValidLiteralValue($itemAST, $itemType)) { return false; } } return true; } else { return self::isValidLiteralValue($valueAST, $itemType); } } // Scalar/Enum input checks to ensure the type can serialize the value to // a non-null value. if ($type instanceof ScalarType || $type instanceof EnumType) { return $type->parseLiteral($valueAST) !== null; } // Input objects check each defined field, ensuring it is of the correct // type and provided if non-nullable. if ($type instanceof InputObjectType) { $fields = $type->getFields(); if ($valueAST->kind !== Node::OBJECT) { return false; } $fieldASTs = $valueAST->fields; $fieldASTMap = Utils::keyMap($fieldASTs, function ($field) { return $field->name->value; }); foreach ($fields as $fieldKey => $field) { $fieldName = $field->name ?: $fieldKey; if (!isset($fieldASTMap[$fieldName]) && $field->getType() instanceof NonNull) { // Required fields missing return false; } } foreach ($fieldASTs as $fieldAST) { if (empty($fields[$fieldAST->name->value]) || !self::isValidLiteralValue($fieldAST->value, $fields[$fieldAST->name->value]->getType())) { return false; } } return true; } // Any other kind of type is not an input type, and a literal cannot be used. return false; }
/** * 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 `serialize` method of GraphQL type * definition. * * Otherwise, the field type expects a sub-selection set, and will complete the * value by evaluating all sub-selections. */ private static function completeValue(ExecutionContext $exeContext, Type $returnType, $fieldASTs, ResolveInfo $info, &$result) { // If field type is NonNull, complete for inner type, and throw field error // if result is null. if ($returnType instanceof NonNull) { $completed = self::completeValue($exeContext, $returnType->getWrappedType(), $fieldASTs, $info, $result); if ($completed === null) { throw new Error('Cannot return null for non-nullable type.', $fieldASTs instanceof \ArrayObject ? $fieldASTs->getArrayCopy() : $fieldASTs); } return $completed; } // If result is null-like, return null. if (null === $result) { return null; } // If field type is Scalar or Enum, serialize to a valid value, returning // null if serialization is not possible. if ($returnType instanceof ScalarType || $returnType instanceof EnumType) { return $returnType->serialize($result); } // If field type is List, and return type is Composite - complete by executing these fields with list value as parameter if ($returnType instanceof ListOfType) { $itemType = $returnType->getWrappedType(); Utils::invariant(is_array($result) || $result instanceof \Traversable, 'User Error: expected iterable, but did not find one.'); // For Object[]: // Allow all object fields to process list value in it's `map` callback: if ($itemType instanceof ObjectType) { // Filter out nulls (as `map` doesn't expect it): $list = []; foreach ($result as $index => $item) { if (null !== $item) { $list[] = $item; } } $subFieldASTs = self::collectSubFields($exeContext, $itemType, $fieldASTs); $mapped = self::executeFields($exeContext, $itemType, $list, $subFieldASTs); $i = 0; $completed = []; foreach ($result as $index => $item) { if (null === $item) { // Complete nulls separately $completed[] = self::completeValueCatchingError($exeContext, $itemType, $fieldASTs, $info, $item); } else { // Assuming same order of mapped values $completed[] = $mapped[$i++]; } } return $completed; } else { if ($itemType instanceof AbstractType) { // Values sharded by ObjectType $listPerObjectType = []; // Helper structures to restore ordering after resolve calls $resultTypeMap = []; $typeNameMap = []; $cursors = []; $copied = []; foreach ($result as $index => $item) { $copied[$index] = $item; if (null !== $item) { $objectType = $itemType->getObjectType($item, $info); if ($objectType && !$itemType->isPossibleType($objectType)) { $exeContext->addError(new Error("Runtime Object type \"{$objectType}\" is not a possible type for \"{$itemType}\".")); $copied[$index] = null; } else { $listPerObjectType[$objectType->name][] = $item; $resultTypeMap[$index] = $objectType->name; $typeNameMap[$objectType->name] = $objectType; } } } $mapped = []; foreach ($listPerObjectType as $typeName => $list) { $objectType = $typeNameMap[$typeName]; $subFieldASTs = self::collectSubFields($exeContext, $objectType, $fieldASTs); $mapped[$typeName] = self::executeFields($exeContext, $objectType, $list, $subFieldASTs); $cursors[$typeName] = 0; } // Restore order: $completed = []; foreach ($copied as $index => $item) { if (null === $item) { // Complete nulls separately $completed[] = self::completeValueCatchingError($exeContext, $itemType, $fieldASTs, $info, $item); } else { $typeName = $resultTypeMap[$index]; $completed[] = $mapped[$typeName][$cursors[$typeName]++]; } } return $completed; } else { // For simple lists: $tmp = []; foreach ($result as $item) { $tmp[] = self::completeValueCatchingError($exeContext, $itemType, $fieldASTs, $info, $item); } return $tmp; } } } if ($returnType instanceof ObjectType) { $objectType = $returnType; } else { if ($returnType instanceof AbstractType) { $objectType = $returnType->getObjectType($result, $info); if ($objectType && !$returnType->isPossibleType($objectType)) { throw new Error("Runtime Object type \"{$objectType}\" is not a possible type for \"{$returnType}\"."); } } else { $objectType = null; } } if (!$objectType) { return null; } // If there is an isTypeOf predicate function, call it with the // current result. If isTypeOf returns false, then raise an error rather // than continuing execution. if (false === $objectType->isTypeOf($result, $info)) { throw new Error("Expected value of type {$objectType} but got: {$result}.", $fieldASTs); } // Collect sub-fields to execute to complete this value. $subFieldASTs = self::collectSubFields($exeContext, $objectType, $fieldASTs); $executed = self::executeFields($exeContext, $objectType, [$result], $subFieldASTs); return isset($executed[0]) ? $executed[0] : null; }
/** * Given a type and a value AST node known to match this type, build a * runtime value. */ private static function coerceValueAST(Type $type, $valueAST, $variables) { if ($type instanceof NonNull) { // 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(), $valueAST, $variables); } if (!$valueAST) { return null; } if ($valueAST->kind === Node::VARIABLE) { $variableName = $valueAST->name->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 ListOfType) { $itemType = $type->getWrappedType(); if ($valueAST->kind === Node::ARR) { $tmp = []; foreach ($valueAST->values as $itemAST) { $tmp[] = self::coerceValueAST($itemType, $itemAST, $variables); } return $tmp; } else { return [self::coerceValueAST($itemType, $valueAST, $variables)]; } } if ($type instanceof InputObjectType) { $fields = $type->getFields(); if ($valueAST->kind !== Node::OBJECT) { return null; } $fieldASTs = Utils::keyMap($valueAST->fields, function ($field) { return $field->name->value; }); $obj = []; foreach ($fields as $fieldName => $field) { $fieldAST = $fieldASTs[$fieldName]; $fieldValue = self::coerceValueAST($field->getType(), $fieldAST ? $fieldAST->value : null, $variables); $obj[$fieldName] = $fieldValue === null ? $field->defaultValue : $fieldValue; } return $obj; } if ($type instanceof ScalarType || $type instanceof EnumType) { $coerced = $type->coerceLiteral($valueAST); if (null !== $coerced) { return $coerced; } } return null; }
/** * Given a type and any value, return a runtime value coerced to match the type. */ private static function coerceValue(Type $type, $value) { $undefined = Utils::undefined(); if ($value === $undefined) { return $undefined; } if ($type instanceof NonNull) { if ($value === null) { // Intentionally return no value. return $undefined; } return self::coerceValue($type->getWrappedType(), $value); } if (null === $value) { return null; } if ($type instanceof ListOfType) { $itemType = $type->getWrappedType(); if (is_array($value) || $value instanceof \Traversable) { $coercedValues = []; foreach ($value as $item) { $itemValue = self::coerceValue($itemType, $item); if ($undefined === $itemValue) { // Intentionally return no value. return $undefined; } $coercedValues[] = $itemValue; } return $coercedValues; } else { $coercedValue = self::coerceValue($itemType, $value); if ($coercedValue === $undefined) { // Intentionally return no value. return $undefined; } return [$coercedValue]; } } if ($type instanceof InputObjectType) { $coercedObj = []; $fields = $type->getFields(); foreach ($fields as $fieldName => $field) { if (!array_key_exists($fieldName, $value)) { if ($field->defaultValueExists()) { $coercedObj[$fieldName] = $field->defaultValue; } else { if ($field->getType() instanceof NonNull) { // Intentionally return no value. return $undefined; } } continue; } $fieldValue = self::coerceValue($field->getType(), $value[$fieldName]); if ($fieldValue === $undefined) { // Intentionally return no value. return $undefined; } $coercedObj[$fieldName] = $fieldValue; } return $coercedObj; } if ($type instanceof LeafType) { $parsed = $type->parseValue($value); if (null === $parsed) { // null or invalid values represent a failure to parse correctly, // in which case no value is returned. return $undefined; } return $parsed; } throw new InvariantViolation('Must be input type'); }
/** * Given a type and any value, return a runtime value coerced to match the type. */ private static function coerceValue(Type $type, $value) { if ($type instanceof NonNull) { // Note: we're not checking that the result of coerceValue is non-null. // We only call this function after calling isValidPHPValue. return self::coerceValue($type->getWrappedType(), $value); } if (null === $value) { return null; } if ($type instanceof ListOfType) { $itemType = $type->getWrappedType(); if (is_array($value) || $value instanceof \Traversable) { return Utils::map($value, function ($item) use($itemType) { return Values::coerceValue($itemType, $item); }); } else { return [self::coerceValue($itemType, $value)]; } } if ($type instanceof InputObjectType) { $fields = $type->getFields(); $obj = []; foreach ($fields as $fieldName => $field) { $fieldValue = self::coerceValue($field->getType(), isset($value[$fieldName]) ? $value[$fieldName] : null); if (null === $fieldValue) { $fieldValue = $field->defaultValue; } if (null !== $fieldValue) { $obj[$fieldName] = $fieldValue; } } return $obj; } if ($type instanceof LeafType) { return $type->parseValue($value); } throw new InvariantViolation('Must be input type'); }
/** * 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. */ private static function completeField(ExecutionContext $exeContext, Type $fieldType, $fieldASTs, &$result) { // If field type is NonNull, complete for inner type, and throw field error // if result is null. if ($fieldType instanceof NonNull) { $completed = self::completeField($exeContext, $fieldType->getWrappedType(), $fieldASTs, $result); if ($completed === null) { throw new Error('Cannot return null for non-nullable type.', $fieldASTs instanceof \ArrayObject ? $fieldASTs->getArrayCopy() : $fieldASTs); } return $completed; } // If result is null-like, return null. if (null === $result) { return null; } // If field type is List, complete each item in the list with the inner type if ($fieldType instanceof ListOfType) { $itemType = $fieldType->getWrappedType(); Utils::invariant(is_array($result) || $result instanceof \Traversable, 'User Error: expected iterable, but did not find one.'); $tmp = []; foreach ($result as $item) { $tmp[] = self::completeField($exeContext, $itemType, $fieldASTs, $item); } return $tmp; } // If field type is Scalar or Enum, coerce to a valid value, returning null // if coercion is not possible. if ($fieldType instanceof ScalarType || $fieldType instanceof EnumType) { Utils::invariant(method_exists($fieldType, 'coerce'), 'Missing coerce method on type'); return $fieldType->coerce($result); } // Field type must be Object, Interface or Union and expect sub-selections. $objectType = $fieldType instanceof ObjectType ? $fieldType : ($fieldType instanceof InterfaceType || $fieldType instanceof UnionType ? $fieldType->resolveType($result) : null); if (!$objectType) { return null; } // Collect sub-fields to execute to complete this value. $subFieldASTs = new \ArrayObject(); $visitedFragmentNames = new \ArrayObject(); for ($i = 0; $i < count($fieldASTs); $i++) { $selectionSet = $fieldASTs[$i]->selectionSet; if ($selectionSet) { $subFieldASTs = self::collectFields($exeContext, $objectType, $selectionSet, $subFieldASTs, $visitedFragmentNames); } } return self::executeFields($exeContext, $objectType, $result, $subFieldASTs); }
/** * Utility for validators which determines if a value literal AST is valid given * an input type. * * Note that this only validates literal values, variables are assumed to * provide values of the correct type. * * @return array */ public static function isValidLiteralValue(Type $type, $valueAST) { // A value must be provided if the type is non-null. if ($type instanceof NonNull) { $wrappedType = $type->getWrappedType(); if (!$valueAST) { if ($wrappedType->name) { return ["Expected \"{$wrappedType->name}!\", found null."]; } return ['Expected non-null value, found null.']; } return static::isValidLiteralValue($wrappedType, $valueAST); } if (!$valueAST) { return []; } // This function only tests literals, and assumes variables will provide // values of the correct type. if ($valueAST instanceof Variable) { return []; } // Lists accept a non-list value as a list of one. if ($type instanceof ListOfType) { $itemType = $type->getWrappedType(); if ($valueAST instanceof ListValue) { $errors = []; foreach ($valueAST->values as $index => $itemAST) { $tmp = static::isValidLiteralValue($itemType, $itemAST); if ($tmp) { $errors = array_merge($errors, Utils::map($tmp, function ($error) use($index) { return "In element #{$index}: {$error}"; })); } } return $errors; } else { return static::isValidLiteralValue($itemType, $valueAST); } } // Input objects check each defined field and look for undefined fields. if ($type instanceof InputObjectType) { if ($valueAST->kind !== Node::OBJECT) { return ["Expected \"{$type->name}\", found not an object."]; } $fields = $type->getFields(); $errors = []; // Ensure every provided field is defined. $fieldASTs = $valueAST->fields; foreach ($fieldASTs as $providedFieldAST) { if (empty($fields[$providedFieldAST->name->value])) { $errors[] = "In field \"{$providedFieldAST->name->value}\": Unknown field."; } } // Ensure every defined field is valid. $fieldASTMap = Utils::keyMap($fieldASTs, function ($fieldAST) { return $fieldAST->name->value; }); foreach ($fields as $fieldName => $field) { $result = static::isValidLiteralValue($field->getType(), isset($fieldASTMap[$fieldName]) ? $fieldASTMap[$fieldName]->value : null); if ($result) { $errors = array_merge($errors, Utils::map($result, function ($error) use($fieldName) { return "In field \"{$fieldName}\": {$error}"; })); } } return $errors; } if ($type instanceof LeafType) { // Scalar/Enum input checks to ensure the type can parse the value to // a non-null value. $parseResult = $type->parseLiteral($valueAST); if (null === $parseResult) { $printed = Printer::doPrint($valueAST); return ["Expected type \"{$type->name}\", found {$printed}."]; } return []; } throw new InvariantViolation('Must be input type'); }