Produces a PHP value given a Automattic\WooCommerce\Vendor\GraphQL Value AST.
A Automattic\WooCommerce\Vendor\GraphQL type must be provided, which will be used to interpret different Automattic\WooCommerce\Vendor\GraphQL Value literals.
Returns null when the value could not be validly coerced according to the provided type.
public static function valueFromAST(?ValueNode $valueNode, Type $type, ?array $variables = null, ?Schema $schema = null)
{
$undefined = Utils::undefined();
if ($valueNode === null) {
// When there is no AST, then there is also no value.
// Importantly, this is different from returning the Automattic\WooCommerce\Vendor\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, $schema);
}
if ($valueNode instanceof NullValueNode) {
// This is explicitly returning the value null.
return null;
}
if ($valueNode instanceof VariableNode) {
$variableName = $valueNode->name->value;
if ($variables === null || ! array_key_exists($variableName, $variables)) {
// No valid return value.
return $undefined;
}
// Note: This does no further checking that this variable is correct.
// This assumes 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, $schema);
if ($undefined === $itemValue) {
// Invalid: intentionally return no value.
return $undefined;
}
$coercedValues[] = $itemValue;
}
}
return $coercedValues;
}
$coercedValue = self::valueFromAST($valueNode, $itemType, $variables, $schema);
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 = [];
foreach ($valueNode->fields as $field) {
$fieldNodes[$field->name->value] = $field;
}
foreach ($fields as $field) {
$fieldName = $field->name;
$fieldNode = $fieldNodes[$fieldName] ?? null;
if ($fieldNode === null || self::isMissingVariable($fieldNode->value, $variables)) {
if ($field->defaultValueExists()) {
$coercedObj[$fieldName] = $field->defaultValue;
} elseif ($field->getType() instanceof NonNull) {
// Invalid: intentionally return no value.
return $undefined;
}
continue;
}
$fieldValue = self::valueFromAST(
$fieldNode->value,
$field->getType(),
$variables,
$schema,
);
if ($undefined === $fieldValue) {
// Invalid: intentionally return no value.
return $undefined;
}
$coercedObj[$fieldName] = $fieldValue;
}
return $type->parseValue($coercedObj);
}
if ($type instanceof EnumType) {
try {
return $type->parseLiteral($valueNode, $variables);
} catch (\Throwable $error) {
return $undefined;
}
}
assert($type instanceof ScalarType, 'only remaining option');
$typeName = $type->name;
// Account for type loader returning a different scalar instance than
// the built-in singleton used in field definitions. Resolve the actual
// type from the schema to ensure the correct parseLiteral() is called.
if ($schema !== null && Type::isBuiltInScalarName($typeName)) {
$schemaType = $schema->getType($typeName);
assert($schemaType instanceof ScalarType, "Schema must provide a ScalarType for built-in scalar \"{$typeName}\".");
$type = $schemaType;
}
// Scalars fulfill parsing a literal value via parseLiteral().
// Invalid values represent a failure to parse correctly, in which case
// no value is returned.
try {
return $type->parseLiteral($valueNode, $variables);
} catch (\Throwable $error) {
return $undefined;
}
}