mirror of
https://github.com/retailcrm/graphql-php.git
synced 2024-11-24 22:06:04 +03:00
Make Types throw instead of returning Utils::undefined()
This commit is contained in:
parent
ec0985619f
commit
f140149127
@ -30,11 +30,12 @@ class UrlType extends ScalarType
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return mixed
|
||||
* @throws Error
|
||||
*/
|
||||
public function parseValue($value)
|
||||
{
|
||||
if (!is_string($value) || !filter_var($value, FILTER_VALIDATE_URL)) { // quite naive, but after all this is example
|
||||
throw new \UnexpectedValueException("Cannot represent value as URL: " . Utils::printSafe($value));
|
||||
throw new Error("Cannot represent value as URL: " . Utils::printSafe($value));
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
@ -1197,8 +1197,7 @@ class Executor
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete a Scalar or Enum by serializing to a valid value, returning
|
||||
* null if serialization is not possible.
|
||||
* Complete a Scalar or Enum by serializing to a valid value, throwing if serialization is not possible.
|
||||
*
|
||||
* @param LeafType $returnType
|
||||
* @param $result
|
||||
@ -1207,14 +1206,21 @@ class Executor
|
||||
*/
|
||||
private function completeLeafValue(LeafType $returnType, &$result)
|
||||
{
|
||||
$serializedResult = $returnType->serialize($result);
|
||||
|
||||
if (Utils::isInvalid($serializedResult)) {
|
||||
try {
|
||||
return $returnType->serialize($result);
|
||||
} catch (\Exception $error) {
|
||||
throw new InvariantViolation(
|
||||
'Expected a value of type "'. Utils::printSafe($returnType) . '" but received: ' . Utils::printSafe($result)
|
||||
'Expected a value of type "'. Utils::printSafe($returnType) . '" but received: ' . Utils::printSafe($result),
|
||||
0,
|
||||
$error
|
||||
);
|
||||
} catch (\Throwable $error) {
|
||||
throw new InvariantViolation(
|
||||
'Expected a value of type "'. Utils::printSafe($returnType) . '" but received: ' . Utils::printSafe($result),
|
||||
0,
|
||||
$error
|
||||
);
|
||||
}
|
||||
return $serializedResult;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,7 +1,9 @@
|
||||
<?php
|
||||
namespace GraphQL\Type\Definition;
|
||||
|
||||
use GraphQL\Error\Error;
|
||||
use GraphQL\Language\AST\BooleanValueNode;
|
||||
use GraphQL\Language\AST\Node;
|
||||
use GraphQL\Utils\Utils;
|
||||
|
||||
/**
|
||||
@ -32,22 +34,30 @@ class BooleanType extends ScalarType
|
||||
/**
|
||||
* @param mixed $value
|
||||
* @return bool
|
||||
* @throws Error
|
||||
*/
|
||||
public function parseValue($value)
|
||||
{
|
||||
return is_bool($value) ? $value : Utils::undefined();
|
||||
if (is_bool($value)) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
throw new Error("Cannot represent value as boolean: " . Utils::printSafe($value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $valueNode
|
||||
* @param Node $valueNode
|
||||
* @param array|null $variables
|
||||
* @return bool|null
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function parseLiteral($valueNode, array $variables = null)
|
||||
{
|
||||
if ($valueNode instanceof BooleanValueNode) {
|
||||
return (bool) $valueNode->value;
|
||||
}
|
||||
return Utils::undefined();
|
||||
|
||||
// Intentionally without message, as all information already in wrapped Exception
|
||||
throw new \Exception();
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
<?php
|
||||
namespace GraphQL\Type\Definition;
|
||||
|
||||
use GraphQL\Error\Error;
|
||||
use GraphQL\Language\AST\Node;
|
||||
use GraphQL\Utils\AST;
|
||||
use GraphQL\Utils\Utils;
|
||||
|
||||
@ -25,10 +27,6 @@ class CustomScalarType extends ScalarType
|
||||
*/
|
||||
public function parseValue($value)
|
||||
{
|
||||
if (Utils::isInvalid($value)) {
|
||||
return Utils::undefined();
|
||||
}
|
||||
|
||||
if (isset($this->config['parseValue'])) {
|
||||
return call_user_func($this->config['parseValue'], $value);
|
||||
} else {
|
||||
@ -37,9 +35,10 @@ class CustomScalarType extends ScalarType
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $valueNode
|
||||
* @param Node $valueNode
|
||||
* @param array|null $variables
|
||||
* @return mixed
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function parseLiteral(/* GraphQL\Language\AST\ValueNode */ $valueNode, array $variables = null)
|
||||
{
|
||||
|
@ -1,6 +1,7 @@
|
||||
<?php
|
||||
namespace GraphQL\Type\Definition;
|
||||
|
||||
use GraphQL\Error\Error;
|
||||
use GraphQL\Error\InvariantViolation;
|
||||
use GraphQL\Language\AST\EnumTypeDefinitionNode;
|
||||
use GraphQL\Language\AST\EnumValueNode;
|
||||
@ -103,7 +104,8 @@ class EnumType extends Type implements InputType, OutputType, LeafType, NamedTyp
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
* @return null
|
||||
* @return mixed
|
||||
* @throws Error
|
||||
*/
|
||||
public function serialize($value)
|
||||
{
|
||||
@ -112,36 +114,44 @@ class EnumType extends Type implements InputType, OutputType, LeafType, NamedTyp
|
||||
return $lookup[$value]->name;
|
||||
}
|
||||
|
||||
return Utils::undefined();
|
||||
throw new Error("Cannot serialize value as enum: " . Utils::printSafe($value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
* @return null
|
||||
* @return mixed
|
||||
* @throws Error
|
||||
*/
|
||||
public function parseValue($value)
|
||||
{
|
||||
$lookup = $this->getNameLookup();
|
||||
return isset($lookup[$value]) ? $lookup[$value]->value : Utils::undefined();
|
||||
if (isset($lookup[$value])) {
|
||||
return $lookup[$value]->value;
|
||||
}
|
||||
|
||||
throw new Error("Cannot represent value as enum: " . Utils::printSafe($value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
* @param $valueNode
|
||||
* @param array|null $variables
|
||||
* @return null
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function parseLiteral($value, array $variables = null)
|
||||
public function parseLiteral($valueNode, array $variables = null)
|
||||
{
|
||||
if ($value instanceof EnumValueNode) {
|
||||
if ($valueNode instanceof EnumValueNode) {
|
||||
$lookup = $this->getNameLookup();
|
||||
if (isset($lookup[$value->value])) {
|
||||
$enumValue = $lookup[$value->value];
|
||||
if (isset($lookup[$valueNode->value])) {
|
||||
$enumValue = $lookup[$valueNode->value];
|
||||
if ($enumValue) {
|
||||
return $enumValue->value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
// Intentionally without message, as all information already in wrapped Exception
|
||||
throw new \Exception();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -49,13 +49,16 @@ values as specified by
|
||||
* @param $valueNode
|
||||
* @param array|null $variables
|
||||
* @return float|null
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function parseLiteral($valueNode, array $variables = null)
|
||||
{
|
||||
if ($valueNode instanceof FloatValueNode || $valueNode instanceof IntValueNode) {
|
||||
return (float) $valueNode->value;
|
||||
}
|
||||
return Utils::undefined();
|
||||
|
||||
// Intentionally without message, as all information already in wrapped Exception
|
||||
throw new \Exception();
|
||||
}
|
||||
|
||||
private function coerceFloat($value) {
|
||||
|
@ -3,6 +3,7 @@ namespace GraphQL\Type\Definition;
|
||||
|
||||
use GraphQL\Error\Error;
|
||||
use GraphQL\Language\AST\IntValueNode;
|
||||
use GraphQL\Language\AST\Node;
|
||||
use GraphQL\Language\AST\StringValueNode;
|
||||
use GraphQL\Utils\Utils;
|
||||
|
||||
@ -30,6 +31,7 @@ When expected as an input type, any string (such as `"4"`) or integer
|
||||
/**
|
||||
* @param mixed $value
|
||||
* @return string
|
||||
* @throws Error
|
||||
*/
|
||||
public function serialize($value)
|
||||
{
|
||||
@ -51,22 +53,30 @@ When expected as an input type, any string (such as `"4"`) or integer
|
||||
/**
|
||||
* @param mixed $value
|
||||
* @return string
|
||||
* @throws Error
|
||||
*/
|
||||
public function parseValue($value)
|
||||
{
|
||||
return (is_string($value) || is_int($value)) ? (string) $value : Utils::undefined();
|
||||
if (is_string($value) || is_int($value)) {
|
||||
return (string) $value;
|
||||
}
|
||||
|
||||
throw new Error("Cannot represent value as ID: " . Utils::printSafe($value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $ast
|
||||
* @param Node $valueNode
|
||||
* @param array|null $variables
|
||||
* @return null|string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function parseLiteral($valueNode, array $variables = null)
|
||||
{
|
||||
if ($valueNode instanceof StringValueNode || $valueNode instanceof IntValueNode) {
|
||||
return $valueNode->value;
|
||||
}
|
||||
return Utils::undefined();
|
||||
|
||||
// Intentionally without message, as all information already in wrapped Exception
|
||||
throw new \Exception();
|
||||
}
|
||||
}
|
||||
|
@ -55,6 +55,7 @@ values. Int can represent values between -(2^31) and 2^31 - 1. ';
|
||||
* @param $valueNode
|
||||
* @param array|null $variables
|
||||
* @return int|null
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function parseLiteral($valueNode, array $variables = null)
|
||||
{
|
||||
@ -64,7 +65,9 @@ values. Int can represent values between -(2^31) and 2^31 - 1. ';
|
||||
return $val;
|
||||
}
|
||||
}
|
||||
return Utils::undefined();
|
||||
|
||||
// Intentionally without message, as all information already in wrapped Exception
|
||||
throw new \Exception();
|
||||
}
|
||||
|
||||
private function coerceInt($value) {
|
||||
|
@ -1,6 +1,7 @@
|
||||
<?php
|
||||
namespace GraphQL\Type\Definition;
|
||||
|
||||
use GraphQL\Error\Error;
|
||||
use \GraphQL\Language\AST\Node;
|
||||
|
||||
/*
|
||||
@ -15,27 +16,30 @@ interface LeafType
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return mixed
|
||||
* @throws Error
|
||||
*/
|
||||
public function serialize($value);
|
||||
|
||||
/**
|
||||
* Parses an externally provided value (query variable) to use as an input
|
||||
*
|
||||
* In the case of an invalid value this method must return Utils::undefined()
|
||||
* In the case of an invalid value this method must throw an Exception
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return mixed
|
||||
* @throws Error
|
||||
*/
|
||||
public function parseValue($value);
|
||||
|
||||
/**
|
||||
* Parses an externally provided literal value (hardcoded in GraphQL query) to use as an input
|
||||
*
|
||||
* In the case of an invalid value this method must return Utils::undefined()
|
||||
* In the case of an invalid node or value this method must throw an Exception
|
||||
*
|
||||
* @param Node $valueNode
|
||||
* @param array|null $variables
|
||||
* @return mixed
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function parseLiteral($valueNode, array $variables = null);
|
||||
}
|
||||
|
@ -60,13 +60,16 @@ represent free-form human-readable text.';
|
||||
* @param $valueNode
|
||||
* @param array|null $variables
|
||||
* @return null|string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function parseLiteral($valueNode, array $variables = null)
|
||||
{
|
||||
if ($valueNode instanceof StringValueNode) {
|
||||
return $valueNode->value;
|
||||
}
|
||||
return Utils::undefined();
|
||||
|
||||
// Intentionally without message, as all information already in wrapped Exception
|
||||
throw new \Exception();
|
||||
}
|
||||
|
||||
private function coerceString($value) {
|
||||
|
@ -209,9 +209,18 @@ class AST
|
||||
if ($type instanceof ScalarType || $type instanceof EnumType) {
|
||||
// Since value is an internally represented value, it must be serialized
|
||||
// to an externally represented value before converting into an AST.
|
||||
$serialized = $type->serialize($value);
|
||||
if (null === $serialized || Utils::isInvalid($serialized)) {
|
||||
return null;
|
||||
try {
|
||||
$serialized = $type->serialize($value);
|
||||
} catch (\Exception $error) {
|
||||
if ($error instanceof Error && $type instanceof EnumType) {
|
||||
return null;
|
||||
}
|
||||
throw $error;
|
||||
} catch (\Throwable $error) {
|
||||
if ($error instanceof Error && $type instanceof EnumType) {
|
||||
return null;
|
||||
}
|
||||
throw $error;
|
||||
}
|
||||
|
||||
// Others serialize based on their corresponding PHP scalar types.
|
||||
@ -400,18 +409,12 @@ class AST
|
||||
// Invalid values represent a failure to parse correctly, in which case
|
||||
// no value is returned.
|
||||
try {
|
||||
$result = $type->parseLiteral($valueNode, $variables);
|
||||
return $type->parseLiteral($valueNode, $variables);
|
||||
} catch (\Exception $error) {
|
||||
return $undefined;
|
||||
} catch (\Throwable $error) {
|
||||
return $undefined;
|
||||
}
|
||||
|
||||
if (Utils::isInvalid($result)) {
|
||||
return $undefined;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
throw new Error('Unknown type: ' . Utils::printSafe($type) . '.');
|
||||
@ -420,7 +423,7 @@ class AST
|
||||
/**
|
||||
* Produces a PHP value given a GraphQL Value AST.
|
||||
*
|
||||
* Unlike `valueFromAST()`, no type is provided. The resulting JavaScript value
|
||||
* Unlike `valueFromAST()`, no type is provided. The resulting PHP value
|
||||
* will reflect the provided GraphQL value AST.
|
||||
*
|
||||
* | GraphQL Value | PHP Value |
|
||||
@ -471,7 +474,7 @@ class AST
|
||||
);
|
||||
case $valueNode instanceof VariableNode:
|
||||
$variableName = $valueNode->name->value;
|
||||
return ($variables && isset($variables[$variableName]) && !Utils::isInvalid($variables[$variableName]))
|
||||
return ($variables && isset($variables[$variableName]))
|
||||
? $variables[$variableName]
|
||||
: null;
|
||||
}
|
||||
|
@ -46,14 +46,7 @@ class Value
|
||||
// throw to indicate failure. If it throws, maintain a reference to
|
||||
// the original error.
|
||||
try {
|
||||
$parseResult = $type->parseValue($value);
|
||||
if (Utils::isInvalid($parseResult)) {
|
||||
return self::ofErrors([
|
||||
self::coercionError("Expected type {$type->name}", $blameNode, $path),
|
||||
]);
|
||||
}
|
||||
|
||||
return self::ofValue($parseResult);
|
||||
return self::ofValue($type->parseValue($value));
|
||||
} catch (\Exception $error) {
|
||||
return self::ofErrors([
|
||||
self::coercionError(
|
||||
|
@ -173,20 +173,9 @@ class ValuesOfCorrectType extends AbstractValidationRule
|
||||
}
|
||||
|
||||
// Scalars determine if a literal value is valid via parseLiteral() which
|
||||
// may throw or return an invalid value to indicate failure.
|
||||
// may throw to indicate failure.
|
||||
try {
|
||||
$parseResult = $type->parseLiteral($node);
|
||||
if (Utils::isInvalid($parseResult)) {
|
||||
$context->reportError(
|
||||
new Error(
|
||||
self::badValueMessage(
|
||||
(string) $locationType,
|
||||
Printer::doPrint($node)
|
||||
),
|
||||
$node
|
||||
)
|
||||
);
|
||||
}
|
||||
$type->parseLiteral($node);
|
||||
} catch (\Exception $error) {
|
||||
// Ensure a reference to the original error is maintained.
|
||||
$context->reportError(
|
||||
|
@ -1,6 +1,7 @@
|
||||
<?php
|
||||
namespace GraphQL\Tests\Executor;
|
||||
|
||||
use GraphQL\Error\Error;
|
||||
use GraphQL\Type\Definition\ScalarType;
|
||||
use GraphQL\Utils\Utils;
|
||||
|
||||
@ -53,28 +54,40 @@ class ComplexScalar extends ScalarType
|
||||
|
||||
public $name = 'ComplexScalar';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function serialize($value)
|
||||
{
|
||||
if ($value === 'DeserializedValue') {
|
||||
return 'SerializedValue';
|
||||
}
|
||||
return null;
|
||||
|
||||
throw new Error("Cannot serialize value as ComplexScalar: " . Utils::printSafe($value));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function parseValue($value)
|
||||
{
|
||||
if ($value === 'SerializedValue') {
|
||||
return 'DeserializedValue';
|
||||
}
|
||||
return Utils::undefined();
|
||||
|
||||
throw new Error("Cannot represent value as ComplexScalar: " . Utils::printSafe($value));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function parseLiteral($valueNode, array $variables = null)
|
||||
{
|
||||
if ($valueNode->value === 'SerializedValue') {
|
||||
return 'DeserializedValue';
|
||||
}
|
||||
return Utils::undefined();
|
||||
|
||||
throw new Error("Cannot represent literal as ComplexScalar: " . Utils::printSafe($valueNode->value));
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user