Browse Source

allowEmpty and notEmpty to take field as list

Paweł Kukiełka 10 years ago
parent
commit
60a01c80cf
2 changed files with 423 additions and 141 deletions
  1. 273 132
      src/Validation/Validator.php
  2. 150 9
      tests/TestCase/Validation/ValidatorTest.php

+ 273 - 132
src/Validation/Validator.php

@@ -158,6 +158,7 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
             $set = $set ?: new ValidationSet;
             $this->_fields[$name] = $set;
         }
+
         return $this->_fields[$name];
     }
 
@@ -181,7 +182,7 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
      * If called with no arguments, it will return the provider stored under that name if
      * it exists, otherwise it returns this instance of chaining.
      *
-     * @param string $name  The name under which the provider should be set.
+     * @param string $name The name under which the provider should be set.
      * @param null|object|string $object Provider object or class name.
      * @return $this|object|string|null
      */
@@ -194,9 +195,11 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
             if ($name === 'default') {
                 return $this->_providers[$name] = new RulesProvider;
             }
+
             return null;
         }
         $this->_providers[$name] = $object;
+
         return $this;
     }
 
@@ -349,8 +352,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
                 $validator->provider($provider, $this->provider($provider));
             }
             $errors = $validator->errors($value, $context['newRecord']);
+
             return empty($errors) ? true : $errors;
         }]);
+
         return $this;
     }
 
@@ -391,8 +396,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
                     $errors[$i] = $check;
                 }
             }
+
             return empty($errors) ? true : $errors;
         }]);
+
         return $this;
     }
 
@@ -418,52 +425,42 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
         } else {
             $this->field($field)->remove($rule);
         }
