3434use GraphQL \Validator \Rules \OverlappingFieldsCanBeMerged ;
3535use GraphQL \Validator \Rules \PossibleFragmentSpreads ;
3636use GraphQL \Validator \Rules \ProvidedNonNullArguments ;
37+ use GraphQL \Validator \Rules \QueryComplexity ;
38+ use GraphQL \Validator \Rules \QueryDepth ;
3739use GraphQL \Validator \Rules \ScalarLeafs ;
3840use GraphQL \Validator \Rules \VariablesAreInputTypes ;
3941use GraphQL \Validator \Rules \VariablesInAllowedPosition ;
4042
4143class DocumentValidator
4244{
43- private static $ allRules ;
45+ private static $ rules = [] ;
4446
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 ()
4662 {
47- if (null === self ::$ allRules ) {
48- self ::$ allRules = [
63+ if (null === self ::$ defaultRules ) {
64+ self ::$ defaultRules = [
4965 // new UniqueOperationNames,
5066 // 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 () ,
5672 // 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 () ,
6581 // 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
7190 ];
7291 }
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 ;
74106 }
75107
76108 public static function validate (Schema $ schema , Document $ ast , array $ rules = null )
77109 {
78- $ errors = self ::visitUsingRules ($ schema , $ ast , $ rules ?: self ::allRules ());
110+ $ errors = static ::visitUsingRules ($ schema , $ ast , $ rules ?: static ::allRules ());
79111 return $ errors ;
80112 }
81113
82- static function isError ($ value )
114+ public static function isError ($ value )
83115 {
84116 return is_array ($ value )
85117 ? count (array_filter ($ value , function ($ item ) { return $ item instanceof \Exception;})) === count ($ value )
86118 : $ value instanceof \Exception;
87119 }
88120
89- static function append (&$ arr , $ items )
121+ public static function append (&$ arr , $ items )
90122 {
91123 if (is_array ($ items )) {
92124 $ arr = array_merge ($ arr , $ items );
@@ -96,7 +128,7 @@ static function append(&$arr, $items)
96128 return $ arr ;
97129 }
98130
99- static function isValidLiteralValue ($ valueAST , Type $ type )
131+ public static function isValidLiteralValue ($ valueAST , Type $ type )
100132 {
101133 // A value can only be not provided if the type is nullable.
102134 if (!$ valueAST ) {
@@ -105,7 +137,7 @@ static function isValidLiteralValue($valueAST, Type $type)
105137
106138 // Unwrap non-null.
107139 if ($ type instanceof NonNull) {
108- return self ::isValidLiteralValue ($ valueAST , $ type ->getWrappedType ());
140+ return static ::isValidLiteralValue ($ valueAST , $ type ->getWrappedType ());
109141 }
110142
111143 // This function only tests literals, and assumes variables will provide
@@ -123,13 +155,13 @@ static function isValidLiteralValue($valueAST, Type $type)
123155 $ itemType = $ type ->getWrappedType ();
124156 if ($ valueAST instanceof ListValue) {
125157 foreach ($ valueAST ->values as $ itemAST ) {
126- if (!self ::isValidLiteralValue ($ itemAST , $ itemType )) {
158+ if (!static ::isValidLiteralValue ($ itemAST , $ itemType )) {
127159 return false ;
128160 }
129161 }
130162 return true ;
131163 } else {
132- return self ::isValidLiteralValue ($ valueAST , $ itemType );
164+ return static ::isValidLiteralValue ($ valueAST , $ itemType );
133165 }
134166 }
135167
@@ -157,7 +189,7 @@ static function isValidLiteralValue($valueAST, Type $type)
157189 }
158190 }
159191 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 ())) {
161193 return false ;
162194 }
163195 }
@@ -231,8 +263,8 @@ public static function visitUsingRules(Schema $schema, Document $documentAST, ar
231263 } else if ($ result ->doBreak ) {
232264 $ instances [$ i ] = null ;
233265 }
234- } else if ($ result && self ::isError ($ result )) {
235- self ::append ($ errors , $ result );
266+ } else if ($ result && static ::isError ($ result )) {
267+ static ::append ($ errors , $ result );
236268 for ($ j = $ i - 1 ; $ j >= 0 ; $ j --) {
237269 $ leaveFn = Visitor::getVisitFn ($ instances [$ j ], true , $ node ->kind );
238270 if ($ leaveFn ) {
@@ -243,8 +275,8 @@ public static function visitUsingRules(Schema $schema, Document $documentAST, ar
243275 if ($ result ->doBreak ) {
244276 $ instances [$ j ] = null ;
245277 }
246- } else if (self ::isError ($ result )) {
247- self ::append ($ errors , $ result );
278+ } else if (static ::isError ($ result )) {
279+ static ::append ($ errors , $ result );
248280 } else if ($ result !== null ) {
249281 throw new \Exception ("Config cannot edit document. " );
250282 }
@@ -294,8 +326,8 @@ public static function visitUsingRules(Schema $schema, Document $documentAST, ar
294326 if ($ result ->doBreak ) {
295327 $ instances [$ i ] = null ;
296328 }
297- } else if (self ::isError ($ result )) {
298- self ::append ($ errors , $ result );
329+ } else if (static ::isError ($ result )) {
330+ static ::append ($ errors , $ result );
299331 } else if ($ result !== null ) {
300332 throw new \Exception ("Config cannot edit document. " );
301333 }
@@ -309,7 +341,7 @@ public static function visitUsingRules(Schema $schema, Document $documentAST, ar
309341 // Visit the whole document with instances of all provided rules.
310342 $ allRuleInstances = [];
311343 foreach ($ rules as $ rule ) {
312- $ allRuleInstances [] = $ rule( $ context );
344+ $ allRuleInstances [] = call_user_func_array ( $ rule, [ $ context] );
313345 }
314346 $ visitInstances ($ documentAST , $ allRuleInstances );
315347
0 commit comments