88 * @since 0.2.0
99 *
1010 * @method static bool is(string $type, mixed $value, array $rule = []) Checks if value passes as type
11+ * @method static bool isAny(mixed $value, array $rule = []) Always returns true
1112 * @method static bool isNull(mixed $value, array $rule = []) Checks if value is null
1213 * @method static bool isBool(mixed $value, array $rule = []) Checks if value is boolean
1314 * @method static bool isBoolean(mixed $value, array $rule = []) Checks if value is boolean
@@ -41,24 +42,26 @@ class Validator
4142 /**
4243 * @var Collection
4344 */
44- private $ values ;
45+ protected $ values ;
4546
4647 /**
4748 * @var Collection
4849 */
49- private $ rules ;
50+ protected $ rules ;
5051
5152 /**
5253 * @var Collection
5354 */
54- private $ errors ;
55+ protected $ errors ;
5556
5657 /**
57- * Map of types to validate method names.
58+ * Map built-in types to associated validate method
5859 *
5960 * @var array
6061 */
61- private $ validateTypeMethodMap = [
62+ protected $ typeValidateFunctionMap = [
63+ '* ' => 'validateAny ' ,
64+ 'any ' => 'validateAny ' ,
6265 'null ' => 'validateNull ' ,
6366 'bool ' => 'validateBoolean ' ,
6467 'boolean ' => 'validateBoolean ' ,
@@ -220,26 +223,52 @@ public function rules() : array
220223 */
221224 public function validate () : bool
222225 {
223- if (! empty ( $ this ->rules )) {
226+ if ($ this ->rules -> count ( )) {
224227 foreach ($ this ->rules as $ name => $ rule ) {
225- if (array_key_exists ($ name , $ this ->values ->toArray ())) {
226- if (is_string ($ rule )) {
227- // Rebuild $rule into proper format
228- // e.g. 'email' -> ['type' => 'email']
229- $ rule = ['type ' => $ rule ];
228+ // Convert string/closure rules into proper rule format
229+ if (is_string ($ rule )) {
230+ $ rule = ['type ' => $ rule ];
231+ } elseif ($ rule instanceof \Closure || is_callable ($ rule )) {
232+ // Rule uses closure/callable for validation
233+ $ rule = ['type ' => 'any ' , 'validator ' => $ rule ];
234+ }
235+
236+ // Make sure rule is formatted correctly
237+ if (!is_array ($ rule ) || !isset ($ rule ['type ' ])) {
238+ throw new \InvalidArgumentException ("Rule format for ' $ name' is invalid. " );
239+ }
240+
241+ // Value is required by default
242+ if (!isset ($ rule ['required ' ])) {
243+ $ rule ['required ' ] = true ;
244+ }
245+
246+ // Check if value exists
247+ if ($ value = $ this ->values ->get ($ name , false )) {
248+ // Validate using type validators
249+ if (!$ this ->validateType ($ rule ['type ' ], $ value , $ rule )) {
250+ $ this ->setError ($ name , "' $ value' is not valid {$ rule ['type ' ]} for ' $ name'. " );
251+ continue ;
230252 }
231- if (isset ($ rule ['type ' ])) {
232- if (!$ this ->validateType ($ rule ['type ' ], $ this ->values [$ name ], $ rule )) {
233- // Error: Value for '%s' is invalid
234- $ this ->setError ($ name , "Value for ' $ name' is invalid. Expected {$ rule ['type ' ]}. " );
253+
254+ // Validate using closure/callable validator
255+ if (isset ($ rule ['validator ' ])) {
256+ if ($ rule ['validator ' ] instanceof \Closure) {
257+ if (!$ rule ['validator ' ]($ name , $ value , $ this )) {
258+ $ this ->setError ($ name , "' $ value' is not valid for ' $ name'. " );
259+ continue ;
260+ }
261+ } elseif (is_callable ($ rule ['validator ' ])) {
262+ if (!call_user_func_array ($ rule ['validator ' ], [$ name , $ value , $ this ])) {
263+ $ this ->setError ($ name , "' $ value' is not valid for ' $ name'. " );
264+ continue ;
265+ }
235266 }
236- } else {
237- throw new \InvalidArgumentException ("Invalid rule for ' $ name' " );
238267 }
239268 } else {
240- if (isset ( $ rule [ ' required ' ]) && $ rule ['required ' ]) {
241- // Error: Value for '%s ' is required
242- $ this -> setError ( $ name , " Value for ' $ name ' is required " ) ;
269+ if ($ rule ['required ' ]) {
270+ $ this -> setError ( $ name , " Value for ' $ name ' is required. " );
271+ continue ;
243272 }
244273 }
245274 }
@@ -299,11 +328,22 @@ public function hasErrors() : bool
299328 public function validateType ($ type , $ value , array $ rule = []) : bool
300329 {
301330 $ type = strtolower ($ type );
302- if (isset ($ this ->validateTypeMethodMap [$ type ])) {
303- return $ this ->{$ this ->validateTypeMethodMap [$ type ]}($ value , $ rule );
304- } else {
305- throw new \InvalidArgumentException ("Type ' $ type' is not a valid rule type " );
331+ if (isset ($ this ->typeValidateFunctionMap [$ type ])) {
332+ return $ this ->{$ this ->typeValidateFunctionMap [$ type ]}($ value , $ rule );
306333 }
334+ throw new \InvalidArgumentException ("Type ' $ type' is not a valid rule type " );
335+ }
336+
337+ /**
338+ * No validation is done. Always returns true.
339+ *
340+ * @param $value
341+ * @param array $rule
342+ * @return bool
343+ */
344+ protected function validateAny ($ value , array $ rule = []) : bool
345+ {
346+ return true ;
307347 }
308348
309349 /**
@@ -313,7 +353,7 @@ public function validateType($type, $value, array $rule = []) : bool
313353 * @param array $rule
314354 * @return bool
315355 */
316- private function validateNull ($ value , array $ rule = []) : bool
356+ protected function validateNull ($ value , array $ rule = []) : bool
317357 {
318358 return is_null ($ value );
319359 }
@@ -325,7 +365,7 @@ private function validateNull($value, array $rule = []) : bool
325365 * @param array $rule
326366 * @return bool
327367 */
328- private function validateBoolean ($ value , array $ rule = []) : bool
368+ protected function validateBoolean ($ value , array $ rule = []) : bool
329369 {
330370 return is_bool ($ value );
331371 }
@@ -337,7 +377,7 @@ private function validateBoolean($value, array $rule = []) : bool
337377 * @param array $rule
338378 * @return bool
339379 */
340- private function validateScalar ($ value , array $ rule = []) : bool
380+ protected function validateScalar ($ value , array $ rule = []) : bool
341381 {
342382 return is_scalar ($ value );
343383 }
@@ -349,7 +389,7 @@ private function validateScalar($value, array $rule = []) : bool
349389 * @param array $rule
350390 * @return bool
351391 */
352- private function validateArray ($ value , array $ rule = []) : bool
392+ protected function validateArray ($ value , array $ rule = []) : bool
353393 {
354394 return is_array ($ value );
355395 }
@@ -361,7 +401,7 @@ private function validateArray($value, array $rule = []) : bool
361401 * @param array $rule
362402 * @return bool
363403 */
364- private function validateObject ($ value , array $ rule = []) : bool
404+ protected function validateObject ($ value , array $ rule = []) : bool
365405 {
366406 return is_object ($ value );
367407 }
@@ -373,7 +413,7 @@ private function validateObject($value, array $rule = []) : bool
373413 * @param array $rule
374414 * @return bool
375415 */
376- private function validateString ($ value , array $ rule = []) : bool
416+ protected function validateString ($ value , array $ rule = []) : bool
377417 {
378418 return is_string ($ value );
379419 }
@@ -385,7 +425,7 @@ private function validateString($value, array $rule = []) : bool
385425 * @param array $rule
386426 * @return bool
387427 */
388- private function validateInteger ($ value , array $ rule = []) : bool
428+ protected function validateInteger ($ value , array $ rule = []) : bool
389429 {
390430 return is_int ($ value );
391431 }
@@ -397,7 +437,7 @@ private function validateInteger($value, array $rule = []) : bool
397437 * @param array $rule
398438 * @return bool
399439 */
400- private function validateNumeric ($ value , array $ rule = []) : bool
440+ protected function validateNumeric ($ value , array $ rule = []) : bool
401441 {
402442 return is_numeric ($ value );
403443 }
@@ -409,7 +449,7 @@ private function validateNumeric($value, array $rule = []) : bool
409449 * @param array $rule
410450 * @return bool
411451 */
412- private function validateFloat ($ value , array $ rule = []) : bool
452+ protected function validateFloat ($ value , array $ rule = []) : bool
413453 {
414454 return is_float ($ value );
415455 }
@@ -421,7 +461,7 @@ private function validateFloat($value, array $rule = []) : bool
421461 * @param array $rule
422462 * @return bool
423463 */
424- private function validateAlphaNumeric ($ value , array $ rule = []) : bool
464+ protected function validateAlphaNumeric ($ value , array $ rule = []) : bool
425465 {
426466 return is_string ($ value ) && ctype_alnum ($ value );
427467 }
@@ -433,7 +473,7 @@ private function validateAlphaNumeric($value, array $rule = []) : bool
433473 * @param array $rule
434474 * @return bool
435475 */
436- private function validateAlpha ($ value , array $ rule = []) : bool
476+ protected function validateAlpha ($ value , array $ rule = []) : bool
437477 {
438478 return is_string ($ value ) && ctype_alpha ($ value );
439479 }
@@ -445,7 +485,7 @@ private function validateAlpha($value, array $rule = []) : bool
445485 * @param array $rule
446486 * @return bool
447487 */
448- private function validateEmail ($ value , array $ rule = []) : bool
488+ protected function validateEmail ($ value , array $ rule = []) : bool
449489 {
450490 return (bool ) filter_var ($ value , FILTER_VALIDATE_EMAIL );
451491 }
@@ -457,7 +497,7 @@ private function validateEmail($value, array $rule = []) : bool
457497 * @param array $rule
458498 * @return bool
459499 */
460- private function validateIP ($ value , array $ rule = []) : bool
500+ protected function validateIP ($ value , array $ rule = []) : bool
461501 {
462502 return $ this ->validateIPv4 ($ value , $ rule ) || $ this ->validateIPv6 ($ value , $ rule );
463503 }
@@ -469,7 +509,7 @@ private function validateIP($value, array $rule = []) : bool
469509 * @param array $rule
470510 * @return bool
471511 */
472- private function validateIPv4 ($ value , array $ rule = []) : bool
512+ protected function validateIPv4 ($ value , array $ rule = []) : bool
473513 {
474514 return (bool ) filter_var ($ value , FILTER_VALIDATE_IP , FILTER_FLAG_IPV4 );
475515 }
@@ -481,7 +521,7 @@ private function validateIPv4($value, array $rule = []) : bool
481521 * @param array $rule
482522 * @return bool
483523 */
484- private function validateIPv6 ($ value , array $ rule = []) : bool
524+ protected function validateIPv6 ($ value , array $ rule = []) : bool
485525 {
486526 return (bool ) filter_var ($ value , FILTER_VALIDATE_IP , FILTER_FLAG_IPV6 );
487527 }
@@ -493,7 +533,7 @@ private function validateIPv6($value, array $rule = []) : bool
493533 * @param array $rule
494534 * @return bool
495535 */
496- private function validateClosure ($ value , array $ rule = []) : bool
536+ protected function validateClosure ($ value , array $ rule = []) : bool
497537 {
498538 return ($ value instanceof \Closure);
499539 }
@@ -505,7 +545,7 @@ private function validateClosure($value, array $rule = []) : bool
505545 * @param array $rule
506546 * @return bool
507547 */
508- private function validateCallable ($ value , array $ rule = []) : bool
548+ protected function validateCallable ($ value , array $ rule = []) : bool
509549 {
510550 return is_callable ($ value );
511551 }
@@ -517,7 +557,7 @@ private function validateCallable($value, array $rule = []) : bool
517557 * @param array $rule
518558 * @return bool
519559 */
520- private function validateDateTime ($ value , array $ rule = []) : bool
560+ protected function validateDateTime ($ value , array $ rule = []) : bool
521561 {
522562 if (!is_string ($ value ) && !is_int ($ value )) {
523563 return false ;
0 commit comments