@@ -45,126 +45,96 @@ public function __construct(ValidationRulesRegistrar $register)
45
45
public function rules (...$ rules ): self
46
46
{
47
47
foreach ($ rules as $ rule ) {
48
- if ($ rule instanceof Closure) {
49
- $ this ->validateClosureRule ($ rule );
50
- $ this ->rules [] = $ rule ;
51
- } elseif ($ rule instanceof ValidationRule) {
52
- $ this ->rules [] = $ rule ;
53
- } elseif (is_string ($ rule )) {
54
- $ this ->rules [] = $ this ->getRuleFromString ($ rule );
55
- } else {
56
- Config::throwInvalidArgumentException (
57
- sprintf (
58
- 'Validation rule must be a string, instance of %s, or a closure ' ,
59
- ValidationRule::class
60
- )
61
- );
62
- }
48
+ $ this ->rules [] = $ this ->sanitizeRule ($ rule );
63
49
}
64
50
65
51
return $ this ;
66
52
}
67
53
68
54
/**
69
- * Validates that a closure rule has the proper parameters to be used as a validation rule .
55
+ * Prepends a given rule to the start of the rules array .
70
56
*
71
- * @since 1.0 .0
57
+ * @since 1.3 .0
72
58
*
73
- * @return void
59
+ * @param string|ValidationRule|Closure $rule
74
60
*/
75
- private function validateClosureRule ( Closure $ closure )
61
+ public function prependRule ( $ rule ): self
76
62
{
77
- try {
78
- $ reflection = new ReflectionFunction ($ closure );
79
- } catch (ReflectionException $ e ) {
80
- Config::throwInvalidArgumentException (
81
- 'Unable to validate closure parameters. Please ensure that the closure is valid. '
82
- );
83
- }
63
+ array_unshift ($ this ->rules , $ this ->sanitizeRule ($ rule ));
84
64
85
- $ parameters = $ reflection -> getParameters () ;
86
- $ parameterCount = count ( $ parameters );
65
+ return $ this ;
66
+ }
87
67
88
- if ($ parameterCount < 2 || $ parameterCount > 4 ) {
89
- Config::throwInvalidArgumentException (
90
- "Validation rule closure must accept between 2 and 4 parameters, $ parameterCount given. "
91
- );
92
- }
68
+ /**
69
+ * Replaces the given rule at the same index position or appends it if it doesn't exist.
70
+ *
71
+ * @since 1.3.0
72
+ *
73
+ * @param string|ValidationRule|Closure $rule
74
+ *
75
+ * @return bool True if the rule was replaced, false if it was appended.
76
+ */
77
+ public function replaceOrAppendRule (string $ ruleId , $ rule ): bool
78
+ {
79
+ $ replaced = $ this ->replaceRule ($ ruleId , $ rule );
93
80
94
- $ parameterType = $ this ->getParameterTypeName ($ parameters [1 ]);
95
- if ($ parameterType !== null && $ parameterType !== 'Closure ' ) {
96
- Config::throwInvalidArgumentException (
97
- "Validation rule closure must accept a Closure as the second parameter, {$ parameterType } given. "
98
- );
99
- }
81
+ if (!$ replaced ) {
82
+ $ this ->rules ($ rule );
100
83
101
- $ parameterType = $ parameterCount > 2 ? $ this ->getParameterTypeName ($ parameters [2 ]) : null ;
102
- if ($ parameterType !== null && $ parameterType !== 'string ' ) {
103
- Config::throwInvalidArgumentException (
104
- "Validation rule closure must accept a string as the third parameter, {$ parameterType } given. "
105
- );
84
+ return false ;
106
85
}
107
86
108
- $ parameterType = $ parameterCount > 3 ? $ this ->getParameterTypeName ($ parameters [3 ]) : null ;
109
- if ($ parameterType !== null && $ parameterType !== 'array ' ) {
110
- Config::throwInvalidArgumentException (
111
- "Validation rule closure must accept a array as the fourth parameter, {$ parameterType } given. "
112
- );
113
- }
87
+ return true ;
114
88
}
115
89
116
90
/**
117
- * Retrieves the parameter type with PHP 7.0 compatibility .
91
+ * Replaces the given rule at the same index position or prepends it if it doesn't exist .
118
92
*
119
- * @since 1.0 .0
93
+ * @since 1.3 .0
120
94
*
121
- * @return string|null
95
+ * @param string|ValidationRule|Closure $rule
96
+ *
97
+ * @return bool True if the rule was replaced, false if it was prepended.
122
98
*/
123
- private function getParameterTypeName ( ReflectionParameter $ parameter )
99
+ public function replaceOrPrependRule ( string $ ruleId , $ rule ): bool
124
100
{
125
- $ type = $ parameter -> getType ( );
101
+ $ replaced = $ this -> replaceRule ( $ ruleId , $ rule );
126
102
127
- if ($ type === null ) {
128
- return null ;
129
- }
103
+ if (!$ replaced ) {
104
+ $ this ->prependRule ($ rule );
130
105
131
- // Check if the method exists for PHP 7.0 compatibility (it exits as of PHP 7.1)
132
- if (method_exists ($ type , 'getName ' )) {
133
- return $ type ->getName ();
106
+ return false ;
134
107
}
135
108
136
- return ( string ) $ type ;
109
+ return true ;
137
110
}
138
111
139
112
/**
140
- * Takes a validation rule string and returns the corresponding rule instance.
113
+ * Replace a rule with the given id with the given rule at the same index position. Returns true if the rule was
114
+ * replaced, false otherwise.
141
115
*
142
- * @since 1.0.0
116
+ * @since 1.3.0
117
+ *
118
+ * @param string|ValidationRule|Closure $rule
143
119
*/
144
- private function getRuleFromString (string $ rule ): ValidationRule
120
+ public function replaceRule (string $ ruleId , $ rule ): bool
145
121
{
146
- list ($ ruleId , $ ruleOptions ) = array_pad (explode (': ' , $ rule , 2 ), 2 , null );
147
-
148
- /**
149
- * @var ValidationRule $ruleClass
150
- */
151
- $ ruleClass = $ this ->register ->getRule ($ ruleId );
122
+ foreach ($ this ->rules as $ index => $ validationRule ) {
123
+ if ($ validationRule instanceof ValidationRule && $ validationRule ::id () === $ ruleId ) {
124
+ $ this ->rules [$ index ] = $ this ->sanitizeRule ($ rule );
152
125
153
- if (!$ ruleClass ) {
154
- Config::throwInvalidArgumentException (
155
- sprintf (
156
- 'Validation rule with id %s has not been registered. ' ,
157
- $ ruleId
158
- )
159
- );
126
+ return true ;
127
+ }
160
128
}
161
129
162
- return $ ruleClass :: fromString ( $ ruleOptions ) ;
130
+ return false ;
163
131
}
164
132
165
133
/**
166
134
* Finds and returns the validation rule by id. Does not work for Closure rules.
167
135
*
136
+ * @since 1.0.0
137
+ *
168
138
* @return ValidationRule|null
169
139
*/
170
140
public function getRule (string $ rule )
@@ -268,4 +238,130 @@ public function jsonSerialize()
268
238
269
239
return $ rules ;
270
240
}
241
+
242
+ /**
243
+ * Sanitizes a given rule by validating the rule and making sure it's safe to use.
244
+ *
245
+ * @since 1.3.0
246
+ *
247
+ * @param mixed $rule
248
+ *
249
+ * @return Closure|ValidationRule
250
+ */
251
+ private function sanitizeRule ($ rule )
252
+ {
253
+ if ($ rule instanceof Closure) {
254
+ $ this ->validateClosureRule ($ rule );
255
+
256
+ return $ rule ;
257
+ } elseif ($ rule instanceof ValidationRule) {
258
+ return $ rule ;
259
+ } elseif (is_string ($ rule )) {
260
+ return $ this ->getRuleFromString ($ rule );
261
+ } else {
262
+ Config::throwInvalidArgumentException (
263
+ sprintf (
264
+ 'Validation rule must be a string, instance of %s, or a closure ' ,
265
+ ValidationRule::class
266
+ )
267
+ );
268
+ }
269
+ }
270
+
271
+ /**
272
+ * Validates that a closure rule has the proper parameters to be used as a validation rule.
273
+ *
274
+ * @since 1.0.0
275
+ *
276
+ * @return void
277
+ */
278
+ private function validateClosureRule (Closure $ closure )
279
+ {
280
+ try {
281
+ $ reflection = new ReflectionFunction ($ closure );
282
+ } catch (ReflectionException $ e ) {
283
+ Config::throwInvalidArgumentException (
284
+ 'Unable to validate closure parameters. Please ensure that the closure is valid. '
285
+ );
286
+ }
287
+
288
+ $ parameters = $ reflection ->getParameters ();
289
+ $ parameterCount = count ($ parameters );
290
+
291
+ if ($ parameterCount < 2 || $ parameterCount > 4 ) {
292
+ Config::throwInvalidArgumentException (
293
+ "Validation rule closure must accept between 2 and 4 parameters, $ parameterCount given. "
294
+ );
295
+ }
296
+
297
+ $ parameterType = $ this ->getParameterTypeName ($ parameters [1 ]);
298
+ if ($ parameterType !== null && $ parameterType !== 'Closure ' ) {
299
+ Config::throwInvalidArgumentException (
300
+ "Validation rule closure must accept a Closure as the second parameter, {$ parameterType } given. "
301
+ );
302
+ }
303
+
304
+ $ parameterType = $ parameterCount > 2 ? $ this ->getParameterTypeName ($ parameters [2 ]) : null ;
305
+ if ($ parameterType !== null && $ parameterType !== 'string ' ) {
306
+ Config::throwInvalidArgumentException (
307
+ "Validation rule closure must accept a string as the third parameter, {$ parameterType } given. "
308
+ );
309
+ }
310
+
311
+ $ parameterType = $ parameterCount > 3 ? $ this ->getParameterTypeName ($ parameters [3 ]) : null ;
312
+ if ($ parameterType !== null && $ parameterType !== 'array ' ) {
313
+ Config::throwInvalidArgumentException (
314
+ "Validation rule closure must accept a array as the fourth parameter, {$ parameterType } given. "
315
+ );
316
+ }
317
+ }
318
+
319
+ /**
320
+ * Retrieves the parameter type with PHP 7.0 compatibility.
321
+ *
322
+ * @since 1.0.0
323
+ *
324
+ * @return string|null
325
+ */
326
+ private function getParameterTypeName (ReflectionParameter $ parameter )
327
+ {
328
+ $ type = $ parameter ->getType ();
329
+
330
+ if ($ type === null ) {
331
+ return null ;
332
+ }
333
+
334
+ // Check if the method exists for PHP 7.0 compatibility (it exits as of PHP 7.1)
335
+ if (method_exists ($ type , 'getName ' )) {
336
+ return $ type ->getName ();
337
+ }
338
+
339
+ return (string )$ type ;
340
+ }
341
+
342
+ /**
343
+ * Takes a validation rule string and returns the corresponding rule instance.
344
+ *
345
+ * @since 1.0.0
346
+ */
347
+ private function getRuleFromString (string $ rule ): ValidationRule
348
+ {
349
+ [$ ruleId , $ ruleOptions ] = array_pad (explode (': ' , $ rule , 2 ), 2 , null );
350
+
351
+ /**
352
+ * @var ValidationRule $ruleClass
353
+ */
354
+ $ ruleClass = $ this ->register ->getRule ($ ruleId );
355
+
356
+ if (!$ ruleClass ) {
357
+ Config::throwInvalidArgumentException (
358
+ sprintf (
359
+ 'Validation rule with id %s has not been registered. ' ,
360
+ $ ruleId
361
+ )
362
+ );
363
+ }
364
+
365
+ return $ ruleClass ::fromString ($ ruleOptions );
366
+ }
271
367
}
0 commit comments