From 203fddfe4ec98fa82f349e1f5c6378d30cedd35f Mon Sep 17 00:00:00 2001 From: Vladimir Razuvaev Date: Fri, 18 Aug 2017 20:48:27 +0700 Subject: [PATCH] Abstract base class for validation rules --- UPGRADE.md | 43 ++++++++ src/GraphQL.php | 40 ++++++-- src/Validator/DocumentValidator.php | 99 +++++++++++-------- src/Validator/Rules/AbstractQuerySecurity.php | 4 +- .../Rules/AbstractValidationRule.php | 26 +++++ .../Rules/ArgumentsOfCorrectType.php | 4 +- src/Validator/Rules/CustomValidationRule.php | 27 +++++ .../Rules/DefaultValuesOfCorrectType.php | 4 +- src/Validator/Rules/DisableIntrospection.php | 4 +- src/Validator/Rules/FieldsOnCorrectType.php | 4 +- .../Rules/FragmentsOnCompositeTypes.php | 4 +- src/Validator/Rules/KnownArgumentNames.php | 4 +- src/Validator/Rules/KnownDirectives.php | 4 +- src/Validator/Rules/KnownFragmentNames.php | 4 +- src/Validator/Rules/KnownTypeNames.php | 4 +- .../Rules/LoneAnonymousOperation.php | 4 +- src/Validator/Rules/NoFragmentCycles.php | 11 +-- src/Validator/Rules/NoUndefinedVariables.php | 4 +- src/Validator/Rules/NoUnusedFragments.php | 4 +- src/Validator/Rules/NoUnusedVariables.php | 4 +- .../Rules/OverlappingFieldsCanBeMerged.php | 4 +- .../Rules/PossibleFragmentSpreads.php | 4 +- .../Rules/ProvidedNonNullArguments.php | 4 +- src/Validator/Rules/QueryComplexity.php | 6 +- src/Validator/Rules/QueryDepth.php | 2 +- src/Validator/Rules/ScalarLeafs.php | 4 +- src/Validator/Rules/UniqueArgumentNames.php | 4 +- .../Rules/UniqueDirectivesPerLocation.php | 4 +- src/Validator/Rules/UniqueFragmentNames.php | 4 +- src/Validator/Rules/UniqueInputFieldNames.php | 4 +- src/Validator/Rules/UniqueOperationNames.php | 4 +- src/Validator/Rules/UniqueVariableNames.php | 4 +- .../Rules/VariablesAreInputTypes.php | 4 +- .../Rules/VariablesInAllowedPosition.php | 4 +- tests/Server/QueryExecutionTest.php | 9 +- tests/Validator/QueryComplexityTest.php | 5 +- tests/Validator/ValidationTest.php | 12 +++ 37 files changed, 268 insertions(+), 116 deletions(-) create mode 100644 src/Validator/Rules/AbstractValidationRule.php create mode 100644 src/Validator/Rules/CustomValidationRule.php diff --git a/UPGRADE.md b/UPGRADE.md index d081b52..a35e094 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -43,6 +43,49 @@ But note that this is deprecated format and will be removed in future versions. In general, if new default formatting doesn't work for you - just set [your own error formatter](http://webonyx.github.io/graphql-php/error-handling/#custom-error-handling-and-formatting). +### Breaking: Validation rules now have abstract base class +Previously any callable was accepted by DocumentValidator as validation rule. Now only instances of +`GraphQL\Validator\Rules\AbstractValidationRule` are allowed. + +If you were using custom validation rules, just wrap them with +`GraphQL\Validator\Rules\CustomValidationRule` (created for backwards compatibility). + +Before: +```php +use GraphQL\Validator\DocumentValidator; + +$myRule = function(ValidationContext $context) {}; +DocumentValidator::validate($schema, $ast, [$myRule]); +``` + +After: +```php +use GraphQL\Validator\Rules\CustomValidationRule; +use GraphQL\Validator\DocumentValidator; + +$myRule = new CustomValidationRule('MyRule', function(ValidationContext $context) {}); +DocumentValidator::validate($schema, $ast, [$myRule]); +``` + +Also `DocumentValidator::addRule()` signature changed. + +Before the change: +```php +use GraphQL\Validator\DocumentValidator; + +$myRule = function(ValidationContext $context) {}; +DocumentValidator::addRule('MyRuleName', $myRule); +``` + +After the change: +```php +use GraphQL\Validator\DocumentValidator; + +$myRule = new CustomValidationRulefunction('MyRule', ValidationContext $context) {}); +DocumentValidator::addRule($myRule); +``` + + ### Breaking: AST now uses `NodeList` vs array for lists of nodes It helps us unserialize AST from array lazily. This change affects you only if you use `array_` functions with AST or mutate AST directly. diff --git a/src/GraphQL.php b/src/GraphQL.php index ca8ce48..6cba278 100644 --- a/src/GraphQL.php +++ b/src/GraphQL.php @@ -113,9 +113,18 @@ class GraphQL $documentNode = Parser::parse(new Source($source ?: '', 'GraphQL')); } - /** @var QueryComplexity $queryComplexity */ - $queryComplexity = DocumentValidator::getRule('QueryComplexity'); - $queryComplexity->setRawVariableValues($variableValues); + // FIXME + if (!empty($validationRules)) { + foreach ($validationRules as $rule) { + if ($rule instanceof QueryComplexity) { + $rule->setRawVariableValues($variableValues); + } + } + } else { + /** @var QueryComplexity $queryComplexity */ + $queryComplexity = DocumentValidator::getRule(QueryComplexity::class); + $queryComplexity->setRawVariableValues($variableValues); + } $validationErrors = DocumentValidator::validate($schema, $documentNode, $validationRules); @@ -223,7 +232,7 @@ class GraphQL * * @return Directive[] */ - public static function getInternalDirectives() + public static function getStandardDirectives() { return array_values(Directive::getInternalDirectives()); } @@ -233,9 +242,17 @@ class GraphQL * * @return Type[] */ - public static function getInternalTypes() + public static function getStandardTypes() { - return Type::getInternalTypes(); + return array_values(Type::getInternalTypes()); + } + + /** + * @return array + */ + public static function getStandardValidationRules() + { + return array_values(DocumentValidator::defaultRules()); } /** @@ -253,4 +270,15 @@ class GraphQL { Executor::setPromiseAdapter($promiseAdapter); } + + /** + * Returns directives defined in GraphQL spec + * + * @deprecated Renamed to getStandardDirectives + * @return Directive[] + */ + public static function getInternalDirectives() + { + return self::getStandardDirectives(); + } } diff --git a/src/Validator/DocumentValidator.php b/src/Validator/DocumentValidator.php index 790b9aa..f87e708 100644 --- a/src/Validator/DocumentValidator.php +++ b/src/Validator/DocumentValidator.php @@ -18,6 +18,7 @@ use GraphQL\Type\Definition\NonNull; use GraphQL\Type\Definition\Type; use GraphQL\Utils\Utils; use GraphQL\Utils\TypeInfo; +use GraphQL\Validator\Rules\AbstractValidationRule; use GraphQL\Validator\Rules\ArgumentsOfCorrectType; use GraphQL\Validator\Rules\DefaultValuesOfCorrectType; use GraphQL\Validator\Rules\DisableIntrospection; @@ -53,6 +54,8 @@ class DocumentValidator private static $defaultRules; + private static $securityRules; + private static $initRules = false; /** @@ -63,8 +66,8 @@ class DocumentValidator public static function allRules() { if (!self::$initRules) { - self::$rules = array_merge(static::defaultRules(), self::$rules); - self::$initRules = true; + static::$rules = array_merge(static::defaultRules(), self::securityRules(), self::$rules); + static::$initRules = true; } return self::$rules; @@ -74,64 +77,82 @@ class DocumentValidator { if (null === self::$defaultRules) { self::$defaultRules = [ - 'UniqueOperationNames' => new UniqueOperationNames(), - 'LoneAnonymousOperation' => new LoneAnonymousOperation(), - 'KnownTypeNames' => new KnownTypeNames(), - 'FragmentsOnCompositeTypes' => new FragmentsOnCompositeTypes(), - 'VariablesAreInputTypes' => new VariablesAreInputTypes(), - 'ScalarLeafs' => new ScalarLeafs(), - 'FieldsOnCorrectType' => new FieldsOnCorrectType(), - 'UniqueFragmentNames' => new UniqueFragmentNames(), - 'KnownFragmentNames' => new KnownFragmentNames(), - 'NoUnusedFragments' => new NoUnusedFragments(), - 'PossibleFragmentSpreads' => new PossibleFragmentSpreads(), - 'NoFragmentCycles' => new NoFragmentCycles(), - 'UniqueVariableNames' => new UniqueVariableNames(), - 'NoUndefinedVariables' => new NoUndefinedVariables(), - 'NoUnusedVariables' => new NoUnusedVariables(), - 'KnownDirectives' => new KnownDirectives(), - 'UniqueDirectivesPerLocation' => new UniqueDirectivesPerLocation(), - 'KnownArgumentNames' => new KnownArgumentNames(), - 'UniqueArgumentNames' => new UniqueArgumentNames(), - 'ArgumentsOfCorrectType' => new ArgumentsOfCorrectType(), - 'ProvidedNonNullArguments' => new ProvidedNonNullArguments(), - 'DefaultValuesOfCorrectType' => new DefaultValuesOfCorrectType(), - 'VariablesInAllowedPosition' => new VariablesInAllowedPosition(), - 'OverlappingFieldsCanBeMerged' => new OverlappingFieldsCanBeMerged(), - 'UniqueInputFieldNames' => new UniqueInputFieldNames(), - - // Query Security - 'DisableIntrospection' => new DisableIntrospection(DisableIntrospection::DISABLED), // DEFAULT DISABLED - 'QueryDepth' => new QueryDepth(QueryDepth::DISABLED), // default disabled - 'QueryComplexity' => new QueryComplexity(QueryComplexity::DISABLED), // default disabled + UniqueOperationNames::class => new UniqueOperationNames(), + LoneAnonymousOperation::class => new LoneAnonymousOperation(), + KnownTypeNames::class => new KnownTypeNames(), + FragmentsOnCompositeTypes::class => new FragmentsOnCompositeTypes(), + VariablesAreInputTypes::class => new VariablesAreInputTypes(), + ScalarLeafs::class => new ScalarLeafs(), + FieldsOnCorrectType::class => new FieldsOnCorrectType(), + UniqueFragmentNames::class => new UniqueFragmentNames(), + KnownFragmentNames::class => new KnownFragmentNames(), + NoUnusedFragments::class => new NoUnusedFragments(), + PossibleFragmentSpreads::class => new PossibleFragmentSpreads(), + NoFragmentCycles::class => new NoFragmentCycles(), + UniqueVariableNames::class => new UniqueVariableNames(), + NoUndefinedVariables::class => new NoUndefinedVariables(), + NoUnusedVariables::class => new NoUnusedVariables(), + KnownDirectives::class => new KnownDirectives(), + UniqueDirectivesPerLocation::class => new UniqueDirectivesPerLocation(), + KnownArgumentNames::class => new KnownArgumentNames(), + UniqueArgumentNames::class => new UniqueArgumentNames(), + ArgumentsOfCorrectType::class => new ArgumentsOfCorrectType(), + ProvidedNonNullArguments::class => new ProvidedNonNullArguments(), + DefaultValuesOfCorrectType::class => new DefaultValuesOfCorrectType(), + VariablesInAllowedPosition::class => new VariablesInAllowedPosition(), + OverlappingFieldsCanBeMerged::class => new OverlappingFieldsCanBeMerged(), + UniqueInputFieldNames::class => new UniqueInputFieldNames(), ]; } return self::$defaultRules; } + /** + * @return array + */ + public static function securityRules() + { + // This way of defining rules is deprecated + // When custom security rule is required - it should be just added via DocumentValidator::addRule(); + // TODO: deprecate this + + if (null === self::$securityRules) { + self::$securityRules = [ + DisableIntrospection::class => new DisableIntrospection(DisableIntrospection::DISABLED), // DEFAULT DISABLED + QueryDepth::class => new QueryDepth(QueryDepth::DISABLED), // default disabled + QueryComplexity::class => new QueryComplexity(QueryComplexity::DISABLED), // default disabled + ]; + } + return self::$securityRules; + } + /** * Returns validation rule * * @param string $name - * @return callable|null + * @return AbstractValidationRule */ public static function getRule($name) { $rules = static::allRules(); + if (isset($rules[$name])) { + return $rules[$name]; + } + + $name = "GraphQL\\Validator\\Rules\\$name"; return isset($rules[$name]) ? $rules[$name] : null ; } /** * Add rule to list of default validation rules * - * @param string $name - * @param callable $rule + * @param AbstractValidationRule $rule */ - public static function addRule($name, callable $rule) + public static function addRule(AbstractValidationRule $rule) { - self::$rules[$name] = $rule; + self::$rules[$rule->getName()] = $rule; } /** @@ -292,7 +313,7 @@ class DocumentValidator * @param Schema $schema * @param TypeInfo $typeInfo * @param DocumentNode $documentNode - * @param array $rules + * @param AbstractValidationRule[] $rules * @return array */ public static function visitUsingRules(Schema $schema, TypeInfo $typeInfo, DocumentNode $documentNode, array $rules) @@ -300,7 +321,7 @@ class DocumentValidator $context = new ValidationContext($schema, $documentNode, $typeInfo); $visitors = []; foreach ($rules as $rule) { - $visitors[] = $rule($context); + $visitors[] = $rule->getVisitor($context); } Visitor::visit($documentNode, Visitor::visitWithTypeInfo($typeInfo, Visitor::visitInParallel($visitors))); return $context->getErrors(); diff --git a/src/Validator/Rules/AbstractQuerySecurity.php b/src/Validator/Rules/AbstractQuerySecurity.php index ef0d4a0..cfdc7bc 100644 --- a/src/Validator/Rules/AbstractQuerySecurity.php +++ b/src/Validator/Rules/AbstractQuerySecurity.php @@ -14,7 +14,7 @@ use GraphQL\Type\Introspection; use GraphQL\Utils\TypeInfo; use GraphQL\Validator\ValidationContext; -abstract class AbstractQuerySecurity +abstract class AbstractQuerySecurity extends AbstractValidationRule { const DISABLED = 0; @@ -83,7 +83,7 @@ abstract class AbstractQuerySecurity * time we do not know what object type will be used, so we unconditionally * spread in all fragments. * - * @see GraphQL\Validator\Rules\OverlappingFieldsCanBeMerged + * @see \GraphQL\Validator\Rules\OverlappingFieldsCanBeMerged * * @param ValidationContext $context * @param Type|null $parentType diff --git a/src/Validator/Rules/AbstractValidationRule.php b/src/Validator/Rules/AbstractValidationRule.php new file mode 100644 index 0000000..7bf9189 --- /dev/null +++ b/src/Validator/Rules/AbstractValidationRule.php @@ -0,0 +1,26 @@ +name ?: get_class($this); + } + + public function __invoke(ValidationContext $context) + { + return $this->getVisitor($context); + } + + /** + * @param ValidationContext $context + * @return Error[] + */ + abstract public function getVisitor(ValidationContext $context); +} diff --git a/src/Validator/Rules/ArgumentsOfCorrectType.php b/src/Validator/Rules/ArgumentsOfCorrectType.php index 3ee3162..3e37322 100644 --- a/src/Validator/Rules/ArgumentsOfCorrectType.php +++ b/src/Validator/Rules/ArgumentsOfCorrectType.php @@ -9,7 +9,7 @@ use GraphQL\Language\Visitor; use GraphQL\Validator\DocumentValidator; use GraphQL\Validator\ValidationContext; -class ArgumentsOfCorrectType +class ArgumentsOfCorrectType extends AbstractValidationRule { static function badValueMessage($argName, $type, $value, $verboseErrors = []) { @@ -17,7 +17,7 @@ class ArgumentsOfCorrectType return "Argument \"$argName\" has invalid value $value.$message"; } - public function __invoke(ValidationContext $context) + public function getVisitor(ValidationContext $context) { return [ NodeKind::ARGUMENT => function(ArgumentNode $argNode) use ($context) { diff --git a/src/Validator/Rules/CustomValidationRule.php b/src/Validator/Rules/CustomValidationRule.php new file mode 100644 index 0000000..ba7cd40 --- /dev/null +++ b/src/Validator/Rules/CustomValidationRule.php @@ -0,0 +1,27 @@ +name = $name; + $this->visitorFn = $visitorFn; + } + + /** + * @param ValidationContext $context + * @return Error[] + */ + public function getVisitor(ValidationContext $context) + { + $fn = $this->visitorFn; + return $fn($context); + } +} diff --git a/src/Validator/Rules/DefaultValuesOfCorrectType.php b/src/Validator/Rules/DefaultValuesOfCorrectType.php index b8f1b1d..792acd7 100644 --- a/src/Validator/Rules/DefaultValuesOfCorrectType.php +++ b/src/Validator/Rules/DefaultValuesOfCorrectType.php @@ -12,7 +12,7 @@ use GraphQL\Type\Definition\NonNull; use GraphQL\Validator\DocumentValidator; use GraphQL\Validator\ValidationContext; -class DefaultValuesOfCorrectType +class DefaultValuesOfCorrectType extends AbstractValidationRule { static function badValueForDefaultArgMessage($varName, $type, $value, $verboseErrors = null) { @@ -27,7 +27,7 @@ class DefaultValuesOfCorrectType "Perhaps you meant to use type $guessType."; } - public function __invoke(ValidationContext $context) + public function getVisitor(ValidationContext $context) { return [ NodeKind::VARIABLE_DEFINITION => function(VariableDefinitionNode $varDefNode) use ($context) { diff --git a/src/Validator/Rules/DisableIntrospection.php b/src/Validator/Rules/DisableIntrospection.php index f820375..dec9f37 100644 --- a/src/Validator/Rules/DisableIntrospection.php +++ b/src/Validator/Rules/DisableIntrospection.php @@ -11,7 +11,7 @@ class DisableIntrospection extends AbstractQuerySecurity const ENABLED = 1; private $isEnabled; - public function __construct($enabled) + public function __construct($enabled = self::ENABLED) { $this->setEnabled($enabled); } @@ -31,7 +31,7 @@ class DisableIntrospection extends AbstractQuerySecurity return $this->isEnabled !== static::DISABLED; } - public function __invoke(ValidationContext $context) + public function getVisitor(ValidationContext $context) { return $this->invokeIfNeeded( $context, diff --git a/src/Validator/Rules/FieldsOnCorrectType.php b/src/Validator/Rules/FieldsOnCorrectType.php index 7f339e7..26ee748 100644 --- a/src/Validator/Rules/FieldsOnCorrectType.php +++ b/src/Validator/Rules/FieldsOnCorrectType.php @@ -7,7 +7,7 @@ use GraphQL\Language\AST\NodeKind; use GraphQL\Utils\Utils; use GraphQL\Validator\ValidationContext; -class FieldsOnCorrectType +class FieldsOnCorrectType extends AbstractValidationRule { static function undefinedFieldMessage($field, $type, array $suggestedTypes = []) { @@ -29,7 +29,7 @@ class FieldsOnCorrectType return $message; } - public function __invoke(ValidationContext $context) + public function getVisitor(ValidationContext $context) { return [ NodeKind::FIELD => function(FieldNode $node) use ($context) { diff --git a/src/Validator/Rules/FragmentsOnCompositeTypes.php b/src/Validator/Rules/FragmentsOnCompositeTypes.php index 1d6e450..f2731d0 100644 --- a/src/Validator/Rules/FragmentsOnCompositeTypes.php +++ b/src/Validator/Rules/FragmentsOnCompositeTypes.php @@ -10,7 +10,7 @@ use GraphQL\Type\Definition\Type; use GraphQL\Utils\TypeInfo; use GraphQL\Validator\ValidationContext; -class FragmentsOnCompositeTypes +class FragmentsOnCompositeTypes extends AbstractValidationRule { static function inlineFragmentOnNonCompositeErrorMessage($type) { @@ -22,7 +22,7 @@ class FragmentsOnCompositeTypes return "Fragment \"$fragName\" cannot condition on non composite type \"$type\"."; } - public function __invoke(ValidationContext $context) + public function getVisitor(ValidationContext $context) { return [ NodeKind::INLINE_FRAGMENT => function(InlineFragmentNode $node) use ($context) { diff --git a/src/Validator/Rules/KnownArgumentNames.php b/src/Validator/Rules/KnownArgumentNames.php index b2dfdb8..78ee3f9 100644 --- a/src/Validator/Rules/KnownArgumentNames.php +++ b/src/Validator/Rules/KnownArgumentNames.php @@ -7,7 +7,7 @@ use GraphQL\Language\AST\NodeKind; use GraphQL\Utils\Utils; use GraphQL\Validator\ValidationContext; -class KnownArgumentNames +class KnownArgumentNames extends AbstractValidationRule { public static function unknownArgMessage($argName, $fieldName, $type) { @@ -19,7 +19,7 @@ class KnownArgumentNames return "Unknown argument \"$argName\" on directive \"@$directiveName\"."; } - public function __invoke(ValidationContext $context) + public function getVisitor(ValidationContext $context) { return [ NodeKind::ARGUMENT => function(ArgumentNode $node, $key, $parent, $path, $ancestors) use ($context) { diff --git a/src/Validator/Rules/KnownDirectives.php b/src/Validator/Rules/KnownDirectives.php index 37c2584..3593f62 100644 --- a/src/Validator/Rules/KnownDirectives.php +++ b/src/Validator/Rules/KnownDirectives.php @@ -9,7 +9,7 @@ use GraphQL\Language\AST\NodeKind; use GraphQL\Validator\ValidationContext; use GraphQL\Type\Definition\DirectiveLocation; -class KnownDirectives +class KnownDirectives extends AbstractValidationRule { static function unknownDirectiveMessage($directiveName) { @@ -21,7 +21,7 @@ class KnownDirectives return "Directive \"$directiveName\" may not be used on \"$location\"."; } - public function __invoke(ValidationContext $context) + public function getVisitor(ValidationContext $context) { return [ NodeKind::DIRECTIVE => function (DirectiveNode $node, $key, $parent, $path, $ancestors) use ($context) { diff --git a/src/Validator/Rules/KnownFragmentNames.php b/src/Validator/Rules/KnownFragmentNames.php index 39e5858..35645db 100644 --- a/src/Validator/Rules/KnownFragmentNames.php +++ b/src/Validator/Rules/KnownFragmentNames.php @@ -8,14 +8,14 @@ use GraphQL\Language\AST\Node; use GraphQL\Language\AST\NodeKind; use GraphQL\Validator\ValidationContext; -class KnownFragmentNames +class KnownFragmentNames extends AbstractValidationRule { static function unknownFragmentMessage($fragName) { return "Unknown fragment \"$fragName\"."; } - public function __invoke(ValidationContext $context) + public function getVisitor(ValidationContext $context) { return [ NodeKind::FRAGMENT_SPREAD => function(FragmentSpreadNode $node) use ($context) { diff --git a/src/Validator/Rules/KnownTypeNames.php b/src/Validator/Rules/KnownTypeNames.php index 7ca22d8..71fa60a 100644 --- a/src/Validator/Rules/KnownTypeNames.php +++ b/src/Validator/Rules/KnownTypeNames.php @@ -8,14 +8,14 @@ use GraphQL\Language\AST\NodeKind; use GraphQL\Language\Visitor; use GraphQL\Validator\ValidationContext; -class KnownTypeNames +class KnownTypeNames extends AbstractValidationRule { static function unknownTypeMessage($type) { return "Unknown type \"$type\"."; } - public function __invoke(ValidationContext $context) + public function getVisitor(ValidationContext $context) { $skip = function() {return Visitor::skipNode();}; diff --git a/src/Validator/Rules/LoneAnonymousOperation.php b/src/Validator/Rules/LoneAnonymousOperation.php index 1d735b5..f02025f 100644 --- a/src/Validator/Rules/LoneAnonymousOperation.php +++ b/src/Validator/Rules/LoneAnonymousOperation.php @@ -15,14 +15,14 @@ use GraphQL\Validator\ValidationContext; * A GraphQL document is only valid if when it contains an anonymous operation * (the query short-hand) that it contains only that one operation definition. */ -class LoneAnonymousOperation +class LoneAnonymousOperation extends AbstractValidationRule { static function anonOperationNotAloneMessage() { return 'This anonymous operation must be the only defined operation.'; } - public function __invoke(ValidationContext $context) + public function getVisitor(ValidationContext $context) { $operationCount = 0; return [ diff --git a/src/Validator/Rules/NoFragmentCycles.php b/src/Validator/Rules/NoFragmentCycles.php index 06d9f18..cf3eb0a 100644 --- a/src/Validator/Rules/NoFragmentCycles.php +++ b/src/Validator/Rules/NoFragmentCycles.php @@ -1,11 +1,4 @@ operationDefs = []; $this->fragmentDefs = []; diff --git a/src/Validator/Rules/NoUnusedVariables.php b/src/Validator/Rules/NoUnusedVariables.php index cd939a2..c004623 100644 --- a/src/Validator/Rules/NoUnusedVariables.php +++ b/src/Validator/Rules/NoUnusedVariables.php @@ -6,7 +6,7 @@ use GraphQL\Language\AST\NodeKind; use GraphQL\Language\AST\OperationDefinitionNode; use GraphQL\Validator\ValidationContext; -class NoUnusedVariables +class NoUnusedVariables extends AbstractValidationRule { static function unusedVariableMessage($varName, $opName = null) { @@ -17,7 +17,7 @@ class NoUnusedVariables public $variableDefs; - public function __invoke(ValidationContext $context) + public function getVisitor(ValidationContext $context) { $this->variableDefs = []; diff --git a/src/Validator/Rules/OverlappingFieldsCanBeMerged.php b/src/Validator/Rules/OverlappingFieldsCanBeMerged.php index db907c9..d0a0fb0 100644 --- a/src/Validator/Rules/OverlappingFieldsCanBeMerged.php +++ b/src/Validator/Rules/OverlappingFieldsCanBeMerged.php @@ -23,7 +23,7 @@ use GraphQL\Utils\PairSet; use GraphQL\Utils\TypeInfo; use GraphQL\Validator\ValidationContext; -class OverlappingFieldsCanBeMerged +class OverlappingFieldsCanBeMerged extends AbstractValidationRule { static function fieldsConflictMessage($responseName, $reason) { @@ -49,7 +49,7 @@ class OverlappingFieldsCanBeMerged */ public $comparedSet; - public function __invoke(ValidationContext $context) + public function getVisitor(ValidationContext $context) { $this->comparedSet = new PairSet(); diff --git a/src/Validator/Rules/PossibleFragmentSpreads.php b/src/Validator/Rules/PossibleFragmentSpreads.php index 598d591..fec7dc7 100644 --- a/src/Validator/Rules/PossibleFragmentSpreads.php +++ b/src/Validator/Rules/PossibleFragmentSpreads.php @@ -16,7 +16,7 @@ use GraphQL\Type\Definition\UnionType; use GraphQL\Validator\ValidationContext; use GraphQL\Utils\TypeInfo; -class PossibleFragmentSpreads +class PossibleFragmentSpreads extends AbstractValidationRule { static function typeIncompatibleSpreadMessage($fragName, $parentType, $fragType) { @@ -28,7 +28,7 @@ class PossibleFragmentSpreads return "Fragment cannot be spread here as objects of type \"$parentType\" can never be of type \"$fragType\"."; } - public function __invoke(ValidationContext $context) + public function getVisitor(ValidationContext $context) { return [ NodeKind::INLINE_FRAGMENT => function(InlineFragmentNode $node) use ($context) { diff --git a/src/Validator/Rules/ProvidedNonNullArguments.php b/src/Validator/Rules/ProvidedNonNullArguments.php index 1fe8bfc..a0370f9 100644 --- a/src/Validator/Rules/ProvidedNonNullArguments.php +++ b/src/Validator/Rules/ProvidedNonNullArguments.php @@ -12,7 +12,7 @@ use GraphQL\Type\Definition\NonNull; use GraphQL\Utils\Utils; use GraphQL\Validator\ValidationContext; -class ProvidedNonNullArguments +class ProvidedNonNullArguments extends AbstractValidationRule { static function missingFieldArgMessage($fieldName, $argName, $type) { @@ -24,7 +24,7 @@ class ProvidedNonNullArguments return "Directive \"@$directiveName\" argument \"$argName\" of type \"$type\" is required but not provided."; } - public function __invoke(ValidationContext $context) + public function getVisitor(ValidationContext $context) { return [ NodeKind::FIELD => [ diff --git a/src/Validator/Rules/QueryComplexity.php b/src/Validator/Rules/QueryComplexity.php index 0a00fe2..f20334e 100644 --- a/src/Validator/Rules/QueryComplexity.php +++ b/src/Validator/Rules/QueryComplexity.php @@ -31,9 +31,9 @@ class QueryComplexity extends AbstractQuerySecurity */ private $context; - public function __construct($maxQueryDepth) + public function __construct($maxQueryComplexity) { - $this->setMaxQueryComplexity($maxQueryDepth); + $this->setMaxQueryComplexity($maxQueryComplexity); } public static function maxQueryComplexityErrorMessage($max, $count) @@ -68,7 +68,7 @@ class QueryComplexity extends AbstractQuerySecurity return $this->rawVariableValues; } - public function __invoke(ValidationContext $context) + public function getVisitor(ValidationContext $context) { $this->context = $context; diff --git a/src/Validator/Rules/QueryDepth.php b/src/Validator/Rules/QueryDepth.php index ca0a8df..5fb7065 100644 --- a/src/Validator/Rules/QueryDepth.php +++ b/src/Validator/Rules/QueryDepth.php @@ -45,7 +45,7 @@ class QueryDepth extends AbstractQuerySecurity return sprintf('Max query depth should be %d but got %d.', $max, $count); } - public function __invoke(ValidationContext $context) + public function getVisitor(ValidationContext $context) { return $this->invokeIfNeeded( $context, diff --git a/src/Validator/Rules/ScalarLeafs.php b/src/Validator/Rules/ScalarLeafs.php index de1f7d6..670403d 100644 --- a/src/Validator/Rules/ScalarLeafs.php +++ b/src/Validator/Rules/ScalarLeafs.php @@ -7,7 +7,7 @@ use GraphQL\Language\AST\NodeKind; use GraphQL\Type\Definition\Type; use GraphQL\Validator\ValidationContext; -class ScalarLeafs +class ScalarLeafs extends AbstractValidationRule { static function noSubselectionAllowedMessage($field, $type) { @@ -19,7 +19,7 @@ class ScalarLeafs return "Field \"$field\" of type \"$type\" must have a sub selection."; } - public function __invoke(ValidationContext $context) + public function getVisitor(ValidationContext $context) { return [ NodeKind::FIELD => function(FieldNode $node) use ($context) { diff --git a/src/Validator/Rules/UniqueArgumentNames.php b/src/Validator/Rules/UniqueArgumentNames.php index 6c4f5c2..7c6eef1 100644 --- a/src/Validator/Rules/UniqueArgumentNames.php +++ b/src/Validator/Rules/UniqueArgumentNames.php @@ -8,7 +8,7 @@ use GraphQL\Language\AST\NodeKind; use GraphQL\Language\Visitor; use GraphQL\Validator\ValidationContext; -class UniqueArgumentNames +class UniqueArgumentNames extends AbstractValidationRule { static function duplicateArgMessage($argName) { @@ -17,7 +17,7 @@ class UniqueArgumentNames public $knownArgNames; - public function __invoke(ValidationContext $context) + public function getVisitor(ValidationContext $context) { $this->knownArgNames = []; diff --git a/src/Validator/Rules/UniqueDirectivesPerLocation.php b/src/Validator/Rules/UniqueDirectivesPerLocation.php index f389b12..08d778a 100644 --- a/src/Validator/Rules/UniqueDirectivesPerLocation.php +++ b/src/Validator/Rules/UniqueDirectivesPerLocation.php @@ -6,14 +6,14 @@ use GraphQL\Language\AST\DirectiveNode; use GraphQL\Language\AST\Node; use GraphQL\Validator\ValidationContext; -class UniqueDirectivesPerLocation +class UniqueDirectivesPerLocation extends AbstractValidationRule { static function duplicateDirectiveMessage($directiveName) { return 'The directive "'.$directiveName.'" can only be used once at this location.'; } - public function __invoke(ValidationContext $context) + public function getVisitor(ValidationContext $context) { return [ 'enter' => function(Node $node) use ($context) { diff --git a/src/Validator/Rules/UniqueFragmentNames.php b/src/Validator/Rules/UniqueFragmentNames.php index 12e92a5..af5706b 100644 --- a/src/Validator/Rules/UniqueFragmentNames.php +++ b/src/Validator/Rules/UniqueFragmentNames.php @@ -9,7 +9,7 @@ use GraphQL\Language\AST\NodeKind; use GraphQL\Language\Visitor; use GraphQL\Validator\ValidationContext; -class UniqueFragmentNames +class UniqueFragmentNames extends AbstractValidationRule { static function duplicateFragmentNameMessage($fragName) { @@ -18,7 +18,7 @@ class UniqueFragmentNames public $knownFragmentNames; - public function __invoke(ValidationContext $context) + public function getVisitor(ValidationContext $context) { $this->knownFragmentNames = []; diff --git a/src/Validator/Rules/UniqueInputFieldNames.php b/src/Validator/Rules/UniqueInputFieldNames.php index cbc7b73..3e60df8 100644 --- a/src/Validator/Rules/UniqueInputFieldNames.php +++ b/src/Validator/Rules/UniqueInputFieldNames.php @@ -8,7 +8,7 @@ use GraphQL\Language\AST\ObjectFieldNode; use GraphQL\Language\Visitor; use GraphQL\Validator\ValidationContext; -class UniqueInputFieldNames +class UniqueInputFieldNames extends AbstractValidationRule { static function duplicateInputFieldMessage($fieldName) { @@ -18,7 +18,7 @@ class UniqueInputFieldNames public $knownNames; public $knownNameStack; - public function __invoke(ValidationContext $context) + public function getVisitor(ValidationContext $context) { $this->knownNames = []; $this->knownNameStack = []; diff --git a/src/Validator/Rules/UniqueOperationNames.php b/src/Validator/Rules/UniqueOperationNames.php index 30e494f..17fff14 100644 --- a/src/Validator/Rules/UniqueOperationNames.php +++ b/src/Validator/Rules/UniqueOperationNames.php @@ -8,7 +8,7 @@ use GraphQL\Language\AST\OperationDefinitionNode; use GraphQL\Language\Visitor; use GraphQL\Validator\ValidationContext; -class UniqueOperationNames +class UniqueOperationNames extends AbstractValidationRule { static function duplicateOperationNameMessage($operationName) { @@ -17,7 +17,7 @@ class UniqueOperationNames public $knownOperationNames; - public function __invoke(ValidationContext $context) + public function getVisitor(ValidationContext $context) { $this->knownOperationNames = []; diff --git a/src/Validator/Rules/UniqueVariableNames.php b/src/Validator/Rules/UniqueVariableNames.php index ee6267a..cdbb1ca 100644 --- a/src/Validator/Rules/UniqueVariableNames.php +++ b/src/Validator/Rules/UniqueVariableNames.php @@ -7,7 +7,7 @@ use GraphQL\Language\AST\NodeKind; use GraphQL\Language\AST\VariableDefinitionNode; use GraphQL\Validator\ValidationContext; -class UniqueVariableNames +class UniqueVariableNames extends AbstractValidationRule { static function duplicateVariableMessage($variableName) { @@ -16,7 +16,7 @@ class UniqueVariableNames public $knownVariableNames; - public function __invoke(ValidationContext $context) + public function getVisitor(ValidationContext $context) { $this->knownVariableNames = []; diff --git a/src/Validator/Rules/VariablesAreInputTypes.php b/src/Validator/Rules/VariablesAreInputTypes.php index 4db3193..a8f1bbf 100644 --- a/src/Validator/Rules/VariablesAreInputTypes.php +++ b/src/Validator/Rules/VariablesAreInputTypes.php @@ -12,14 +12,14 @@ use GraphQL\Type\Definition\Type; use GraphQL\Utils\TypeInfo; use GraphQL\Validator\ValidationContext; -class VariablesAreInputTypes +class VariablesAreInputTypes extends AbstractValidationRule { static function nonInputTypeOnVarMessage($variableName, $typeName) { return "Variable \"\$$variableName\" cannot be non-input type \"$typeName\"."; } - public function __invoke(ValidationContext $context) + public function getVisitor(ValidationContext $context) { return [ NodeKind::VARIABLE_DEFINITION => function(VariableDefinitionNode $node) use ($context) { diff --git a/src/Validator/Rules/VariablesInAllowedPosition.php b/src/Validator/Rules/VariablesInAllowedPosition.php index e29ac57..c0608ff 100644 --- a/src/Validator/Rules/VariablesInAllowedPosition.php +++ b/src/Validator/Rules/VariablesInAllowedPosition.php @@ -11,7 +11,7 @@ use GraphQL\Utils\TypeComparators; use GraphQL\Utils\TypeInfo; use GraphQL\Validator\ValidationContext; -class VariablesInAllowedPosition +class VariablesInAllowedPosition extends AbstractValidationRule { static function badVarPosMessage($varName, $varType, $expectedType) { @@ -21,7 +21,7 @@ class VariablesInAllowedPosition public $varDefMap; - public function __invoke(ValidationContext $context) + public function getVisitor(ValidationContext $context) { return [ NodeKind::OPERATION_DEFINITION => [ diff --git a/tests/Server/QueryExecutionTest.php b/tests/Server/QueryExecutionTest.php index a543327..16c99a7 100644 --- a/tests/Server/QueryExecutionTest.php +++ b/tests/Server/QueryExecutionTest.php @@ -17,6 +17,7 @@ use GraphQL\Server\ServerConfig; use GraphQL\Type\Definition\ObjectType; use GraphQL\Type\Definition\Type; use GraphQL\Validator\DocumentValidator; +use GraphQL\Validator\Rules\CustomValidationRule; use GraphQL\Validator\ValidationContext; class QueryExecutionTest extends \PHPUnit_Framework_TestCase @@ -219,10 +220,10 @@ class QueryExecutionTest extends \PHPUnit_Framework_TestCase $called = false; $rules = [ - function() use (&$called) { + new CustomValidationRule('SomeRule', function() use (&$called) { $called = true; return []; - } + }) ]; $this->config->setValidationRules($rules); @@ -268,9 +269,9 @@ class QueryExecutionTest extends \PHPUnit_Framework_TestCase } else { $called2 = true; return [ - function(ValidationContext $context) { + new CustomValidationRule('MyRule', function(ValidationContext $context) { $context->reportError(new Error("This is the error we are looking for!")); - } + }) ]; } }); diff --git a/tests/Validator/QueryComplexityTest.php b/tests/Validator/QueryComplexityTest.php index 1dd3e37..fb1a8d7 100644 --- a/tests/Validator/QueryComplexityTest.php +++ b/tests/Validator/QueryComplexityTest.php @@ -5,6 +5,7 @@ use GraphQL\Error\Error; use GraphQL\Language\AST\NodeKind; use GraphQL\Language\Parser; use GraphQL\Validator\DocumentValidator; +use GraphQL\Validator\Rules\CustomValidationRule; use GraphQL\Validator\Rules\QueryComplexity; use GraphQL\Validator\ValidationContext; @@ -159,7 +160,7 @@ class QueryComplexityTest extends AbstractQuerySecurityTest $query = 'query MyQuery { human(name: INVALID_VALUE) { dogs {name} } }'; $reportedError = new Error("OtherValidatorError"); - $otherRule = function(ValidationContext $context) use ($reportedError) { + $otherRule = new CustomValidationRule('otherRule', function(ValidationContext $context) use ($reportedError) { return [ NodeKind::OPERATION_DEFINITION => [ 'leave' => function() use ($context, $reportedError) { @@ -167,7 +168,7 @@ class QueryComplexityTest extends AbstractQuerySecurityTest } ] ]; - }; + }); $errors = DocumentValidator::validate( QuerySecuritySchema::buildSchema(), diff --git a/tests/Validator/ValidationTest.php b/tests/Validator/ValidationTest.php index 55f1059..d5fd855 100644 --- a/tests/Validator/ValidationTest.php +++ b/tests/Validator/ValidationTest.php @@ -1,6 +1,9 @@ assertSame($rule, $instance); + } +*/ public function testPassesValidationWithEmptyRules() { $query = '{invalid}';