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
|
// Scalar/Enum input checks to ensure the type can parse the value to
|
||||||
// a non-null value.
|
// a non-null value.
|
||||||
$parseResult = $type->parseValue($value);
|
$parseResult = $type->parseValue($value);
|
||||||
if (null === $parseResult) {
|
if (null === $parseResult && !$type->isValidValue($value)) {
|
||||||
$v = Utils::printSafe($value);
|
$v = Utils::printSafe($value);
|
||||||
return [
|
return [
|
||||||
"Expected type \"{$type->name}\", found $v."
|
"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;
|
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
|
* @param $value
|
||||||
* @return null
|
* @return null
|
||||||
|
@ -31,4 +31,16 @@ interface LeafType
|
|||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function parseLiteral($valueNode);
|
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);
|
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) {
|
if ($type instanceof LeafType) {
|
||||||
$parsed = $type->parseLiteral($valueNode);
|
$parsed = $type->parseLiteral($valueNode);
|
||||||
|
|
||||||
if (null === $parsed) {
|
if (null === $parsed && !$type->isValidLiteral($valueNode)) {
|
||||||
// null represent a failure to parse correctly,
|
// Invalid values represent a failure to parse correctly, in which case
|
||||||
// in which case no value is returned.
|
// no value is returned.
|
||||||
return $undefined;
|
return $undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,6 +43,16 @@ class MixedStore implements \ArrayAccess
|
|||||||
*/
|
*/
|
||||||
private $lastArrayValue;
|
private $lastArrayValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var mixed
|
||||||
|
*/
|
||||||
|
private $nullValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
private $nullValueIsSet = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MixedStore constructor.
|
* MixedStore constructor.
|
||||||
*/
|
*/
|
||||||
@ -83,6 +93,9 @@ class MixedStore implements \ArrayAccess
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (null === $offset) {
|
||||||
|
return $this->nullValueIsSet;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,6 +127,9 @@ class MixedStore implements \ArrayAccess
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (null === $offset) {
|
||||||
|
return $this->nullValue;
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,6 +154,9 @@ class MixedStore implements \ArrayAccess
|
|||||||
} else if (is_array($offset)) {
|
} else if (is_array($offset)) {
|
||||||
$this->arrayKeys[] = $offset;
|
$this->arrayKeys[] = $offset;
|
||||||
$this->arrayValues[] = $value;
|
$this->arrayValues[] = $value;
|
||||||
|
} else if (null === $offset) {
|
||||||
|
$this->nullValue = $value;
|
||||||
|
$this->nullValueIsSet = true;
|
||||||
} else {
|
} else {
|
||||||
throw new \InvalidArgumentException("Unexpected offset type: " . Utils::printSafe($offset));
|
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->arrayKeys, $index, 1);
|
||||||
array_splice($this->arrayValues, $index, 1);
|
array_splice($this->arrayValues, $index, 1);
|
||||||
}
|
}
|
||||||
|
} else if (null === $offset) {
|
||||||
|
$this->nullValue = null;
|
||||||
|
$this->nullValueIsSet = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,16 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace GraphQL\Validator;
|
namespace GraphQL\Validator;
|
||||||
|
|
||||||
use GraphQL\Error\Error;
|
|
||||||
use GraphQL\Error\InvariantViolation;
|
use GraphQL\Error\InvariantViolation;
|
||||||
use GraphQL\Language\AST\ListValueNode;
|
use GraphQL\Language\AST\ListValueNode;
|
||||||
use GraphQL\Language\AST\DocumentNode;
|
use GraphQL\Language\AST\DocumentNode;
|
||||||
use GraphQL\Language\AST\FragmentSpreadNode;
|
|
||||||
use GraphQL\Language\AST\Node;
|
|
||||||
use GraphQL\Language\AST\NodeKind;
|
use GraphQL\Language\AST\NodeKind;
|
||||||
use GraphQL\Language\AST\NullValueNode;
|
use GraphQL\Language\AST\NullValueNode;
|
||||||
use GraphQL\Language\AST\ValueNode;
|
|
||||||
use GraphQL\Language\AST\VariableNode;
|
use GraphQL\Language\AST\VariableNode;
|
||||||
use GraphQL\Language\Printer;
|
use GraphQL\Language\Printer;
|
||||||
use GraphQL\Language\Visitor;
|
use GraphQL\Language\Visitor;
|
||||||
use GraphQL\Language\VisitorOperation;
|
|
||||||
use GraphQL\Schema;
|
use GraphQL\Schema;
|
||||||
use GraphQL\Type\Definition\InputObjectType;
|
use GraphQL\Type\Definition\InputObjectType;
|
||||||
use GraphQL\Type\Definition\InputType;
|
|
||||||
use GraphQL\Type\Definition\LeafType;
|
use GraphQL\Type\Definition\LeafType;
|
||||||
use GraphQL\Type\Definition\ListOfType;
|
use GraphQL\Type\Definition\ListOfType;
|
||||||
use GraphQL\Type\Definition\NonNull;
|
use GraphQL\Type\Definition\NonNull;
|
||||||
@ -231,11 +225,8 @@ class DocumentValidator
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($type instanceof LeafType) {
|
if ($type instanceof LeafType) {
|
||||||
// Scalar/Enum input checks to ensure the type can parse the value to
|
// Scalars must parse to a non-null value
|
||||||
// a non-null value.
|
if (!$type->isValidLiteral($valueNode)) {
|
||||||
$parseResult = $type->parseLiteral($valueNode);
|
|
||||||
|
|
||||||
if (null === $parseResult) {
|
|
||||||
$printed = Printer::doPrint($valueNode);
|
$printed = Printer::doPrint($valueNode);
|
||||||
return [ "Expected type \"{$type->name}\", found $printed." ];
|
return [ "Expected type \"{$type->name}\", found $printed." ];
|
||||||
}
|
}
|
||||||
|
@ -72,6 +72,7 @@ class ValueFromAstTest extends \PHPUnit_Framework_TestCase
|
|||||||
'RED' => ['value' => 1],
|
'RED' => ['value' => 1],
|
||||||
'GREEN' => ['value' => 2],
|
'GREEN' => ['value' => 2],
|
||||||
'BLUE' => ['value' => 3],
|
'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, '3', Utils::undefined());
|
||||||
$this->runTestCase($testEnum, '"BLUE"', Utils::undefined());
|
$this->runTestCase($testEnum, '"BLUE"', Utils::undefined());
|
||||||
$this->runTestCase($testEnum, 'null', null);
|
$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
|
* @it null into nullable type
|
||||||
*/
|
*/
|
||||||
|
@ -183,6 +183,7 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase
|
|||||||
'BLACK' => [ 'value' => 1 ],
|
'BLACK' => [ 'value' => 1 ],
|
||||||
'TAN' => [ 'value' => 2 ],
|
'TAN' => [ 'value' => 2 ],
|
||||||
'SPOTTED' => [ 'value' => 3 ],
|
'SPOTTED' => [ 'value' => 3 ],
|
||||||
|
'NO_FUR' => [ 'value' => null ],
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user