34
34
use GraphQL \Validator \Rules \OverlappingFieldsCanBeMerged ;
35
35
use GraphQL \Validator \Rules \PossibleFragmentSpreads ;
36
36
use GraphQL \Validator \Rules \ProvidedNonNullArguments ;
37
+ use GraphQL \Validator \Rules \QueryComplexity ;
38
+ use GraphQL \Validator \Rules \QueryDepth ;
37
39
use GraphQL \Validator \Rules \ScalarLeafs ;
38
40
use GraphQL \Validator \Rules \VariablesAreInputTypes ;
39
41
use GraphQL \Validator \Rules \VariablesInAllowedPosition ;
40
42
41
43
class DocumentValidator
42
44
{
43
- private static $ allRules ;
45
+ private static $ rules = [] ;
44
46
45
- static function allRules ()
47
+ private static $ defaultRules ;
48
+
49
+ private static $ initRules = false ;
50
+
51
+ public static function allRules ()
52
+ {
53
+ if (!self ::$ initRules ) {
54
+ self ::$ rules = array_merge (static ::defaultRules (), self ::$ rules );
55
+ self ::$ initRules = true ;
56
+ }
57
+
58
+ return self ::$ rules ;
59
+ }
60
+
61
+ public static function defaultRules ()
46
62
{
47
- if (null === self ::$ allRules ) {
48
- self ::$ allRules = [
63
+ if (null === self ::$ defaultRules ) {
64
+ self ::$ defaultRules = [
49
65
// new UniqueOperationNames,
50
66
// new LoneAnonymousOperation,
51
- new KnownTypeNames ,
52
- new FragmentsOnCompositeTypes ,
53
- new VariablesAreInputTypes ,
54
- new ScalarLeafs ,
55
- new FieldsOnCorrectType ,
67
+ ' KnownTypeNames ' => new KnownTypeNames () ,
68
+ ' FragmentsOnCompositeTypes ' => new FragmentsOnCompositeTypes () ,
69
+ ' VariablesAreInputTypes ' => new VariablesAreInputTypes () ,
70
+ ' ScalarLeafs ' => new ScalarLeafs () ,
71
+ ' FieldsOnCorrectType ' => new FieldsOnCorrectType () ,
56
72
// new UniqueFragmentNames,
57
- new KnownFragmentNames ,
58
- new NoUnusedFragments ,
59
- new PossibleFragmentSpreads ,
60
- new NoFragmentCycles ,
61
- new NoUndefinedVariables ,
62
- new NoUnusedVariables ,
63
- new KnownDirectives ,
64
- new KnownArgumentNames ,
73
+ ' KnownFragmentNames ' => new KnownFragmentNames () ,
74
+ ' NoUnusedFragments ' => new NoUnusedFragments () ,
75
+ ' PossibleFragmentSpreads ' => new PossibleFragmentSpreads () ,
76
+ ' NoFragmentCycles ' => new NoFragmentCycles () ,
77
+ ' NoUndefinedVariables ' => new NoUndefinedVariables () ,
78
+ ' NoUnusedVariables ' => new NoUnusedVariables () ,
79
+ ' KnownDirectives ' => new KnownDirectives () ,
80
+ ' KnownArgumentNames ' => new KnownArgumentNames () ,
65
81
// new UniqueArgumentNames,
66
- new ArgumentsOfCorrectType ,
67
- new ProvidedNonNullArguments ,
68
- new DefaultValuesOfCorrectType ,
69
- new VariablesInAllowedPosition ,
70
- new OverlappingFieldsCanBeMerged ,
82
+ 'ArgumentsOfCorrectType ' => new ArgumentsOfCorrectType (),
83
+ 'ProvidedNonNullArguments ' => new ProvidedNonNullArguments (),
84
+ 'DefaultValuesOfCorrectType ' => new DefaultValuesOfCorrectType (),
85
+ 'VariablesInAllowedPosition ' => new VariablesInAllowedPosition (),
86
+ 'OverlappingFieldsCanBeMerged ' => new OverlappingFieldsCanBeMerged (),
87
+ // Query Security
88
+ 'QueryDepth ' => new QueryDepth (QueryDepth::DISABLED ), // default disabled
89
+ 'QueryComplexity ' => new QueryComplexity (QueryComplexity::DISABLED ), // default disabled
71
90
];
72
91
}
73
- return self ::$ allRules ;
92
+
93
+ return self ::$ defaultRules ;
94
+ }
95
+
96
+ public static function getRule ($ name )
97
+ {
98
+ $ rules = static ::allRules ();
99
+
100
+ return isset ($ rules [$ name ]) ? $ rules [$ name ] : null ;
101
+ }
102
+
103
+ public static function addRule ($ name , callable $ rule )
104
+ {
105
+ self ::$ rules [$ name ] = $ rule ;
74
106
}
75
107
76
108
public static function validate (Schema $ schema , Document $ ast , array $ rules = null )
77
109
{
78
- $ errors = self ::visitUsingRules ($ schema , $ ast , $ rules ?: self ::allRules ());
110
+ $ errors = static ::visitUsingRules ($ schema , $ ast , $ rules ?: static ::allRules ());
79
111
return $ errors ;
80
112
}
81
113
82
- static function isError ($ value )
114
+ public static function isError ($ value )
83
115
{
84
116
return is_array ($ value )
85
117
? count (array_filter ($ value , function ($ item ) { return $ item instanceof \Exception;})) === count ($ value )
86
118
: $ value instanceof \Exception;
87
119
}
88
120
89
- static function append (&$ arr , $ items )
121
+ public static function append (&$ arr , $ items )
90
122
{
91
123
if (is_array ($ items )) {
92
124
$ arr = array_merge ($ arr , $ items );
@@ -96,7 +128,7 @@ static function append(&$arr, $items)
96
128
return $ arr ;
97
129
}
98
130
99
- static function isValidLiteralValue ($ valueAST , Type $ type )
131
+ public static function isValidLiteralValue ($ valueAST , Type $ type )
100
132
{
101
133
// A value can only be not provided if the type is nullable.
102
134
if (!$ valueAST ) {
@@ -105,7 +137,7 @@ static function isValidLiteralValue($valueAST, Type $type)
105
137
106
138
// Unwrap non-null.
107
139
if ($ type instanceof NonNull) {
108
- return self ::isValidLiteralValue ($ valueAST , $ type ->getWrappedType ());
140
+ return static ::isValidLiteralValue ($ valueAST , $ type ->getWrappedType ());
109
141
}
110
142
111
143
// This function only tests literals, and assumes variables will provide
@@ -123,13 +155,13 @@ static function isValidLiteralValue($valueAST, Type $type)
123
155
$ itemType = $ type ->getWrappedType ();
124
156
if ($ valueAST instanceof ListValue) {
125
157
foreach ($ valueAST ->values as $ itemAST ) {
126
- if (!self ::isValidLiteralValue ($ itemAST , $ itemType )) {
158
+ if (!static ::isValidLiteralValue ($ itemAST , $ itemType )) {
127
159
return false ;
128
160
}
129
161
}
130
162
return true ;
131
163
} else {
132
- return self ::isValidLiteralValue ($ valueAST , $ itemType );
164
+ return static ::isValidLiteralValue ($ valueAST , $ itemType );
133
165
}
134
166
}
135
167
@@ -157,7 +189,7 @@ static function isValidLiteralValue($valueAST, Type $type)
157
189
}
158
190
}
159
191
foreach ($ fieldASTs as $ fieldAST ) {
160
- if (empty ($ fields [$ fieldAST ->name ->value ]) || !self ::isValidLiteralValue ($ fieldAST ->value , $ fields [$ fieldAST ->name ->value ]->getType ())) {
192
+ if (empty ($ fields [$ fieldAST ->name ->value ]) || !static ::isValidLiteralValue ($ fieldAST ->value , $ fields [$ fieldAST ->name ->value ]->getType ())) {
161
193
return false ;
162
194
}
163
195
}
@@ -231,8 +263,8 @@ public static function visitUsingRules(Schema $schema, Document $documentAST, ar
231
263
} else if ($ result ->doBreak ) {
232
264
$ instances [$ i ] = null ;
233
265
}
234
- } else if ($ result && self ::isError ($ result )) {
235
- self ::append ($ errors , $ result );
266
+ } else if ($ result && static ::isError ($ result )) {
267
+ static ::append ($ errors , $ result );
236
268
for ($ j = $ i - 1 ; $ j >= 0 ; $ j --) {
237
269
$ leaveFn = Visitor::getVisitFn ($ instances [$ j ], true , $ node ->kind );
238
270
if ($ leaveFn ) {
@@ -243,8 +275,8 @@ public static function visitUsingRules(Schema $schema, Document $documentAST, ar
243
275
if ($ result ->doBreak ) {
244
276
$ instances [$ j ] = null ;
245
277
}
246
- } else if (self ::isError ($ result )) {
247
- self ::append ($ errors , $ result );
278
+ } else if (static ::isError ($ result )) {
279
+ static ::append ($ errors , $ result );
248
280
} else if ($ result !== null ) {
249
281
throw new \Exception ("Config cannot edit document. " );
250
282
}
@@ -294,8 +326,8 @@ public static function visitUsingRules(Schema $schema, Document $documentAST, ar
294
326
if ($ result ->doBreak ) {
295
327
$ instances [$ i ] = null ;
296
328
}
297
- } else if (self ::isError ($ result )) {
298
- self ::append ($ errors , $ result );
329
+ } else if (static ::isError ($ result )) {
330
+ static ::append ($ errors , $ result );
299
331
} else if ($ result !== null ) {
300
332
throw new \Exception ("Config cannot edit document. " );
301
333
}
@@ -309,7 +341,7 @@ public static function visitUsingRules(Schema $schema, Document $documentAST, ar
309
341
// Visit the whole document with instances of all provided rules.
310
342
$ allRuleInstances = [];
311
343
foreach ($ rules as $ rule ) {
312
- $ allRuleInstances [] = $ rule( $ context );
344
+ $ allRuleInstances [] = call_user_func_array ( $ rule, [ $ context] );
313
345
}
314
346
$ visitInstances ($ documentAST , $ allRuleInstances );
315
347
0 commit comments