public static function valueFromAST($valueNode, InputType $type, $variables = null)
{
$undefined = Utils::undefined();
if (!$valueNode) {
// When there is no AST, then there is also no value.
// Importantly, this is different from returning the GraphQL null value.
return $undefined;
}
if ($type instanceof NonNull) {
if ($valueNode instanceof NullValueNode) {
// Invalid: intentionally return no value.
return $undefined;
}
return self::valueFromAST($valueNode, $type->getWrappedType(), $variables);
}
if ($valueNode instanceof NullValueNode) {
// This is explicitly returning the value null.
return null;
}
if ($valueNode instanceof VariableNode) {
$variableName = $valueNode->name->value;
if (!$variables || !array_key_exists($variableName, $variables)) {
// No valid return value.
return $undefined;
}
// 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 ($valueNode instanceof ListValueNode) {
$coercedValues = [];
$itemNodes = $valueNode->values;
foreach ($itemNodes as $itemNode) {
if (self::isMissingVariable($itemNode, $variables)) {
// If an array contains a missing variable, it is either coerced to
// null or if the item type is non-null, it considered invalid.
if ($itemType instanceof NonNull) {
// Invalid: intentionally return no value.
return $undefined;
}
$coercedValues[] = null;
} else {
$itemValue = self::valueFromAST($itemNode, $itemType, $variables);
if ($undefined === $itemValue) {
// Invalid: intentionally return no value.
return $undefined;
}
$coercedValues[] = $itemValue;
}
}
return $coercedValues;
}
$coercedValue = self::valueFromAST($valueNode, $itemType, $variables);
if ($undefined === $coercedValue) {
// Invalid: intentionally return no value.
return $undefined;
}
return [$coercedValue];
}
if ($type instanceof InputObjectType) {
if (!$valueNode instanceof ObjectValueNode) {
// Invalid: intentionally return no value.
return $undefined;
}
$coercedObj = [];
$fields = $type->getFields();
$fieldNodes = Utils::keyMap($valueNode->fields, function ($field) {
return $field->name->value;
});
foreach ($fields as $field) {
/** @var ValueNode $fieldNode */
$fieldName = $field->name;
$fieldNode = isset($fieldNodes[$fieldName]) ? $fieldNodes[$fieldName] : null;
if (!$fieldNode || self::isMissingVariable($fieldNode->value, $variables)) {
if ($field->defaultValueExists()) {
$coercedObj[$fieldName] = $field->defaultValue;
} else {
if ($field->getType() instanceof NonNull) {
// Invalid: intentionally return no value.
return $undefined;
}
}
continue;
}
$fieldValue = self::valueFromAST($fieldNode ? $fieldNode->value : null, $field->getType(), $variables);
if ($undefined === $fieldValue) {
// Invalid: intentionally return no value.
return $undefined;
}
$coercedObj[$fieldName] = $fieldValue;
}
return $coercedObj;
}
if ($type instanceof LeafType) {
$parsed = $type->parseLiteral($valueNode);
if (null === $parsed) {
// null represent a failure to parse correctly,
// in which case no value is returned.
return $undefined;
}
return $parsed;
}
throw new InvariantViolation('Must be input type');
}