+
         return $this;
     }
 
     /**
-     * Sets whether a field is required to be present in data array. You can also pass array.
-     * Using an array will let you provide the following keys:
+     * Sets whether a field is required to be present in data array.
+     * You can also pass array. Using an array will let you provide  the following
+     * keys:
      *
      * - `mode` individual mode for field
      * - `message` individual error message for field
      *
-     * You can also set mode and message for all passed fields, the individual setting
-     * takes precedence over group settings.
+     * You can also set mode and message for all passed fields, the individual
+     * setting takes precedence over group settings.
      *
      * @param string|array $field the name of the field
      * @param bool|string|callable $mode Valid values are true, false, 'create', 'update'.
      * If a callable is passed then the field will be required only when the callback
      * returns true.
      * @param string|null $message The message to show if the field presence validation fails.
+     *
      * @return $this
      */
     public function requirePresence($field, $mode = true, $message = null)
     {
         if (!is_array($field)) {
-            $field = [
-                $field => [
-                    'mode' => $mode,
-                    'message' => $message
-                ]
-            ];
+            $field = $this->_convertValidatorToArray($field, ['mode', 'message'], [$mode, $message]);
         }
 
         foreach ($field as $fieldName => $setting) {
-            if (is_string($setting)) {
-                $fieldName = $setting;
-                $setting = [];
-            }
-            if (!is_array($setting)) {
-                throw new InvalidArgumentException(sprintf('Invalid field "%s" setting, must be an array.', $fieldName));
-            }
-            $setting += [
-                'mode' => $mode,
-                'message' => $message
-            ];
-            $this->field($fieldName)->isPresenceRequired($setting['mode']);
-            if ($setting['message']) {
-                $this->_presenceMessages[$fieldName] = $setting['message'];
+            $settings = $this->_convertValidatorToArray($fieldName, ['mode', 'message'], [$mode, $message], $setting);
+            $fieldName = current(array_keys($settings));
+
+            $this->field($fieldName)->isPresenceRequired($settings[$fieldName]['mode']);
+            if ($settings[$fieldName]['message']) {
+                $this->_presenceMessages[$fieldName] = $settings[$fieldName]['message'];
             }
         }
 
@@ -471,7 +468,13 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
     }
 
     /**
-     * Allows a field to be empty.
+     * Allows a field to be empty. You can also pass array.
+     * Using an array will let you provide the following keys:
+     *
+     * - `when` individual when condition for field
+     *
+     * You can also set when and message for all passed fields, the individual setting
+     * takes precedence over group settings.
      *
      * This is the opposite of notEmpty() which requires a field to not be empty.
      * By using $mode equal to 'create' or 'update', you can allow fields to be empty
@@ -483,6 +486,17 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
      * $validator->allowEmpty('email'); // Email can be empty
      * $validator->allowEmpty('email', 'create'); // Email can be empty on create
      * $validator->allowEmpty('email', 'update'); // Email can be empty on update
+     * $validator->allowEmpty(['email', 'subject'], 'update'); // Email and subject can be empty on update
+     * $validator->allowEmpty(
+     *      [
+     *          'email' => [
+     *              'when' => true
+     *          ],
+     *          'subject'
+     *      ],
+     *      'update'
+     * ); // Email can be always empty on and subject can be empty on update
+     *
      * ```
      *
      * It is possible to conditionally allow emptiness on a field by passing a callback
@@ -508,12 +522,54 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
      */
     public function allowEmpty($field, $when = true)
     {
-        $this->field($field)->isEmptyAllowed($when);
+        if (!is_array($field)) {
+            $field = $this->_convertValidatorToArray($field, ['when'], [$when]);
+        }
+
+        foreach ($field as $fieldName => $setting) {
+            $settings = $this->_convertValidatorToArray($fieldName, ['when'], [$when], $setting);
+            $fieldName = current(array_keys($settings));
+
+            $this->field($fieldName)->isEmptyAllowed($settings[$fieldName]['when']);
+        }
+
         return $this;
     }
 
     /**
-     * Sets a field to require a non-empty value.
+     * Converts validator to fieldName => $setting array
+     *
+     * @param string $fieldName name of field
+     * @param array $settingKeys keys that will be used to create default settings
+     * @param array $settingsValues values that will be used to create default settings
+     * @param array $setting settings from data
+     * @return array
+     */
+    protected function _convertValidatorToArray($fieldName, $settingKeys = [], $settingsValues = [], $setting = [])
+    {
+        if (is_string($setting)) {
+            $fieldName = $setting;
+            $setting = [];
+        }
+        if (!is_array($setting)) {
+            throw new InvalidArgumentException(
+                sprintf('Invalid field "%s" setting, must be an array.', $fieldName)
+            );
+        }
+        $setting += array_combine($settingKeys, $settingsValues);
+
+        return [$fieldName => $setting];
+    }
+
+    /**
+     * Sets a field to require a non-empty value. You can also pass array.
+     * Using an array will let you provide the following keys:
+     *
+     * - `when` individual when condition for field
+     * - `message` individual error message for field
+     *
+     * You can also set when and message for all passed fields, the individual setting
+     * takes precedence over group settings.
      *
      * This is the opposite of allowEmpty() which allows a field to be empty.
      * By using $mode equal to 'create' or 'update', you can make fields required
@@ -526,6 +582,19 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
      * $validator->notEmpty('email'); // Email cannot be empty
      * $validator->notEmpty('email', $message, 'create'); // Email can be empty on update
      * $validator->notEmpty('email', $message, 'update'); // Email can be empty on create
+     * $validator->notEmpty(['email', 'title'], $message, 'update');
+     * // Email and title can be empty on create but can not on update
+     * $validator->notEmpty(
+     *      [
+     *          'email',
+     *          'title' => [
+     *              'when' => true,
+     *              'message' => 'Title cannot be empty'
+     *          ]
+     *      ],
+     *      $message,
+     *      'update'
+     * ); // Email can be empty on create, title must always be not empty
      * ```
      *
      * It is possible to conditionally disallow emptiness on a field by passing a callback
@@ -543,26 +612,47 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
      *
      * @param string $field the name of the field
      * @param string|null $message The message to show if the field is not
-     * @param bool|string|callable $when  Indicates when the field is not allowed
+     * @param bool|string|callable $when Indicates when the field is not allowed
      * to be empty. Valid values are true (always), 'create', 'update'. If a
      * callable is passed then the field will allowed be empty only when
      * the callback returns false.
+     *
      * @return $this
      */
     public function notEmpty($field, $message = null, $when = false)
     {
-        if ($when === 'create' || $when === 'update') {
-            $when = $when === 'create' ? 'update' : 'create';
-        } elseif (is_callable($when)) {
-            $when = function ($context) use ($when) {
-                return !$when($context);
-            };
+        if (!is_array($field)) {
+            $field = $this->_convertValidatorToArray(
+                $field,
+                ['when', 'message'],
+                [$when, $message]
+            );
         }
 
-        $this->field($field)->isEmptyAllowed($when);
-        if ($message) {
-            $this->_allowEmptyMessages[$field] = $message;
+        foreach ($field as $fieldName => $setting) {
+            $settings = $this->_convertValidatorToArray(
+                $fieldName,
+                ['when', 'message'],
+                [$when, $message],
+                $setting
+            );
+            $fieldName = current(array_keys($settings));
+            $whenSetting = $settings[$fieldName]['when'];
+
+            if ($whenSetting === 'create' || $whenSetting === 'update') {
+                $whenSetting = $whenSetting === 'create' ? 'update' : 'create';
+            } elseif (is_callable($whenSetting)) {
+                $whenSetting = function ($context) use ($whenSetting) {
+                    return !$whenSetting($context);
+                };
+            }
+
+            $this->field($fieldName)->isEmptyAllowed($whenSetting);
+            if ($settings[$fieldName]['message']) {
+                $this->_allowEmptyMessages[$fieldName] = $settings[$fieldName]['message'];
+            }
         }
+
         return $this;
     }
 
@@ -579,9 +669,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
     public function notBlank($field, $message = null, $when = null)
     {
         $extra = array_filter(['on' => $when, 'message' => $message]);
+
         return $this->add($field, 'notBlank', $extra + [
-            'rule' => 'notBlank',
-        ]);
+                'rule' => 'notBlank',
+            ]);
     }
 
     /**
@@ -597,9 +688,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
     public function alphaNumeric($field, $message = null, $when = null)
     {
         $extra = array_filter(['on' => $when, 'message' => $message]);
+
         return $this->add($field, 'alphaNumeric', $extra + [
-            'rule' => 'alphaNumeric',
-        ]);
+                'rule' => 'alphaNumeric',
+            ]);
     }
 
     /**
@@ -619,9 +711,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
             throw new InvalidArgumentException('The $range argument requires 2 numbers');
         }
         $extra = array_filter(['on' => $when, 'message' => $message]);
+
         return $this->add($field, 'lengthBetween', $extra + [
-            'rule' => ['lengthBetween', array_shift($range), array_shift($range)],
-        ]);
+                'rule' => ['lengthBetween', array_shift($range), array_shift($range)],
+            ]);
     }
 
     /**
@@ -639,9 +732,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
     public function creditCard($field, $type = 'all', $message = null, $when = null)
     {
         $extra = array_filter(['on' => $when, 'message' => $message]);
+
         return $this->add($field, 'creditCard', $extra + [
-            'rule' => ['cc', $type, true],
-        ]);
+                'rule' => ['cc', $type, true],
+            ]);
     }
 
     /**
@@ -658,9 +752,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
     public function greaterThan($field, $value, $message = null, $when = null)
     {
         $extra = array_filter(['on' => $when, 'message' => $message]);
+
         return $this->add($field, 'greaterThan', $extra + [
-            'rule' => ['comparison', '>', $value]
-        ]);
+                'rule' => ['comparison', '>', $value]
+            ]);
     }
 
     /**
@@ -677,9 +772,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
     public function greaterThanOrEqual($field, $value, $message = null, $when = null)
     {
         $extra = array_filter(['on' => $when, 'message' => $message]);
+
         return $this->add($field, 'greaterThanOrEqual', $extra + [
-            'rule' => ['comparison', '>=', $value]
-        ]);
+                'rule' => ['comparison', '>=', $value]
+            ]);
     }
 
     /**
@@ -696,9 +792,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
     public function lessThan($field, $value, $message = null, $when = null)
     {
         $extra = array_filter(['on' => $when, 'message' => $message]);
+
         return $this->add($field, 'lessThan', $extra + [
-            'rule' => ['comparison', '<', $value]
-        ]);
+                'rule' => ['comparison', '<', $value]
+            ]);
     }
 
     /**
@@ -715,9 +812,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
     public function lessThanOrEqual($field, $value, $message = null, $when = null)
     {
         $extra = array_filter(['on' => $when, 'message' => $message]);
+
         return $this->add($field, 'lessThanOrEqual', $extra + [
-            'rule' => ['comparison', '<=', $value]
-        ]);
+                'rule' => ['comparison', '<=', $value]
+            ]);
     }
 
     /**
@@ -734,9 +832,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
     public function equals($field, $value, $message = null, $when = null)
     {
         $extra = array_filter(['on' => $when, 'message' => $message]);
+
         return $this->add($field, 'equals', $extra + [
-            'rule' => ['comparison', '=', $value]
-        ]);
+                'rule' => ['comparison', '=', $value]
+            ]);
     }
 
     /**
@@ -753,9 +852,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
     public function notEquals($field, $value, $message = null, $when = null)
     {
         $extra = array_filter(['on' => $when, 'message' => $message]);
+
         return $this->add($field, 'notEquals', $extra + [
-            'rule' => ['comparison', '!=', $value]
-        ]);
+                'rule' => ['comparison', '!=', $value]
+            ]);
     }
 
     /**
@@ -774,9 +874,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
     public function sameAs($field, $secondField, $message = null, $when = null)
     {
         $extra = array_filter(['on' => $when, 'message' => $message]);
+
         return $this->add($field, 'sameAs', $extra + [
-            'rule' => ['compareWith', $secondField]
-        ]);
+                'rule' => ['compareWith', $secondField]
+            ]);
     }
 
     /**
@@ -793,9 +894,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
     public function containsNonAlphaNumeric($field, $limit = 1, $message = null, $when = null)
     {
         $extra = array_filter(['on' => $when, 'message' => $message]);
+
         return $this->add($field, 'containsNonAlphaNumeric', $extra + [
-            'rule' => ['containsNonAlphaNumeric', $limit]
-        ]);
+                'rule' => ['containsNonAlphaNumeric', $limit]
+            ]);
     }
 
     /**
@@ -812,9 +914,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
     public function date($field, $formats = ['ymd'], $message = null, $when = null)
     {
         $extra = array_filter(['on' => $when, 'message' => $message]);
+
         return $this->add($field, 'date', $extra + [
-            'rule' => ['date', $formats]
-        ]);
+                'rule' => ['date', $formats]
+            ]);
     }
 
     /**
@@ -831,9 +934,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
     public function dateTime($field, $formats = ['ymd'], $message = null, $when = null)
     {
         $extra = array_filter(['on' => $when, 'message' => $message]);
+
         return $this->add($field, 'dateTime', $extra + [
-            'rule' => ['datetime', $formats]
-        ]);
+                'rule' => ['datetime', $formats]
+            ]);
     }
 
     /**
@@ -849,9 +953,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
     public function time($field, $message = null, $when = null)
     {
         $extra = array_filter(['on' => $when, 'message' => $message]);
+
         return $this->add($field, 'time', $extra + [
-            'rule' => 'time'
-        ]);
+                'rule' => 'time'
+            ]);
     }
 
     /**
@@ -868,9 +973,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
     public function localizedTime($field, $type = 'datetime', $message = null, $when = null)
     {
         $extra = array_filter(['on' => $when, 'message' => $message]);
+
         return $this->add($field, 'localizedTime', $extra + [
-            'rule' => ['localizedTime', $type]
-        ]);
+                'rule' => ['localizedTime', $type]
+            ]);
     }
 
     /**
@@ -886,9 +992,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
     public function boolean($field, $message = null, $when = null)
     {
         $extra = array_filter(['on' => $when, 'message' => $message]);
+
         return $this->add($field, 'boolean', $extra + [
-            'rule' => 'boolean'
-        ]);
+                'rule' => 'boolean'
+            ]);
     }
 
     /**
@@ -905,9 +1012,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
     public function decimal($field, $places = null, $message = null, $when = null)
     {
         $extra = array_filter(['on' => $when, 'message' => $message]);
+
         return $this->add($field, 'decimal', $extra + [
-            'rule' => ['decimal', $places]
-        ]);
+                'rule' => ['decimal', $places]
+            ]);
     }
 
     /**
@@ -924,9 +1032,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
     public function email($field, $checkMX = false, $message = null, $when = null)
     {
         $extra = array_filter(['on' => $when, 'message' => $message]);
+
         return $this->add($field, 'email', $extra + [
-            'rule' => ['email', $checkMX]
-        ]);
+                'rule' => ['email', $checkMX]
+            ]);
     }
 
     /**
@@ -944,9 +1053,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
     public function ip($field, $message = null, $when = null)
     {
         $extra = array_filter(['on' => $when, 'message' => $message]);
+
         return $this->add($field, 'ip', $extra + [
-            'rule' => 'ip'
-        ]);
+                'rule' => 'ip'
+            ]);
     }
 
     /**
@@ -962,9 +1072,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
     public function ipv4($field, $message = null, $when = null)
     {
         $extra = array_filter(['on' => $when, 'message' => $message]);
+
         return $this->add($field, 'ipv4', $extra + [
-            'rule' => ['ip', 'ipv4']
-        ]);
+                'rule' => ['ip', 'ipv4']
+            ]);
     }
 
     /**
@@ -980,9 +1091,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
     public function ipv6($field, $message = null, $when = null)
     {
         $extra = array_filter(['on' => $when, 'message' => $message]);
+
         return $this->add($field, 'ipv6', $extra + [
-            'rule' => ['ip', 'ipv6']
-        ]);
+                'rule' => ['ip', 'ipv6']
+            ]);
     }
 
     /**
@@ -999,9 +1111,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
     public function minLength($field, $min, $message = null, $when = null)
     {
         $extra = array_filter(['on' => $when, 'message' => $message]);
+
         return $this->add($field, 'minLength', $extra + [
-            'rule' => ['minLength', $min]
-        ]);
+                'rule' => ['minLength', $min]
+            ]);
     }
 
     /**
@@ -1018,9 +1131,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
     public function maxLength($field, $max, $message = null, $when = null)
     {
         $extra = array_filter(['on' => $when, 'message' => $message]);
+
         return $this->add($field, 'maxLength', $extra + [
-            'rule' => ['maxLength', $max]
-        ]);
+                'rule' => ['maxLength', $max]
+            ]);
     }
 
     /**
@@ -1036,9 +1150,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
     public function numeric($field, $message = null, $when = null)
     {
         $extra = array_filter(['on' => $when, 'message' => $message]);
+
         return $this->add($field, 'numeric', $extra + [
-            'rule' => 'numeric'
-        ]);
+                'rule' => 'numeric'
+            ]);
     }
 
     /**
@@ -1054,9 +1169,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
     public function naturalNumber($field, $message = null, $when = null)
     {
         $extra = array_filter(['on' => $when, 'message' => $message]);
+
         return $this->add($field, 'naturalNumber', $extra + [
-            'rule' => ['naturalNumber', false]
-        ]);
+                'rule' => ['naturalNumber', false]
+            ]);
     }
 
     /**
@@ -1072,9 +1188,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
     public function nonNegativeInteger($field, $message = null, $when = null)
     {
         $extra = array_filter(['on' => $when, 'message' => $message]);
+
         return $this->add($field, 'nonNegativeInteger', $extra + [
-            'rule' => ['naturalNumber', true]
-        ]);
+                'rule' => ['naturalNumber', true]
+            ]);
     }
 
     /**
@@ -1094,9 +1211,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
             throw new InvalidArgumentException('The $range argument requires 2 numbers');
         }
         $extra = array_filter(['on' => $when, 'message' => $message]);
+
         return $this->add($field, 'range', $extra + [
-            'rule' => ['range', array_shift($range), array_shift($range)]
-        ]);
+                'rule' => ['range', array_shift($range), array_shift($range)]
+            ]);
     }
 
     /**
@@ -1114,9 +1232,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
     public function url($field, $message = null, $when = null)
     {
         $extra = array_filter(['on' => $when, 'message' => $message]);
+
         return $this->add($field, 'url', $extra + [
-            'rule' => ['url', false]
-        ]);
+                'rule' => ['url', false]
+            ]);
     }
 
     /**
@@ -1134,9 +1253,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
     public function urlWithProtocol($field, $message = null, $when = null)
     {
         $extra = array_filter(['on' => $when, 'message' => $message]);
+
         return $this->add($field, 'urlWithProtocol', $extra + [
-            'rule' => ['url', true]
-        ]);
+                'rule' => ['url', true]
+            ]);
     }
 
     /**
@@ -1153,9 +1273,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
     public function inList($field, array $list, $message = null, $when = null)
     {
         $extra = array_filter(['on' => $when, 'message' => $message]);
+
         return $this->add($field, 'inList', $extra + [
-            'rule' => ['inList', $list]
-        ]);
+                'rule' => ['inList', $list]
+            ]);
     }
 
     /**
@@ -1171,9 +1292,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
     public function uuid($field, $message = null, $when = null)
     {
         $extra = array_filter(['on' => $when, 'message' => $message]);
+
         return $this->add($field, 'uuid', $extra + [
-            'rule' => 'uuid'
-        ]);
+                'rule' => 'uuid'
+            ]);
     }
 
     /**
@@ -1192,9 +1314,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
     public function uploadedFile($field, array $options, $message = null, $when = null)
     {
         $extra = array_filter(['on' => $when, 'message' => $message]);
+
         return $this->add($field, 'uploadedFile', $extra + [
-            'rule' => ['uploadedFile', $options]
-        ]);
+                'rule' => ['uploadedFile', $options]
+            ]);
     }
 
     /**
@@ -1212,9 +1335,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
     public function latLong($field, $message = null, $when = null)
     {
         $extra = array_filter(['on' => $when, 'message' => $message]);
+
         return $this->add($field, 'latLong', $extra + [
-            'rule' => 'geoCoordinate'
-        ]);
+                'rule' => 'geoCoordinate'
+            ]);
     }
 
     /**
@@ -1230,9 +1354,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
     public function latitude($field, $message = null, $when = null)
     {
         $extra = array_filter(['on' => $when, 'message' => $message]);
+
         return $this->add($field, 'latitude', $extra + [
-            'rule' => 'latitude'
-        ]);
+                'rule' => 'latitude'
+            ]);
     }
 
     /**
@@ -1248,9 +1373,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
     public function longitude($field, $message = null, $when = null)
     {
         $extra = array_filter(['on' => $when, 'message' => $message]);
+
         return $this->add($field, 'longitude', $extra + [
-            'rule' => 'longitude'
-        ]);
+                'rule' => 'longitude'
+            ]);
     }
 
     /**
@@ -1266,9 +1392,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
     public function ascii($field, $message = null, $when = null)
     {
         $extra = array_filter(['on' => $when, 'message' => $message]);
+
         return $this->add($field, 'ascii', $extra + [
-            'rule' => 'ascii'
-        ]);
+                'rule' => 'ascii'
+            ]);
     }
 
     /**
@@ -1284,9 +1411,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
     public function utf8($field, $message = null, $when = null)
     {
         $extra = array_filter(['on' => $when, 'message' => $message]);
+
         return $this->add($field, 'utf8', $extra + [
-            'rule' => ['utf8', ['extended' => false]]
-        ]);
+                'rule' => ['utf8', ['extended' => false]]
+            ]);
     }
 
     /**
@@ -1304,9 +1432,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
     public function utf8Extended($field, $message = null, $when = null)
     {
         $extra = array_filter(['on' => $when, 'message' => $message]);
+
         return $this->add($field, 'utf8Extended', $extra + [
-            'rule' => ['utf8', ['extended' => true]]
-        ]);
+                'rule' => ['utf8', ['extended' => true]]
+            ]);
     }
 
     /**
@@ -1322,9 +1451,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
     public function integer($field, $message = null, $when = null)
     {
         $extra = array_filter(['on' => $when, 'message' => $message]);
+
         return $this->add($field, 'integer', $extra + [
-            'rule' => 'isInteger'
-        ]);
+                'rule' => 'isInteger'
+            ]);
     }
 
     /**
@@ -1344,9 +1474,10 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
         $extra = array_filter(['on' => $when, 'message' => $message]);
         $caseInsensitive = isset($options['caseInsenstive']) ? $options['caseInsensitive'] : false;
         unset($options['caseInsensitive']);
+
         return $this->add($field, 'multipleOptions', $extra + [
-            'rule' => ['multiple', $options, $caseInsensitive]
-        ]);
+                'rule' => ['multiple', $options, $caseInsensitive]
+            ]);
     }
 
     /**
@@ -1364,14 +1495,16 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
     public function hasAtLeast($field, $count, $message = null, $when = null)
     {
         $extra = array_filter(['on' => $when, 'message' => $message]);
+
         return $this->add($field, 'hasAtLeast', $extra + [
-            'rule' => function ($value) use ($count) {
-                if (is_array($value) && isset($value['_ids'])) {
-                    $value = $value['_ids'];
+                'rule' => function ($value) use ($count) {
+                    if (is_array($value) && isset($value['_ids'])) {
+                        $value = $value['_ids'];
+                    }
+
+                    return Validation::numElements($value, '>=', $count);
                 }
-                return Validation::numElements($value, '>=', $count);
-            }
-        ]);
+            ]);
     }
 
     /**
@@ -1389,14 +1522,16 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
     public function hasAtMost($field, $count, $message = null, $when = null)
     {
         $extra = array_filter(['on' => $when, 'message' => $message]);
+
         return $this->add($field, 'hasAtMost', $extra + [
-            'rule' => function ($value) use ($count) {
-                if (is_array($value) && isset($value['_ids'])) {
-                    $value = $value['_ids'];
+                'rule' => function ($value) use ($count) {
+                    if (is_array($value) && isset($value['_ids'])) {
+                        $value = $value['_ids'];
+                    }
+
+                    return Validation::numElements($value, '<=', $count);
                 }
-                return Validation::numElements($value, '<=', $count);
-            }
-        ]);
+            ]);
     }
 
     /**
@@ -1412,6 +1547,7 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
         $providers = $this->_providers;
         $data = [];
         $context = compact('data', 'newRecord', 'field', 'providers');
+
         return $this->_canBeEmpty($this->field($field), $context);
     }
 
@@ -1428,6 +1564,7 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
         $providers = $this->_providers;
         $data = [];
         $context = compact('data', 'newRecord', 'field', 'providers');
+
         return !$this->_checkPresence($this->field($field), $context);
     }
 
@@ -1498,11 +1635,13 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
         $isArray = is_array($data);
         if ($isArray && (isset($data['year']) || isset($data['hour']))) {
             $value = implode('', $data);
+
             return strlen($value) === 0;
         }
         if ($isArray && isset($data['name'], $data['type'], $data['tmp_name'], $data['error'])) {
             return (int)$data['error'] === UPLOAD_ERR_NO_FILE;
         }
+
         return false;
     }
 
@@ -1545,6 +1684,7 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
                 break;
             }
         }
+
         return $errors;
     }
 
@@ -1563,6 +1703,7 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
                 'rules' => array_keys($fieldSet->rules()),
             ];
         }
+
         return [
             '_presenceMessages' => $this->_presenceMessages,
             '_allowEmptyMessages' => $this->_allowEmptyMessages,

+ 150 - 9
tests/TestCase/Validation/ValidatorTest.php

@@ -74,6 +74,7 @@ class ValidatorTest extends TestCase
         $inner = new Validator();
         $inner->add('username', 'not-blank', ['rule' => function () use ($inner, $validator) {
             $this->assertSame($validator->providers(), $inner->providers(), 'Providers should match');
+
             return false;
         }]);
         $validator->addNested('user', $inner);
@@ -110,6 +111,7 @@ class ValidatorTest extends TestCase
         $inner = new Validator();
         $inner->add('comment', 'not-blank', ['rule' => function () use ($inner, $validator) {
             $this->assertSame($validator->providers(), $inner->providers(), 'Providers should match');
+
             return false;
         }]);
         $validator->addNestedMany('comments', $inner);
@@ -203,17 +205,23 @@ class ValidatorTest extends TestCase
         $this->assertTrue($validator->field('title')->isPresenceRequired());
         $this->assertTrue($validator->field('created')->isPresenceRequired());
 
-        $validator->requirePresence([
-            'title' => [
-                'mode' => false
-            ],
-            'content' => [
-                'mode' => 'update'
+        $validator->requirePresence(
+            [
+                'title' => [
+                    'mode' => false
+                ],
+                'content' => [
+                    'mode' => 'update'
+                ],
+                'subject'
             ],
-            'subject'
-        ], true);
+            true
+        );
         $this->assertFalse($validator->field('title')->isPresenceRequired());
-        $this->assertEquals('update', $validator->field('content')->isPresenceRequired());
+        $this->assertEquals(
+            'update',
+            $validator->field('content')->isPresenceRequired()
+        );
         $this->assertTrue($validator->field('subject')->isPresenceRequired());
     }
 
@@ -221,6 +229,7 @@ class ValidatorTest extends TestCase
      * Tests the requirePresence failure case
      *
      * @expectedException InvalidArgumentException
+     *
      * @return void
      */
     public function testRequirePresenceAsArrayFailure()
@@ -243,6 +252,7 @@ class ValidatorTest extends TestCase
             $this->assertEquals([], $context['providers']);
             $this->assertEquals('title', $context['field']);
             $this->assertTrue($context['newRecord']);
+
             return $require;
         });
         $this->assertTrue($validator->isPresenceRequired('title', true));
