Utility function getDirectiveValues + related refactoring

This commit is contained in:
Vladimir Razuvaev 2017-07-05 19:33:25 +07:00
parent a79a51d445
commit ea94ee7515
3 changed files with 67 additions and 52 deletions

View File

@ -8,6 +8,8 @@ use GraphQL\Executor\Promise\Promise;
use GraphQL\Language\AST\DocumentNode;
use GraphQL\Language\AST\FieldNode;
use GraphQL\Language\AST\FragmentDefinitionNode;
use GraphQL\Language\AST\FragmentSpreadNode;
use GraphQL\Language\AST\InlineFragmentNode;
use GraphQL\Language\AST\NodeKind;
use GraphQL\Language\AST\OperationDefinitionNode;
use GraphQL\Language\AST\SelectionSetNode;
@ -508,7 +510,7 @@ class Executor
foreach ($selectionSet->selections as $selection) {
switch ($selection->kind) {
case NodeKind::FIELD:
if (!$this->shouldIncludeNode($selection->directives)) {
if (!$this->shouldIncludeNode($selection)) {
continue;
}
$name = self::getFieldEntryKey($selection);
@ -518,7 +520,7 @@ class Executor
$fields[$name][] = $selection;
break;
case NodeKind::INLINE_FRAGMENT:
if (!$this->shouldIncludeNode($selection->directives) ||
if (!$this->shouldIncludeNode($selection) ||
!$this->doesFragmentConditionMatch($selection, $runtimeType)
) {
continue;
@ -532,7 +534,7 @@ class Executor
break;
case NodeKind::FRAGMENT_SPREAD:
$fragName = $selection->name->value;
if (!empty($visitedFragmentNames[$fragName]) || !$this->shouldIncludeNode($selection->directives)) {
if (!empty($visitedFragmentNames[$fragName]) || !$this->shouldIncludeNode($selection)) {
continue;
}
$visitedFragmentNames[$fragName] = true;
@ -558,43 +560,35 @@ class Executor
* Determines if a field should be included based on the @include and @skip
* directives, where @skip has higher precedence than @include.
*
* @param $directives
* @param FragmentSpreadNode | FieldNode | InlineFragmentNode $node
* @return bool
*/
private function shouldIncludeNode($directives)
private function shouldIncludeNode($node)
{
$exeContext = $this->exeContext;
$variableValues = $this->exeContext->variableValues;
$skipDirective = Directive::skipDirective();
$skip = Values::getDirectiveValues(
$skipDirective,
$node,
$variableValues
);
if (isset($skip['if']) && $skip['if'] === true) {
return false;
}
$includeDirective = Directive::includeDirective();
/** @var \GraphQL\Language\AST\DirectiveNode $skipNode */
$skipNode = $directives
? Utils::find($directives, function(\GraphQL\Language\AST\DirectiveNode $directive) use ($skipDirective) {
return $directive->name->value === $skipDirective->name;
})
: null;
$include = Values::getDirectiveValues(
$includeDirective,
$node,
$variableValues
);
if ($skipNode) {
$argValues = Values::getArgumentValues($skipDirective, $skipNode, $exeContext->variableValues);
if (isset($argValues['if']) && $argValues['if'] === true) {
return false;
}
if (isset($include['if']) && $include['if'] === false) {
return false;
}
/** @var \GraphQL\Language\AST\DirectiveNode $includeNode */
$includeNode = $directives
? Utils::find($directives, function(\GraphQL\Language\AST\DirectiveNode $directive) use ($includeDirective) {
return $directive->name->value === $includeDirective->name;
})
: null;
if ($includeNode) {
$argValues = Values::getArgumentValues($includeDirective, $includeNode, $exeContext->variableValues);
if (isset($argValues['if']) && $argValues['if'] === false) {
return false;
}
}
return true;
}

View File

@ -5,15 +5,17 @@ namespace GraphQL\Executor;
use GraphQL\Error\Error;
use GraphQL\Error\InvariantViolation;
use GraphQL\Language\AST\ArgumentNode;
use GraphQL\Language\AST\DirectiveNode;
use GraphQL\Language\AST\EnumValueDefinitionNode;
use GraphQL\Language\AST\FieldDefinitionNode;
use GraphQL\Language\AST\FieldNode;
use GraphQL\Language\AST\NullValueNode;
use GraphQL\Language\AST\ValueNode;
use GraphQL\Language\AST\FragmentSpreadNode;
use GraphQL\Language\AST\InlineFragmentNode;
use GraphQL\Language\AST\VariableNode;
use GraphQL\Language\AST\VariableDefinitionNode;
use GraphQL\Language\Printer;
use GraphQL\Schema;
use GraphQL\Type\Definition\Directive;
use GraphQL\Type\Definition\FieldArgument;
use GraphQL\Type\Definition\FieldDefinition;
use GraphQL\Type\Definition\InputObjectType;
use GraphQL\Type\Definition\InputType;
@ -161,6 +163,33 @@ class Values
return $coercedValues;
}
/**
* Prepares an object map of argument values given a directive definition
* and a AST node which may contain directives. Optionally also accepts a map
* of variable values.
*
* If the directive does not exist on the node, returns undefined.
*
* @param Directive $directiveDef
* @param FragmentSpreadNode | FieldNode | InlineFragmentNode | EnumValueDefinitionNode | FieldDefinitionNode $node
* @param array|null $variableValues
*
* @return array|null
*/
public static function getDirectiveValues(Directive $directiveDef, $node, $variableValues = null)
{
if (isset($node->directives) && is_array($node->directives)) {
$directiveNode = Utils::find($node->directives, function(DirectiveNode $directive) use ($directiveDef) {
return $directive->name->value === $directiveDef->name;
});
if ($directiveNode) {
return self::getArgumentValues($directiveDef, $directiveNode, $variableValues);
}
}
return null;
}
/**
* @deprecated as of 8.0 (Moved to Utils\AST::valueFromAST)
*

View File

@ -6,6 +6,8 @@ use GraphQL\Executor\Values;
use GraphQL\Language\AST\DirectiveDefinitionNode;
use GraphQL\Language\AST\DocumentNode;
use GraphQL\Language\AST\EnumTypeDefinitionNode;
use GraphQL\Language\AST\EnumValueDefinitionNode;
use GraphQL\Language\AST\FieldDefinitionNode;
use GraphQL\Language\AST\InputObjectTypeDefinitionNode;
use GraphQL\Language\AST\InterfaceTypeDefinitionNode;
use GraphQL\Language\AST\NodeKind;
@ -359,7 +361,7 @@ class BuildSchema
'type' => $this->produceOutputType($field->type),
'description' => $this->getDescription($field),
'args' => $this->makeInputValues($field->arguments),
'deprecationReason' => $this->getDeprecationReason($field->directives)
'deprecationReason' => $this->getDeprecationReason($field)
];
}
);
@ -416,7 +418,7 @@ class BuildSchema
function($enumValue) {
return [
'description' => $this->getDescription($enumValue),
'deprecationReason' => $this->getDeprecationReason($enumValue->directives)
'deprecationReason' => $this->getDeprecationReason($enumValue)
];
}
)
@ -461,23 +463,13 @@ class BuildSchema
* Given a collection of directives, returns the string value for the
* deprecation reason.
*
* @param $directives
* @param EnumValueDefinitionNode | FieldDefinitionNode $node
* @return string
*/
private function getDeprecationReason($directives)
private function getDeprecationReason($node)
{
$deprecatedAST = $directives ? Utils::find(
$directives,
function($directive) {
return $directive->name->value === Directive::deprecatedDirective()->name;
}
) : null;
if (!$deprecatedAST) {
return;
}
return Values::getArgumentValues(
Directive::deprecatedDirective(),
$deprecatedAST
)['reason'];
$deprecated = Values::getDirectiveValues(Directive::deprecatedDirective(), $node);
return isset($deprecated['reason']) ? $deprecated['reason'] : null;
}
/**