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

View File

@ -5,15 +5,17 @@ namespace GraphQL\Executor;
use GraphQL\Error\Error; use GraphQL\Error\Error;
use GraphQL\Error\InvariantViolation; use GraphQL\Error\InvariantViolation;
use GraphQL\Language\AST\ArgumentNode; 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\FieldNode;
use GraphQL\Language\AST\NullValueNode; use GraphQL\Language\AST\FragmentSpreadNode;
use GraphQL\Language\AST\ValueNode; use GraphQL\Language\AST\InlineFragmentNode;
use GraphQL\Language\AST\VariableNode; use GraphQL\Language\AST\VariableNode;
use GraphQL\Language\AST\VariableDefinitionNode; use GraphQL\Language\AST\VariableDefinitionNode;
use GraphQL\Language\Printer; use GraphQL\Language\Printer;
use GraphQL\Schema; use GraphQL\Schema;
use GraphQL\Type\Definition\Directive; use GraphQL\Type\Definition\Directive;
use GraphQL\Type\Definition\FieldArgument;
use GraphQL\Type\Definition\FieldDefinition; use GraphQL\Type\Definition\FieldDefinition;
use GraphQL\Type\Definition\InputObjectType; use GraphQL\Type\Definition\InputObjectType;
use GraphQL\Type\Definition\InputType; use GraphQL\Type\Definition\InputType;
@ -161,6 +163,33 @@ class Values
return $coercedValues; 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) * @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\DirectiveDefinitionNode;
use GraphQL\Language\AST\DocumentNode; use GraphQL\Language\AST\DocumentNode;
use GraphQL\Language\AST\EnumTypeDefinitionNode; use GraphQL\Language\AST\EnumTypeDefinitionNode;
use GraphQL\Language\AST\EnumValueDefinitionNode;
use GraphQL\Language\AST\FieldDefinitionNode;
use GraphQL\Language\AST\InputObjectTypeDefinitionNode; use GraphQL\Language\AST\InputObjectTypeDefinitionNode;
use GraphQL\Language\AST\InterfaceTypeDefinitionNode; use GraphQL\Language\AST\InterfaceTypeDefinitionNode;
use GraphQL\Language\AST\NodeKind; use GraphQL\Language\AST\NodeKind;
@ -359,7 +361,7 @@ class BuildSchema
'type' => $this->produceOutputType($field->type), 'type' => $this->produceOutputType($field->type),
'description' => $this->getDescription($field), 'description' => $this->getDescription($field),
'args' => $this->makeInputValues($field->arguments), 'args' => $this->makeInputValues($field->arguments),
'deprecationReason' => $this->getDeprecationReason($field->directives) 'deprecationReason' => $this->getDeprecationReason($field)
]; ];
} }
); );
@ -416,7 +418,7 @@ class BuildSchema
function($enumValue) { function($enumValue) {
return [ return [
'description' => $this->getDescription($enumValue), '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 * Given a collection of directives, returns the string value for the
* deprecation reason. * deprecation reason.
* *
* @param $directives * @param EnumValueDefinitionNode | FieldDefinitionNode $node
* @return string
*/ */
private function getDeprecationReason($directives) private function getDeprecationReason($node)
{ {
$deprecatedAST = $directives ? Utils::find( $deprecated = Values::getDirectiveValues(Directive::deprecatedDirective(), $node);
$directives, return isset($deprecated['reason']) ? $deprecated['reason'] : null;
function($directive) {
return $directive->name->value === Directive::deprecatedDirective()->name;
}
) : null;
if (!$deprecatedAST) {
return;
}
return Values::getArgumentValues(
Directive::deprecatedDirective(),
$deprecatedAST
)['reason'];
} }
/** /**