@@ -550,6 +560,60 @@ class ValidatorTest extends TestCase
     }
 
     /**
+     * Tests the allowEmpty as array method
+     *
+     * @return void
+     */
+    public function testAllowEmptyAsArray()
+    {
+        $validator = new Validator;
+
+        $validator->allowEmpty(
+            [
+                'title',
+                'subject',
+                'posted_at' => [
+                    'when' => false
+                ],
+                'updated_at' => [
+                    'when' => true
+                ],
+                'show_at' => [
+                    'when' => 'update'
+                ]
+            ],
+            'create'
+        );
+        $this->assertEquals(
+            'create',
+            $validator->field('title')->isEmptyAllowed()
+        );
+        $this->assertEquals(
+            'create',
+            $validator->field('subject')->isEmptyAllowed()
+        );
+        $this->assertFalse($validator->field('posted_at')->isEmptyAllowed());
+        $this->assertTrue($validator->field('updated_at')->isEmptyAllowed());
+        $this->assertEquals(
+            'update',
+            $validator->field('show_at')->isEmptyAllowed()
+        );
+    }
+
+    /**
+     * Tests the allowEmpty failure case
+     *
+     * @expectedException InvalidArgumentException
+     *
+     * @return void
+     */
+    public function testAllowEmptyAsArrayFailure()
+    {
+        $validator = new Validator();
+        $validator->allowEmpty(['title' => 'derp', 'created' => false]);
+    }
+
+    /**
      * Test the notEmpty() method.
      *
      * @return void
@@ -565,6 +629,78 @@ class ValidatorTest extends TestCase
     }
 
     /**
+     * Tests the notEmpty as array method
+     *
+     * @return void
+     */
+    public function testNotEmptyAsArray()
+    {
+        $validator = new Validator;
+        $validator->notEmpty(['title', 'created']);
+        $this->assertFalse($validator->field('title')->isEmptyAllowed());
+        $this->assertFalse($validator->field('created')->isEmptyAllowed());
+
+        $validator->notEmpty(
+            [
+                'title' => [
+                    'when' => false
+                ],
+                'content' => [
+                    'when' => 'update'
+                ],
+                'posted_at' => [
+                    'when' => 'create'
+                ],
+                'show_at' => [
+                    'message' => 'Show date cannot be empty',
+                    'when' => false
+                ],
+                'subject'
+            ],
+            'Not empty',
+            true
+        );
+
+        $this->assertFalse($validator->field('title')->isEmptyAllowed());
+        $this->assertTrue($validator->isEmptyAllowed('content', true));
+        $this->assertFalse($validator->isEmptyAllowed('content', false));
+        $this->assertFalse($validator->isEmptyAllowed('posted_at', true));
+        $this->assertTrue($validator->isEmptyAllowed('posted_at', false));
+        $this->assertTrue($validator->field('subject')->isEmptyAllowed());
+
+        $errors = $validator->errors(
+            [
+                'title' => '',
+                'content' => '',
+                'posted_at' => null,
+                'show_at' => null,
+                'subject' => ''
+            ],
+            false
+        );
+
+        $expected = [
+            'title' => ['_empty' => 'Not empty'],
+            'content' => ['_empty' => 'Not empty'],
+            'show_at' => ['_empty' => 'Show date cannot be empty']
+        ];
+        $this->assertEquals($expected, $errors);
+    }
+
+    /**
+     * Tests the notEmpty failure case
+     *
+     * @expectedException InvalidArgumentException
+     *
+     * @return void
+     */
+    public function testNotEmptyAsArrayFailure()
+    {
+        $validator = new Validator();
+        $validator->notEmpty(['title' => 'derp', 'created' => false]);
+    }
+
+    /**
      * Test the notEmpty() method.
      *
      * @return void
@@ -626,6 +762,7 @@ class ValidatorTest extends TestCase
             $this->assertEquals([], $context['data']);
             $this->assertEquals([], $context['providers']);
             $this->assertTrue($context['newRecord']);
+
             return $allow;
         });
         $this->assertTrue($validator->isEmptyAllowed('title', true));
@@ -647,6 +784,7 @@ class ValidatorTest extends TestCase
             $this->assertEquals([], $context['data']);
             $this->assertEquals([], $context['providers']);
             $this->assertFalse($context['newRecord']);
+
             return $prevent;
         });
         $this->assertFalse($validator->isEmptyAllowed('title', false));
@@ -830,6 +968,7 @@ class ValidatorTest extends TestCase
                     'field' => 'title'
                 ];
                 $this->assertEquals($expected, $context);
+
                 return "That ain't cool, yo";
             }));
 
@@ -875,6 +1014,7 @@ class ValidatorTest extends TestCase
                     'field' => 'title'
                 ];
                 $this->assertEquals($expected, $context);
+
                 return "That ain't cool, yo";
             }));
         $validator->provider('thing', $thing);
@@ -896,6 +1036,7 @@ class ValidatorTest extends TestCase
         $validator->add('name', 'myRule', [
             'rule' => function ($data, $provider) {
                 $this->assertEquals('foo', $data);
+
                 return 'You fail';
             }
         ]);