mirror of
https://github.com/retailcrm/graphql-php.git
synced 2024-11-22 04:46:04 +03:00
Abstract base class for validation rules
This commit is contained in:
parent
9499e5ae8e
commit
203fddfe4e
43
UPGRADE.md
43
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.
|
||||
|
@ -113,9 +113,18 @@ class GraphQL
|
||||
$documentNode = Parser::parse(new Source($source ?: '', 'GraphQL'));
|
||||
}
|
||||
|
||||
// FIXME
|
||||
if (!empty($validationRules)) {
|
||||
foreach ($validationRules as $rule) {
|
||||
if ($rule instanceof QueryComplexity) {
|
||||
$rule->setRawVariableValues($variableValues);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/** @var QueryComplexity $queryComplexity */
|
||||
$queryComplexity = DocumentValidator::getRule('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();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
26
src/Validator/Rules/AbstractValidationRule.php
Normal file
26
src/Validator/Rules/AbstractValidationRule.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
namespace GraphQL\Validator\Rules;
|
||||
|
||||
use GraphQL\Error\Error;
|
||||
use GraphQL\Validator\ValidationContext;
|
||||
|
||||
abstract class AbstractValidationRule
|
||||
{
|
||||
protected $name;
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return $this->name ?: get_class($this);
|
||||
}
|
||||
|
||||
public function __invoke(ValidationContext $context)
|
||||
{
|
||||
return $this->getVisitor($context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ValidationContext $context
|
||||
* @return Error[]
|
||||
*/
|
||||
abstract public function getVisitor(ValidationContext $context);
|
||||
}
|
@ -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) {
|
||||
|
27
src/Validator/Rules/CustomValidationRule.php
Normal file
27
src/Validator/Rules/CustomValidationRule.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
namespace GraphQL\Validator\Rules;
|
||||
|
||||
|
||||
use GraphQL\Error\Error;
|
||||
use GraphQL\Validator\ValidationContext;
|
||||
|
||||
class CustomValidationRule extends AbstractValidationRule
|
||||
{
|
||||
private $visitorFn;
|
||||
|
||||
public function __construct($name, callable $visitorFn)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->visitorFn = $visitorFn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ValidationContext $context
|
||||
* @return Error[]
|
||||
*/
|
||||
public function getVisitor(ValidationContext $context)
|
||||
{
|
||||
$fn = $this->visitorFn;
|
||||
return $fn($context);
|
||||
}
|
||||
}
|
@ -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) {
|
||||
|
@ -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,
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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();};
|
||||
|
||||
|
@ -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 [
|
||||
|
@ -1,11 +1,4 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Vladimir
|
||||
* Date: 11.07.2015
|
||||
* Time: 18:54
|
||||
*/
|
||||
|
||||
namespace GraphQL\Validator\Rules;
|
||||
|
||||
|
||||
@ -18,7 +11,7 @@ use GraphQL\Language\Visitor;
|
||||
use GraphQL\Utils\Utils;
|
||||
use GraphQL\Validator\ValidationContext;
|
||||
|
||||
class NoFragmentCycles
|
||||
class NoFragmentCycles extends AbstractValidationRule
|
||||
{
|
||||
static function cycleErrorMessage($fragName, array $spreadNames = [])
|
||||
{
|
||||
@ -32,7 +25,7 @@ class NoFragmentCycles
|
||||
|
||||
public $spreadPathIndexByName;
|
||||
|
||||
public function __invoke(ValidationContext $context)
|
||||
public function getVisitor(ValidationContext $context)
|
||||
{
|
||||
// Tracks already visited fragments to maintain O(N) and to ensure that cycles
|
||||
// are not redundantly reported.
|
||||
|
@ -15,7 +15,7 @@ use GraphQL\Validator\ValidationContext;
|
||||
*
|
||||
* @package GraphQL\Validator\Rules
|
||||
*/
|
||||
class NoUndefinedVariables
|
||||
class NoUndefinedVariables extends AbstractValidationRule
|
||||
{
|
||||
static function undefinedVarMessage($varName, $opName = null)
|
||||
{
|
||||
@ -24,7 +24,7 @@ class NoUndefinedVariables
|
||||
: "Variable \"$$varName\" is not defined.";
|
||||
}
|
||||
|
||||
public function __invoke(ValidationContext $context)
|
||||
public function getVisitor(ValidationContext $context)
|
||||
{
|
||||
$variableNameDefined = [];
|
||||
|
||||
|
@ -7,7 +7,7 @@ use GraphQL\Language\AST\NodeKind;
|
||||
use GraphQL\Language\Visitor;
|
||||
use GraphQL\Validator\ValidationContext;
|
||||
|
||||
class NoUnusedFragments
|
||||
class NoUnusedFragments extends AbstractValidationRule
|
||||
{
|
||||
static function unusedFragMessage($fragName)
|
||||
{
|
||||
@ -18,7 +18,7 @@ class NoUnusedFragments
|
||||
|
||||
public $fragmentDefs;
|
||||
|
||||
public function __invoke(ValidationContext $context)
|
||||
public function getVisitor(ValidationContext $context)
|
||||
{
|
||||
$this->operationDefs = [];
|
||||
$this->fragmentDefs = [];
|
||||
|
@ -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 = [];
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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 => [
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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) {
|
||||
|
@ -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 = [];
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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 = [];
|
||||
|
||||
|
@ -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 = [];
|
||||
|
@ -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 = [];
|
||||
|
||||
|
@ -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 = [];
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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 => [
|
||||
|
@ -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!"));
|
||||
}
|
||||
})
|
||||
];
|
||||
}
|
||||
});
|
||||
|
@ -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(),
|
||||
|
@ -1,6 +1,9 @@
|
||||
<?php
|
||||
namespace GraphQL\Tests\Validator;
|
||||
|
||||
use GraphQL\Validator\DocumentValidator;
|
||||
use GraphQL\Validator\Rules\QueryComplexity;
|
||||
|
||||
class ValidationTest extends TestCase
|
||||
{
|
||||
// Validate: Supports full validation
|
||||
@ -23,7 +26,16 @@ class ValidationTest extends TestCase
|
||||
}
|
||||
');
|
||||
}
|
||||
/*
|
||||
public function testAllowsSettingRulesGlobally()
|
||||
{
|
||||
$rule = new QueryComplexity(0);
|
||||
|
||||
DocumentValidator::addRule($rule);
|
||||
$instance = DocumentValidator::getRule(QueryComplexity::class);
|
||||
$this->assertSame($rule, $instance);
|
||||
}
|
||||
*/
|
||||
public function testPassesValidationWithEmptyRules()
|
||||
{
|
||||
$query = '{invalid}';
|
||||
|
Loading…
Reference in New Issue
Block a user