mirror of
https://github.com/retailcrm/graphql-php.git
synced 2024-11-29 00:25:17 +03:00
Allow null values for enums
This commit is contained in:
parent
f569c6de2d
commit
b47c87f793
@ -247,7 +247,7 @@ class Values
|
||||
// Scalar/Enum input checks to ensure the type can parse the value to
|
||||
// a non-null value.
|
||||
$parseResult = $type->parseValue($value);
|
||||
if (null === $parseResult) {
|
||||
if (null === $parseResult && !$type->isValidValue($value)) {
|
||||
$v = Utils::printSafe($value);
|
||||
return [
|
||||
"Expected type \"{$type->name}\", found $v."
|
||||
|
@ -91,6 +91,24 @@ class EnumType extends Type implements InputType, OutputType, LeafType
|
||||
return isset($lookup[$value]) ? $lookup[$value]->name : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
* @return bool
|
||||
*/
|
||||
public function isValidValue($value)
|
||||
{
|
||||
return is_string($value) && $this->getNameLookup()->offsetExists($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $valueNode
|
||||
* @return bool
|
||||
*/
|
||||
public function isValidLiteral($valueNode)
|
||||
{
|
||||
return $valueNode instanceof EnumValueNode && $this->getNameLookup()->offsetExists($valueNode->value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
* @return null
|
||||
|
@ -31,4 +31,16 @@ interface LeafType
|
||||
* @return mixed
|
||||
*/
|
||||
public function parseLiteral($valueNode);
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
* @return bool
|
||||
*/
|
||||
public function isValidValue($value);
|
||||
|
||||
/**
|
||||
* @param \GraphQL\Language\AST\Node $valueNode
|
||||
* @return mixed
|
||||
*/
|
||||
public function isValidLiteral($valueNode);
|
||||
}
|
||||
|
@ -34,4 +34,28 @@ abstract class ScalarType extends Type implements OutputType, InputType, LeafTyp
|
||||
|
||||
Utils::assertValidName($this->name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if an internal value is valid for this type.
|
||||
* Equivalent to checking for if the parsedValue is nullish.
|
||||
*
|
||||
* @param $value
|
||||
* @return bool
|
||||
*/
|
||||
public function isValidValue($value)
|
||||
{
|
||||
return null !== $this->parseValue($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if an internal value is valid for this type.
|
||||
* Equivalent to checking for if the parsedLiteral is nullish.
|
||||
*
|
||||
* @param $valueNode
|
||||
* @return bool
|
||||
*/
|
||||
public function isValidLiteral($valueNode)
|
||||
{
|
||||
return null !== $this->parseLiteral($valueNode);
|
||||
}
|
||||
}
|
||||
|
@ -307,9 +307,9 @@ class AST
|
||||
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.
|
||||
if (null === $parsed && !$type->isValidLiteral($valueNode)) {
|
||||
// Invalid values represent a failure to parse correctly, in which case
|
||||
// no value is returned.
|
||||
return $undefined;
|
||||
}
|
||||
|
||||
|
@ -43,6 +43,16 @@ class MixedStore implements \ArrayAccess
|
||||
*/
|
||||
private $lastArrayValue;
|
||||
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
private $nullValue;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $nullValueIsSet = false;
|
||||
|
||||
/**
|
||||
* MixedStore constructor.
|
||||
*/
|
||||
@ -83,6 +93,9 @@ class MixedStore implements \ArrayAccess
|
||||
}
|
||||
}
|
||||
}
|
||||
if (null === $offset) {
|
||||
return $this->nullValueIsSet;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -114,6 +127,9 @@ class MixedStore implements \ArrayAccess
|
||||
}
|
||||
}
|
||||
}
|
||||
if (null === $offset) {
|
||||
return $this->nullValue;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -138,6 +154,9 @@ class MixedStore implements \ArrayAccess
|
||||
} else if (is_array($offset)) {
|
||||
$this->arrayKeys[] = $offset;
|
||||
$this->arrayValues[] = $value;
|
||||
} else if (null === $offset) {
|
||||
$this->nullValue = $value;
|
||||
$this->nullValueIsSet = true;
|
||||
} else {
|
||||
throw new \InvalidArgumentException("Unexpected offset type: " . Utils::printSafe($offset));
|
||||
}
|
||||
@ -165,6 +184,9 @@ class MixedStore implements \ArrayAccess
|
||||
array_splice($this->arrayKeys, $index, 1);
|
||||
array_splice($this->arrayValues, $index, 1);
|
||||
}
|
||||
} else if (null === $offset) {
|
||||
$this->nullValue = null;
|
||||
$this->nullValueIsSet = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,22 +1,16 @@
|
||||
<?php
|
||||
namespace GraphQL\Validator;
|
||||
|
||||
use GraphQL\Error\Error;
|
||||
use GraphQL\Error\InvariantViolation;
|
||||
use GraphQL\Language\AST\ListValueNode;
|
||||
use GraphQL\Language\AST\DocumentNode;
|
||||
use GraphQL\Language\AST\FragmentSpreadNode;
|
||||
use GraphQL\Language\AST\Node;
|
||||
use GraphQL\Language\AST\NodeKind;
|
||||
use GraphQL\Language\AST\NullValueNode;
|
||||
use GraphQL\Language\AST\ValueNode;
|
||||
use GraphQL\Language\AST\VariableNode;
|
||||
use GraphQL\Language\Printer;
|
||||
use GraphQL\Language\Visitor;
|
||||
use GraphQL\Language\VisitorOperation;
|
||||
use GraphQL\Schema;
|
||||
use GraphQL\Type\Definition\InputObjectType;
|
||||
use GraphQL\Type\Definition\InputType;
|
||||
use GraphQL\Type\Definition\LeafType;
|
||||
use GraphQL\Type\Definition\ListOfType;
|
||||
use GraphQL\Type\Definition\NonNull;
|
||||
@ -231,11 +225,8 @@ class DocumentValidator
|
||||
}
|
||||
|
||||
if ($type instanceof LeafType) {
|
||||
// Scalar/Enum input checks to ensure the type can parse the value to
|
||||
// a non-null value.
|
||||
$parseResult = $type->parseLiteral($valueNode);
|
||||
|
||||
if (null === $parseResult) {
|
||||
// Scalars must parse to a non-null value
|
||||
if (!$type->isValidLiteral($valueNode)) {
|
||||
$printed = Printer::doPrint($valueNode);
|
||||
return [ "Expected type \"{$type->name}\", found $printed." ];
|
||||
}
|
||||
|
@ -72,6 +72,7 @@ class ValueFromAstTest extends \PHPUnit_Framework_TestCase
|
||||
'RED' => ['value' => 1],
|
||||
'GREEN' => ['value' => 2],
|
||||
'BLUE' => ['value' => 3],
|
||||
'NULL' => ['value' => null],
|
||||
]
|
||||
]);
|
||||
|
||||
@ -80,6 +81,7 @@ class ValueFromAstTest extends \PHPUnit_Framework_TestCase
|
||||
$this->runTestCase($testEnum, '3', Utils::undefined());
|
||||
$this->runTestCase($testEnum, '"BLUE"', Utils::undefined());
|
||||
$this->runTestCase($testEnum, 'null', null);
|
||||
$this->runTestCase($testEnum, 'NULL', null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -132,6 +132,20 @@ class ArgumentsOfCorrectTypeTest extends TestCase
|
||||
');
|
||||
}
|
||||
|
||||
/**
|
||||
* @it Enum with null value
|
||||
*/
|
||||
public function testEnumWithNullValue()
|
||||
{
|
||||
$this->expectPassesRule(new ArgumentsOfCorrectType(), '
|
||||
{
|
||||
complicatedArgs {
|
||||
enumArgField(enumArg: NO_FUR)
|
||||
}
|
||||
}
|
||||
');
|
||||
}
|
||||
|
||||
/**
|
||||
* @it null into nullable type
|
||||
*/
|
||||
|
@ -183,6 +183,7 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase
|
||||
'BLACK' => [ 'value' => 1 ],
|
||||
'TAN' => [ 'value' => 2 ],
|
||||
'SPOTTED' => [ 'value' => 3 ],
|
||||
'NO_FUR' => [ 'value' => null ],
|
||||
],
|
||||
]);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user