2015-07-15 23:05:46 +06:00
|
|
|
<?php
|
|
|
|
namespace GraphQL\Validator\Rules;
|
|
|
|
|
|
|
|
|
2016-10-21 16:39:57 +07:00
|
|
|
use GraphQL\Error\Error;
|
2016-11-19 06:12:18 +07:00
|
|
|
use GraphQL\Language\AST\DirectiveNode;
|
|
|
|
use GraphQL\Language\AST\FieldNode;
|
|
|
|
use GraphQL\Language\AST\FragmentDefinitionNode;
|
|
|
|
use GraphQL\Language\AST\FragmentSpreadNode;
|
|
|
|
use GraphQL\Language\AST\InlineFragmentNode;
|
2015-07-15 23:05:46 +06:00
|
|
|
use GraphQL\Language\AST\Node;
|
2016-11-10 22:20:19 +00:00
|
|
|
use GraphQL\Language\AST\NodeType;
|
2016-11-19 06:12:18 +07:00
|
|
|
use GraphQL\Language\AST\OperationDefinitionNode;
|
2015-07-15 23:05:46 +06:00
|
|
|
use GraphQL\Validator\Messages;
|
|
|
|
use GraphQL\Validator\ValidationContext;
|
2016-04-25 03:57:09 +06:00
|
|
|
use GraphQL\Type\Definition\Directive as DirectiveDef;
|
2015-07-15 23:05:46 +06:00
|
|
|
|
|
|
|
class KnownDirectives
|
|
|
|
{
|
2015-08-17 20:01:55 +06:00
|
|
|
static function unknownDirectiveMessage($directiveName)
|
|
|
|
{
|
|
|
|
return "Unknown directive \"$directiveName\".";
|
|
|
|
}
|
|
|
|
|
2016-04-25 03:57:09 +06:00
|
|
|
static function misplacedDirectiveMessage($directiveName, $location)
|
2015-08-17 20:01:55 +06:00
|
|
|
{
|
2016-04-25 03:57:09 +06:00
|
|
|
return "Directive \"$directiveName\" may not be used on \"$location\".";
|
2015-08-17 20:01:55 +06:00
|
|
|
}
|
|
|
|
|
2015-07-15 23:05:46 +06:00
|
|
|
public function __invoke(ValidationContext $context)
|
|
|
|
{
|
|
|
|
return [
|
2016-11-19 06:12:18 +07:00
|
|
|
NodeType::DIRECTIVE => function (DirectiveNode $node, $key, $parent, $path, $ancestors) use ($context) {
|
2015-07-15 23:05:46 +06:00
|
|
|
$directiveDef = null;
|
|
|
|
foreach ($context->getSchema()->getDirectives() as $def) {
|
|
|
|
if ($def->name === $node->name->value) {
|
|
|
|
$directiveDef = $def;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!$directiveDef) {
|
2016-04-25 03:57:09 +06:00
|
|
|
$context->reportError(new Error(
|
2015-08-17 20:01:55 +06:00
|
|
|
self::unknownDirectiveMessage($node->name->value),
|
2015-07-15 23:05:46 +06:00
|
|
|
[$node]
|
2016-04-25 03:57:09 +06:00
|
|
|
));
|
|
|
|
return ;
|
2015-07-15 23:05:46 +06:00
|
|
|
}
|
|
|
|
$appliedTo = $ancestors[count($ancestors) - 1];
|
2016-04-25 03:57:09 +06:00
|
|
|
$candidateLocation = $this->getLocationForAppliedNode($appliedTo);
|
2015-07-15 23:05:46 +06:00
|
|
|
|
2016-04-25 03:57:09 +06:00
|
|
|
if (!$candidateLocation) {
|
|
|
|
$context->reportError(new Error(
|
|
|
|
self::misplacedDirectiveMessage($node->name->value, $node->type),
|
2015-07-15 23:05:46 +06:00
|
|
|
[$node]
|
2016-04-25 03:57:09 +06:00
|
|
|
));
|
|
|
|
} else if (!in_array($candidateLocation, $directiveDef->locations)) {
|
|
|
|
$context->reportError(new Error(
|
|
|
|
self::misplacedDirectiveMessage($node->name->value, $candidateLocation),
|
|
|
|
[ $node ]
|
|
|
|
));
|
2015-07-15 23:05:46 +06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
];
|
|
|
|
}
|
2016-04-25 03:57:09 +06:00
|
|
|
|
|
|
|
private function getLocationForAppliedNode(Node $appliedTo)
|
|
|
|
{
|
|
|
|
switch ($appliedTo->kind) {
|
2016-11-10 22:20:19 +00:00
|
|
|
case NodeType::OPERATION_DEFINITION:
|
2016-04-25 03:57:09 +06:00
|
|
|
switch ($appliedTo->operation) {
|
2016-11-08 16:55:33 +07:00
|
|
|
case 'query': return DirectiveDef::LOCATION_QUERY;
|
|
|
|
case 'mutation': return DirectiveDef::LOCATION_MUTATION;
|
|
|
|
case 'subscription': return DirectiveDef::LOCATION_SUBSCRIPTION;
|
2016-04-25 03:57:09 +06:00
|
|
|
}
|
|
|
|
break;
|
2016-11-10 22:20:19 +00:00
|
|
|
case NodeType::FIELD: return DirectiveDef::LOCATION_FIELD;
|
|
|
|
case NodeType::FRAGMENT_SPREAD: return DirectiveDef::LOCATION_FRAGMENT_SPREAD;
|
|
|
|
case NodeType::INLINE_FRAGMENT: return DirectiveDef::LOCATION_INLINE_FRAGMENT;
|
|
|
|
case NodeType::FRAGMENT_DEFINITION: return DirectiveDef::LOCATION_FRAGMENT_DEFINITION;
|
2016-04-25 03:57:09 +06:00
|
|
|
}
|
|
|
|
}
|
2015-07-15 23:05:46 +06:00
|
|
|
}
|