4040
4141class DocumentValidator
4242{
43- private static $ allRules ;
43+ private static $ rules = [] ;
4444
45- static function allRules ()
45+ private static $ defaultRules ;
46+
47+ private static $ initRules = false ;
48+
49+ public static function allRules ()
4650 {
47- if (null === self ::$ allRules ) {
48- self ::$ allRules = [
51+ if (!self ::$ initRules ) {
52+ self ::$ rules = array_merge (static ::defaultRules (), self ::$ rules );
53+ self ::$ initRules = true ;
54+ }
55+
56+ return self ::$ rules ;
57+ }
58+
59+ public static function defaultRules ()
60+ {
61+ if (null === self ::$ defaultRules ) {
62+ self ::$ defaultRules = [
4963 // new UniqueOperationNames,
5064 // new LoneAnonymousOperation,
51- new KnownTypeNames ,
52- new FragmentsOnCompositeTypes ,
53- new VariablesAreInputTypes ,
54- new ScalarLeafs ,
55- new FieldsOnCorrectType ,
65+ ' KnownTypeNames ' => new KnownTypeNames () ,
66+ ' FragmentsOnCompositeTypes ' => new FragmentsOnCompositeTypes () ,
67+ ' VariablesAreInputTypes ' => new VariablesAreInputTypes () ,
68+ ' ScalarLeafs ' => new ScalarLeafs () ,
69+ ' FieldsOnCorrectType ' => new FieldsOnCorrectType () ,
5670 // 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 ,
71+ ' KnownFragmentNames ' => new KnownFragmentNames () ,
72+ ' NoUnusedFragments ' => new NoUnusedFragments () ,
73+ ' PossibleFragmentSpreads ' => new PossibleFragmentSpreads () ,
74+ ' NoFragmentCycles ' => new NoFragmentCycles () ,
75+ ' NoUndefinedVariables ' => new NoUndefinedVariables () ,
76+ ' NoUnusedVariables ' => new NoUnusedVariables () ,
77+ ' KnownDirectives ' => new KnownDirectives () ,
78+ ' KnownArgumentNames ' => new KnownArgumentNames () ,
6579 // new UniqueArgumentNames,
66- new ArgumentsOfCorrectType ,
67- new ProvidedNonNullArguments ,
68- new DefaultValuesOfCorrectType ,
69- new VariablesInAllowedPosition ,
70- new OverlappingFieldsCanBeMerged ,
80+ ' ArgumentsOfCorrectType ' => new ArgumentsOfCorrectType () ,
81+ ' ProvidedNonNullArguments ' => new ProvidedNonNullArguments () ,
82+ ' DefaultValuesOfCorrectType ' => new DefaultValuesOfCorrectType () ,
83+ ' VariablesInAllowedPosition ' => new VariablesInAllowedPosition () ,
84+ ' OverlappingFieldsCanBeMerged ' => new OverlappingFieldsCanBeMerged () ,
7185 ];
7286 }
73- return self ::$ allRules ;
87+
88+ return self ::$ defaultRules ;
89+ }
90+
91+ public static function getRule ($ name )
92+ {
93+ return isset (self ::$ rules [$ name ]) ? self ::$ rules [$ name ] : null ;
94+ }
95+
96+ public static function addRule ($ name , callable $ rule )
97+ {
98+ self ::$ rules [$ name ] = $ rule ;
99+ }
100+
101+ public static function removeRule ($ name )
102+ {
103+ unset(self ::$ rules [$ name ]);
74104 }
75105
76106 public static function validate (Schema $ schema , Document $ ast , array $ rules = null )
77107 {
78- $ errors = self ::visitUsingRules ($ schema , $ ast , $ rules ?: self ::allRules ());
108+ $ errors = static ::visitUsingRules ($ schema , $ ast , $ rules ?: static ::allRules ());
79109 return $ errors ;
80110 }
81111
82- static function isError ($ value )
112+ public static function isError ($ value )
83113 {
84114 return is_array ($ value )
85115 ? count (array_filter ($ value , function ($ item ) { return $ item instanceof \Exception;})) === count ($ value )
86116 : $ value instanceof \Exception;
87117 }
88118
89- static function append (&$ arr , $ items )
119+ public static function append (&$ arr , $ items )
90120 {
91121 if (is_array ($ items )) {
92122 $ arr = array_merge ($ arr , $ items );
@@ -96,7 +126,7 @@ static function append(&$arr, $items)
96126 return $ arr ;
97127 }
98128
99- static function isValidLiteralValue ($ valueAST , Type $ type )
129+ public static function isValidLiteralValue ($ valueAST , Type $ type )
100130 {
101131 // A value can only be not provided if the type is nullable.
102132 if (!$ valueAST ) {
@@ -105,7 +135,7 @@ static function isValidLiteralValue($valueAST, Type $type)
105135
106136 // Unwrap non-null.
107137 if ($ type instanceof NonNull) {
108- return self ::isValidLiteralValue ($ valueAST , $ type ->getWrappedType ());
138+ return static ::isValidLiteralValue ($ valueAST , $ type ->getWrappedType ());
109139 }
110140
111141 // This function only tests literals, and assumes variables will provide
@@ -123,13 +153,13 @@ static function isValidLiteralValue($valueAST, Type $type)
123153 $ itemType = $ type ->getWrappedType ();
124154 if ($ valueAST instanceof ListValue) {
125155 foreach ($ valueAST ->values as $ itemAST ) {
126- if (!self ::isValidLiteralValue ($ itemAST , $ itemType )) {
156+ if (!static ::isValidLiteralValue ($ itemAST , $ itemType )) {
127157 return false ;
128158 }
129159 }
130160 return true ;
131161 } else {
132- return self ::isValidLiteralValue ($ valueAST , $ itemType );
162+ return static ::isValidLiteralValue ($ valueAST , $ itemType );
133163 }
134164 }
135165
@@ -157,7 +187,7 @@ static function isValidLiteralValue($valueAST, Type $type)
157187 }
158188 }
159189 foreach ($ fieldASTs as $ fieldAST ) {
160- if (empty ($ fields [$ fieldAST ->name ->value ]) || !self ::isValidLiteralValue ($ fieldAST ->value , $ fields [$ fieldAST ->name ->value ]->getType ())) {
190+ if (empty ($ fields [$ fieldAST ->name ->value ]) || !static ::isValidLiteralValue ($ fieldAST ->value , $ fields [$ fieldAST ->name ->value ]->getType ())) {
161191 return false ;
162192 }
163193 }
@@ -231,8 +261,8 @@ public static function visitUsingRules(Schema $schema, Document $documentAST, ar
231261 } else if ($ result ->doBreak ) {
232262 $ instances [$ i ] = null ;
233263 }
234- } else if ($ result && self ::isError ($ result )) {
235- self ::append ($ errors , $ result );
264+ } else if ($ result && static ::isError ($ result )) {
265+ static ::append ($ errors , $ result );
236266 for ($ j = $ i - 1 ; $ j >= 0 ; $ j --) {
237267 $ leaveFn = Visitor::getVisitFn ($ instances [$ j ], true , $ node ->kind );
238268 if ($ leaveFn ) {
@@ -243,8 +273,8 @@ public static function visitUsingRules(Schema $schema, Document $documentAST, ar
243273 if ($ result ->doBreak ) {
244274 $ instances [$ j ] = null ;
245275 }
246- } else if (self ::isError ($ result )) {
247- self ::append ($ errors , $ result );
276+ } else if (static ::isError ($ result )) {
277+ static ::append ($ errors , $ result );
248278 } else if ($ result !== null ) {
249279 throw new \Exception ("Config cannot edit document. " );
250280 }
@@ -294,8 +324,8 @@ public static function visitUsingRules(Schema $schema, Document $documentAST, ar
294324 if ($ result ->doBreak ) {
295325 $ instances [$ i ] = null ;
296326 }
297- } else if (self ::isError ($ result )) {
298- self ::append ($ errors , $ result );
327+ } else if (static ::isError ($ result )) {
328+ static ::append ($ errors , $ result );
299329 } else if ($ result !== null ) {
300330 throw new \Exception ("Config cannot edit document. " );
301331 }
@@ -309,7 +339,7 @@ public static function visitUsingRules(Schema $schema, Document $documentAST, ar
309339 // Visit the whole document with instances of all provided rules.
310340 $ allRuleInstances = [];
311341 foreach ($ rules as $ rule ) {
312- $ allRuleInstances [] = $ rule( $ context );
342+ $ allRuleInstances [] = call_user_func_array ( $ rule, [ $ context] );
313343 }
314344 $ visitInstances ($ documentAST , $ allRuleInstances );
315345
0 commit comments