1: <?php
2: /**
3: * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
4: * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
5: *
6: * Licensed under The MIT License
7: * For full copyright and license information, please see the LICENSE.txt
8: * Redistributions of files must retain the above copyright notice.
9: *
10: * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
11: * @link https://cakephp.org CakePHP(tm) Project
12: * @since 2.2.0
13: * @license https://opensource.org/licenses/mit-license.php MIT License
14: */
15: namespace Cake\Validation;
16:
17: use ArrayAccess;
18: use ArrayIterator;
19: use Countable;
20: use InvalidArgumentException;
21: use IteratorAggregate;
22:
23: /**
24: * Validator object encapsulates all methods related to data validations for a model
25: * It also provides an API to dynamically change validation rules for each model field.
26: *
27: * Implements ArrayAccess to easily modify rules in the set
28: *
29: * @link https://book.cakephp.org/3.0/en/core-libraries/validation.html
30: */
31: class Validator implements ArrayAccess, IteratorAggregate, Countable
32: {
33: /**
34: * Used to flag nested rules created with addNested() and addNestedMany()
35: *
36: * @var string
37: */
38: const NESTED = '_nested';
39:
40: /**
41: * A flag for allowEmptyFor()
42: *
43: * When an empty string is given, it will be recognized as empty.
44: *
45: * @var int
46: */
47: const EMPTY_STRING = 1;
48:
49: /**
50: * A flag for allowEmptyFor()
51: *
52: * When an empty array is given, it will be recognized as empty.
53: *
54: * @var int
55: */
56: const EMPTY_ARRAY = 2;
57:
58: /**
59: * A flag for allowEmptyFor()
60: *
61: * When an array is given, if it has at least the `name`, `type`, `tmp_name` and `error` keys,
62: * and the value of `error` is equal to `UPLOAD_ERR_NO_FILE`, the value will be recognized as
63: * empty.
64: *
65: * @var int
66: */
67: const EMPTY_FILE = 4;
68:
69: /**
70: * A flag for allowEmptyFor()
71: *
72: * When an array is given, if it contains the `year` key, and only empty strings
73: * or null values, it will be recognized as empty.
74: *
75: * @var int
76: */
77: const EMPTY_DATE = 8;
78:
79: /**
80: * A flag for allowEmptyFor()
81: *
82: * When an array is given, if it contains the `hour` key, and only empty strings
83: * or null values, it will be recognized as empty.
84: *
85: * @var int
86: */
87: const EMPTY_TIME = 16;
88:
89: /**
90: * A combination of the all EMPTY_* flags
91: *
92: * @var int
93: */
94: const EMPTY_ALL = self::EMPTY_STRING | self::EMPTY_ARRAY | self::EMPTY_FILE | self::EMPTY_DATE | self::EMPTY_TIME;
95:
96: /**
97: * Holds the ValidationSet objects array
98: *
99: * @var array
100: */
101: protected $_fields = [];
102:
103: /**
104: * An associative array of objects or classes containing methods
105: * used for validation
106: *
107: * @var array
108: */
109: protected $_providers = [];
110:
111: /**
112: * An associative array of objects or classes used as a default provider list
113: *
114: * @var array
115: */
116: protected static $_defaultProviders = [];
117:
118: /**
119: * Contains the validation messages associated with checking the presence
120: * for each corresponding field.
121: *
122: * @var array
123: */
124: protected $_presenceMessages = [];
125:
126: /**
127: * Whether or not to use I18n functions for translating default error messages
128: *
129: * @var bool
130: */
131: protected $_useI18n = false;
132:
133: /**
134: * Contains the validation messages associated with checking the emptiness
135: * for each corresponding field.
136: *
137: * @var array
138: */
139: protected $_allowEmptyMessages = [];
140:
141: /**
142: * Contains the flags which specify what is empty for each corresponding field.
143: *
144: * @var array
145: */
146: protected $_allowEmptyFlags = [];
147:
148: /**
149: * Constructor
150: *
151: */
152: public function __construct()
153: {
154: $this->_useI18n = function_exists('__d');
155: $this->_providers = self::$_defaultProviders;
156: }
157:
158: /**
159: * Returns an array of fields that have failed validation. On the current model. This method will
160: * actually run validation rules over data, not just return the messages.
161: *
162: * @param array $data The data to be checked for errors
163: * @param bool $newRecord whether the data to be validated is new or to be updated.
164: * @return array Array of invalid fields
165: */
166: public function errors(array $data, $newRecord = true)
167: {
168: $errors = [];
169:
170: foreach ($this->_fields as $name => $field) {
171: $keyPresent = array_key_exists($name, $data);
172:
173: $providers = $this->_providers;
174: $context = compact('data', 'newRecord', 'field', 'providers');
175:
176: if (!$keyPresent && !$this->_checkPresence($field, $context)) {
177: $errors[$name]['_required'] = $this->getRequiredMessage($name);
178: continue;
179: }
180: if (!$keyPresent) {
181: continue;
182: }
183:
184: $canBeEmpty = $this->_canBeEmpty($field, $context);
185:
186: $flags = static::EMPTY_ALL;
187: if (isset($this->_allowEmptyFlags[$name])) {
188: $flags = $this->_allowEmptyFlags[$name];
189: }
190:
191: $isEmpty = $this->isEmpty($data[$name], $flags);
192:
193: if (!$canBeEmpty && $isEmpty) {
194: $errors[$name]['_empty'] = $this->getNotEmptyMessage($name);
195: continue;
196: }
197:
198: if ($isEmpty) {
199: continue;
200: }
201:
202: $result = $this->_processRules($name, $field, $data, $newRecord);
203: if ($result) {
204: $errors[$name] = $result;
205: }
206: }
207:
208: return $errors;
209: }
210:
211: /**
212: * Returns a ValidationSet object containing all validation rules for a field, if
213: * passed a ValidationSet as second argument, it will replace any other rule set defined
214: * before
215: *
216: * @param string $name [optional] The fieldname to fetch.
217: * @param \Cake\Validation\ValidationSet|null $set The set of rules for field
218: * @return \Cake\Validation\ValidationSet
219: */
220: public function field($name, ValidationSet $set = null)
221: {
222: if (empty($this->_fields[$name])) {
223: $set = $set ?: new ValidationSet();
224: $this->_fields[$name] = $set;
225: }
226:
227: return $this->_fields[$name];
228: }
229:
230: /**
231: * Check whether or not a validator contains any rules for the given field.
232: *
233: * @param string $name The field name to check.
234: * @return bool
235: */
236: public function hasField($name)
237: {
238: return isset($this->_fields[$name]);
239: }
240:
241: /**
242: * Associates an object to a name so it can be used as a provider. Providers are
243: * objects or class names that can contain methods used during validation of for
244: * deciding whether a validation rule can be applied. All validation methods,
245: * when called will receive the full list of providers stored in this validator.
246: *
247: * @param string $name The name under which the provider should be set.
248: * @param object|string $object Provider object or class name.
249: * @return $this
250: */
251: public function setProvider($name, $object)
252: {
253: $this->_providers[$name] = $object;
254:
255: return $this;
256: }
257:
258: /**
259: * Returns the provider stored under that name if it exists.
260: *
261: * @param string $name The name under which the provider should be set.
262: * @return object|string|null
263: * @throws \ReflectionException
264: */
265: public function getProvider($name)
266: {
267: if (isset($this->_providers[$name])) {
268: return $this->_providers[$name];
269: }
270: if ($name !== 'default') {
271: return null;
272: }
273:
274: $this->_providers[$name] = new RulesProvider();
275:
276: return $this->_providers[$name];
277: }
278:
279: /**
280: * Returns the default provider stored under that name if it exists.
281: *
282: * @param string $name The name under which the provider should be retrieved.
283: * @return object|string|null
284: */
285: public static function getDefaultProvider($name)
286: {
287: if (!isset(self::$_defaultProviders[$name])) {
288: return null;
289: }
290:
291: return self::$_defaultProviders[$name];
292: }
293:
294: /**
295: * Associates an object to a name so it can be used as a default provider.
296: *
297: * @param string $name The name under which the provider should be set.
298: * @param object|string $object Provider object or class name.
299: * @return void
300: */
301: public static function addDefaultProvider($name, $object)
302: {
303: self::$_defaultProviders[$name] = $object;
304: }
305:
306: /**
307: * Get the list of default providers.
308: *
309: * @return string[]
310: */
311: public static function getDefaultProviders()
312: {
313: return array_keys(self::$_defaultProviders);
314: }
315:
316: /**
317: * Associates an object to a name so it can be used as a provider. Providers are
318: * objects or class names that can contain methods used during validation of for
319: * deciding whether a validation rule can be applied. All validation methods,
320: * when called will receive the full list of providers stored in this validator.
321: *
322: * If called with no arguments, it will return the provider stored under that name if
323: * it exists, otherwise it returns this instance of chaining.
324: *
325: * @deprecated 3.4.0 Use setProvider()/getProvider() instead.
326: * @param string $name The name under which the provider should be set.
327: * @param null|object|string $object Provider object or class name.
328: * @return $this|object|string|null
329: */
330: public function provider($name, $object = null)
331: {
332: deprecationWarning(
333: 'Validator::provider() is deprecated. ' .
334: 'Use Validator::setProvider()/getProvider() instead.'
335: );
336: if ($object !== null) {
337: return $this->setProvider($name, $object);
338: }
339:
340: return $this->getProvider($name);
341: }
342:
343: /**
344: * Get the list of providers in this validator.
345: *
346: * @return string[]
347: */
348: public function providers()
349: {
350: return array_keys($this->_providers);
351: }
352:
353: /**
354: * Returns whether a rule set is defined for a field or not
355: *
356: * @param string $field name of the field to check
357: * @return bool
358: */
359: public function offsetExists($field)
360: {
361: return isset($this->_fields[$field]);
362: }
363:
364: /**
365: * Returns the rule set for a field
366: *
367: * @param string $field name of the field to check
368: * @return \Cake\Validation\ValidationSet
369: */
370: public function offsetGet($field)
371: {
372: return $this->field($field);
373: }
374:
375: /**
376: * Sets the rule set for a field
377: *
378: * @param string $field name of the field to set
379: * @param array|\Cake\Validation\ValidationSet $rules set of rules to apply to field
380: * @return void
381: */
382: public function offsetSet($field, $rules)
383: {
384: if (!$rules instanceof ValidationSet) {
385: $set = new ValidationSet();
386: foreach ((array)$rules as $name => $rule) {
387: $set->add($name, $rule);
388: }
389: }
390: $this->_fields[$field] = $rules;
391: }
392:
393: /**
394: * Unsets the rule set for a field
395: *
396: * @param string $field name of the field to unset
397: * @return void
398: */
399: public function offsetUnset($field)
400: {
401: unset($this->_fields[$field]);
402: }
403:
404: /**
405: * Returns an iterator for each of the fields to be validated
406: *
407: * @return \ArrayIterator
408: */
409: public function getIterator()
410: {
411: return new ArrayIterator($this->_fields);
412: }
413:
414: /**
415: * Returns the number of fields having validation rules
416: *
417: * @return int
418: */
419: public function count()
420: {
421: return count($this->_fields);
422: }
423:
424: /**
425: * Adds a new rule to a field's rule set. If second argument is an array
426: * then rules list for the field will be replaced with second argument and
427: * third argument will be ignored.
428: *
429: * ### Example:
430: *
431: * ```
432: * $validator
433: * ->add('title', 'required', ['rule' => 'notBlank'])
434: * ->add('user_id', 'valid', ['rule' => 'numeric', 'message' => 'Invalid User'])
435: *
436: * $validator->add('password', [
437: * 'size' => ['rule' => ['lengthBetween', 8, 20]],
438: * 'hasSpecialCharacter' => ['rule' => 'validateSpecialchar', 'message' => 'not valid']
439: * ]);
440: * ```
441: *
442: * @param string $field The name of the field from which the rule will be added
443: * @param array|string $name The alias for a single rule or multiple rules array
444: * @param array|\Cake\Validation\ValidationRule $rule the rule to add
445: * @return $this
446: */
447: public function add($field, $name, $rule = [])
448: {
449: $validationSet = $this->field($field);
450:
451: if (!is_array($name)) {
452: $rules = [$name => $rule];
453: } else {
454: $rules = $name;
455: }
456:
457: foreach ($rules as $name => $rule) {
458: if (is_array($rule)) {
459: $rule += ['rule' => $name];
460: }
461: $validationSet->add($name, $rule);
462: }
463:
464: return $this;
465: }
466:
467: /**
468: * Adds a nested validator.
469: *
470: * Nesting validators allows you to define validators for array
471: * types. For example, nested validators are ideal when you want to validate a
472: * sub-document, or complex array type.
473: *
474: * This method assumes that the sub-document has a 1:1 relationship with the parent.
475: *
476: * The providers of the parent validator will be synced into the nested validator, when
477: * errors are checked. This ensures that any validation rule providers connected
478: * in the parent will have the same values in the nested validator when rules are evaluated.
479: *
480: * @param string $field The root field for the nested validator.
481: * @param \Cake\Validation\Validator $validator The nested validator.
482: * @param string|null $message The error message when the rule fails.
483: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
484: * true when the validation rule should be applied.
485: * @return $this
486: */
487: public function addNested($field, Validator $validator, $message = null, $when = null)
488: {
489: $extra = array_filter(['message' => $message, 'on' => $when]);
490:
491: $validationSet = $this->field($field);
492: $validationSet->add(static::NESTED, $extra + ['rule' => function ($value, $context) use ($validator, $message) {
493: if (!is_array($value)) {
494: return false;
495: }
496: foreach ($this->providers() as $provider) {
497: $validator->setProvider($provider, $this->getProvider($provider));
498: }
499: $errors = $validator->errors($value, $context['newRecord']);
500:
501: $message = $message ? [static::NESTED => $message] : [];
502:
503: return empty($errors) ? true : $errors + $message;
504: }]);
505:
506: return $this;
507: }
508:
509: /**
510: * Adds a nested validator.
511: *
512: * Nesting validators allows you to define validators for array
513: * types. For example, nested validators are ideal when you want to validate many
514: * similar sub-documents or complex array types.
515: *
516: * This method assumes that the sub-document has a 1:N relationship with the parent.
517: *
518: * The providers of the parent validator will be synced into the nested validator, when
519: * errors are checked. This ensures that any validation rule providers connected
520: * in the parent will have the same values in the nested validator when rules are evaluated.
521: *
522: * @param string $field The root field for the nested validator.
523: * @param \Cake\Validation\Validator $validator The nested validator.
524: * @param string|null $message The error message when the rule fails.
525: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
526: * true when the validation rule should be applied.
527: * @return $this
528: */
529: public function addNestedMany($field, Validator $validator, $message = null, $when = null)
530: {
531: $extra = array_filter(['message' => $message, 'on' => $when]);
532:
533: $validationSet = $this->field($field);
534: $validationSet->add(static::NESTED, $extra + ['rule' => function ($value, $context) use ($validator, $message) {
535: if (!is_array($value)) {
536: return false;
537: }
538: foreach ($this->providers() as $provider) {
539: $validator->setProvider($provider, $this->getProvider($provider));
540: }
541: $errors = [];
542: foreach ($value as $i => $row) {
543: if (!is_array($row)) {
544: return false;
545: }
546: $check = $validator->errors($row, $context['newRecord']);
547: if (!empty($check)) {
548: $errors[$i] = $check;
549: }
550: }
551:
552: $message = $message ? [static::NESTED => $message] : [];
553:
554: return empty($errors) ? true : $errors + $message;
555: }]);
556:
557: return $this;
558: }
559:
560: /**
561: * Removes a rule from the set by its name
562: *
563: * ### Example:
564: *
565: * ```
566: * $validator
567: * ->remove('title', 'required')
568: * ->remove('user_id')
569: * ```
570: *
571: * @param string $field The name of the field from which the rule will be removed
572: * @param string|null $rule the name of the rule to be removed
573: * @return $this
574: */
575: public function remove($field, $rule = null)
576: {
577: if ($rule === null) {
578: unset($this->_fields[$field]);
579: } else {
580: $this->field($field)->remove($rule);
581: }
582:
583: return $this;
584: }
585:
586: /**
587: * Sets whether a field is required to be present in data array.
588: * You can also pass array. Using an array will let you provide the following
589: * keys:
590: *
591: * - `mode` individual mode for field
592: * - `message` individual error message for field
593: *
594: * You can also set mode and message for all passed fields, the individual
595: * setting takes precedence over group settings.
596: *
597: * @param string|array $field the name of the field or list of fields.
598: * @param bool|string|callable $mode Valid values are true, false, 'create', 'update'.
599: * If a callable is passed then the field will be required only when the callback
600: * returns true.
601: * @param string|null $message The message to show if the field presence validation fails.
602: * @return $this
603: */
604: public function requirePresence($field, $mode = true, $message = null)
605: {
606: $defaults = [
607: 'mode' => $mode,
608: 'message' => $message
609: ];
610:
611: if (!is_array($field)) {
612: $field = $this->_convertValidatorToArray($field, $defaults);
613: }
614:
615: foreach ($field as $fieldName => $setting) {
616: $settings = $this->_convertValidatorToArray($fieldName, $defaults, $setting);
617: $fieldName = current(array_keys($settings));
618:
619: $this->field($fieldName)->requirePresence($settings[$fieldName]['mode']);
620: if ($settings[$fieldName]['message']) {
621: $this->_presenceMessages[$fieldName] = $settings[$fieldName]['message'];
622: }
623: }
624:
625: return $this;
626: }
627:
628: /**
629: * Allows a field to be empty. You can also pass array.
630: * Using an array will let you provide the following keys:
631: *
632: * - `when` individual when condition for field
633: * - 'message' individual message for field
634: *
635: * You can also set when and message for all passed fields, the individual setting
636: * takes precedence over group settings.
637: *
638: * This is the opposite of notEmpty() which requires a field to not be empty.
639: * By using $mode equal to 'create' or 'update', you can allow fields to be empty
640: * when records are first created, or when they are updated.
641: *
642: * ### Example:
643: *
644: * ```
645: * // Email can be empty
646: * $validator->allowEmpty('email');
647: *
648: * // Email can be empty on create
649: * $validator->allowEmpty('email', 'create');
650: *
651: * // Email can be empty on update
652: * $validator->allowEmpty('email', 'update');
653: *
654: * // Email and subject can be empty on update
655: * $validator->allowEmpty(['email', 'subject'], 'update');
656: *
657: * // Email can be always empty, subject and content can be empty on update.
658: * $validator->allowEmpty(
659: * [
660: * 'email' => [
661: * 'when' => true
662: * ],
663: * 'content' => [
664: * 'message' => 'Content cannot be empty'
665: * ],
666: * 'subject'
667: * ],
668: * 'update'
669: * );
670: * ```
671: *
672: * It is possible to conditionally allow emptiness on a field by passing a callback
673: * as a second argument. The callback will receive the validation context array as
674: * argument:
675: *
676: * ```
677: * $validator->allowEmpty('email', function ($context) {
678: * return !$context['newRecord'] || $context['data']['role'] === 'admin';
679: * });
680: * ```
681: *
682: * This method will correctly detect empty file uploads and date/time/datetime fields.
683: *
684: * Because this and `notEmpty()` modify the same internal state, the last
685: * method called will take precedence.
686: *
687: * @deprecated 3.7.0 Use allowEmptyString(), allowEmptyArray(), allowEmptyFile(),
688: * allowEmptyDate(), allowEmptyTime() or allowEmptyDateTime() instead.
689: * @param string|array $field the name of the field or a list of fields
690: * @param bool|string|callable $when Indicates when the field is allowed to be empty
691: * Valid values are true (always), 'create', 'update'. If a callable is passed then
692: * the field will allowed to be empty only when the callback returns true.
693: * @param string|null $message The message to show if the field is not
694: * @return $this
695: */
696: public function allowEmpty($field, $when = true, $message = null)
697: {
698: $defaults = [
699: 'when' => $when,
700: 'message' => $message,
701: ];
702: if (!is_array($field)) {
703: $field = $this->_convertValidatorToArray($field, $defaults);
704: }
705:
706: foreach ($field as $fieldName => $setting) {
707: $settings = $this->_convertValidatorToArray($fieldName, $defaults, $setting);
708: $fieldName = array_keys($settings)[0];
709: $this->allowEmptyFor($fieldName, null, $settings[$fieldName]['when'], $settings[$fieldName]['message']);
710: }
711:
712: return $this;
713: }
714:
715: /**
716: * Indicate that a field can be empty.
717: *
718: * Using an array will let you provide the following keys:
719: *
720: * - `flags` individual flags for field
721: * - `when` individual when condition for field
722: * - `message` individual message for field
723: *
724: * You can also set flags, when and message for all passed fields, the individual
725: * setting takes precedence over group settings.
726: *
727: * ### Example:
728: *
729: * ```
730: * // Email can be empty
731: * $validator->allowEmptyFor('email', Validator::EMPTY_STRING);
732: *
733: * // Email can be empty on create
734: * $validator->allowEmptyFor('email', Validator::EMPTY_STRING, 'create');
735: *
736: * // Email can be empty on update
737: * $validator->allowEmptyFor('email', Validator::EMPTY_STRING, 'update');
738: * ```
739: *
740: * It is possible to conditionally allow emptiness on a field by passing a callback
741: * as a second argument. The callback will receive the validation context array as
742: * argument:
743: *
744: * ```
745: * $validator->allowEmpty('email', Validator::EMPTY_STRING, function ($context) {
746: * return !$context['newRecord'] || $context['data']['role'] === 'admin';
747: * });
748: * ```
749: *
750: * If you want to allow other kind of empty data on a field, you need to pass other
751: * flags:
752: *
753: * ```
754: * $validator->allowEmptyFor('photo', Validator::EMPTY_FILE);
755: * $validator->allowEmptyFor('published', Validator::EMPTY_STRING | Validator::EMPTY_DATE | Validator::EMPTY_TIME);
756: * $validator->allowEmptyFor('items', Validator::EMPTY_STRING | Validator::EMPTY_ARRAY);
757: * ```
758: *
759: * You can also use convenience wrappers of this method. The following calls are the
760: * same as above:
761: *
762: * ```
763: * $validator->allowEmptyFile('photo');
764: * $validator->allowEmptyDateTime('published');
765: * $validator->allowEmptyArray('items');
766: * ```
767: *
768: * @param string $field The name of the field.
769: * @param int|null $flags A bitmask of EMPTY_* flags which specify what is empty
770: * @param bool|string|callable $when Indicates when the field is allowed to be empty
771: * Valid values are true, false, 'create', 'update'. If a callable is passed then
772: * the field will allowed to be empty only when the callback returns true.
773: * @param string|null $message The message to show if the field is not
774: * @since 3.7.0
775: * @return $this
776: */
777: public function allowEmptyFor($field, $flags, $when = true, $message = null)
778: {
779: $this->field($field)->allowEmpty($when);
780: if ($message) {
781: $this->_allowEmptyMessages[$field] = $message;
782: }
783: if ($flags !== null) {
784: $this->_allowEmptyFlags[$field] = $flags;
785: }
786:
787: return $this;
788: }
789:
790: /**
791: * Allows a field to be an empty string.
792: *
793: * This method is equivalent to calling allowEmptyFor() with EMPTY_STRING flag.
794: *
795: * @param string $field The name of the field.
796: * @param bool|string|callable $when Indicates when the field is allowed to be empty
797: * Valid values are true, false, 'create', 'update'. If a callable is passed then
798: * the field will allowed to be empty only when the callback returns true.
799: * @param string|null $message The message to show if the field is not
800: * @return $this
801: * @since 3.7.0
802: * @see \Cake\Validation\Validator::allowEmptyFor() For detail usage
803: */
804: public function allowEmptyString($field, $when = true, $message = null)
805: {
806: return $this->allowEmptyFor($field, self::EMPTY_STRING, $when, $message);
807: }
808:
809: /**
810: * Allows a field to be an empty array.
811: *
812: * This method is equivalent to calling allowEmptyFor() with EMPTY_STRING +
813: * EMPTY_ARRAY flags.
814: *
815: * @param string $field The name of the field.
816: * @param bool|string|callable $when Indicates when the field is allowed to be empty
817: * Valid values are true, false, 'create', 'update'. If a callable is passed then
818: * the field will allowed to be empty only when the callback returns true.
819: * @param string|null $message The message to show if the field is not
820: * @return $this
821: * @since 3.7.0
822: * @see \Cake\Validation\Validator::allowEmptyFor() For detail usage
823: */
824: public function allowEmptyArray($field, $when = true, $message = null)
825: {
826: return $this->allowEmptyFor($field, self::EMPTY_STRING | self::EMPTY_ARRAY, $when, $message);
827: }
828:
829: /**
830: * Allows a field to be an empty file.
831: *
832: * This method is equivalent to calling allowEmptyFor() with EMPTY_FILE flag.
833: *
834: * @param string $field The name of the field.
835: * @param bool|string|callable $when Indicates when the field is allowed to be empty
836: * Valid values are true, false, 'create', 'update'. If a callable is passed then
837: * the field will allowed to be empty only when the callback returns true.
838: * @param string|null $message The message to show if the field is not
839: * @return $this
840: * @since 3.7.0
841: * @see \Cake\Validation\Validator::allowEmptyFor() For detail usage
842: */
843: public function allowEmptyFile($field, $when = true, $message = null)
844: {
845: return $this->allowEmptyFor($field, self::EMPTY_FILE, $when, $message);
846: }
847:
848: /**
849: * Allows a field to be an empty date.
850: *
851: * This method is equivalent to calling allowEmptyFor() with EMPTY_STRING +
852: * EMPTY_DATE flags.
853: *
854: * @param string $field The name of the field.
855: * @param bool|string|callable $when Indicates when the field is allowed to be empty
856: * Valid values are true, false, 'create', 'update'. If a callable is passed then
857: * the field will allowed to be empty only when the callback returns true.
858: * @param string|null $message The message to show if the field is not
859: * @return $this
860: * @since 3.7.0
861: * @see \Cake\Validation\Validator::allowEmptyFor() For detail usage
862: */
863: public function allowEmptyDate($field, $when = true, $message = null)
864: {
865: return $this->allowEmptyFor($field, self::EMPTY_STRING | self::EMPTY_DATE, $when, $message);
866: }
867:
868: /**
869: * Allows a field to be an empty time.
870: *
871: * This method is equivalent to calling allowEmptyFor() with EMPTY_STRING +
872: * EMPTY_TIME flags.
873: *
874: * @param string $field The name of the field.
875: * @param bool|string|callable $when Indicates when the field is allowed to be empty
876: * Valid values are true, false, 'create', 'update'. If a callable is passed then
877: * the field will allowed to be empty only when the callback returns true.
878: * @param string|null $message The message to show if the field is not
879: * @return $this
880: * @since 3.7.0
881: * @see \Cake\Validation\Validator::allowEmptyFor() For detail usage
882: */
883: public function allowEmptyTime($field, $when = true, $message = null)
884: {
885: return $this->allowEmptyFor($field, self::EMPTY_STRING | self::EMPTY_TIME, $when, $message);
886: }
887:
888: /**
889: * Allows a field to be an empty date/time.
890: *
891: * This method is equivalent to calling allowEmptyFor() with EMPTY_STRING +
892: * EMPTY_DATE + EMPTY_TIME flags.
893: *
894: * @param string $field The name of the field.
895: * @param bool|string|callable $when Indicates when the field is allowed to be empty
896: * Valid values are true, false, 'create', 'update'. If a callable is passed then
897: * the field will allowed to be empty only when the callback returns true.
898: * @param string|null $message The message to show if the field is not
899: * @return $this
900: * @since 3.7.0
901: * @see \Cake\Validation\Validator::allowEmptyFor() For detail usage
902: */
903: public function allowEmptyDateTime($field, $when = true, $message = null)
904: {
905: return $this->allowEmptyFor($field, self::EMPTY_STRING | self::EMPTY_DATE | self::EMPTY_TIME, $when, $message);
906: }
907:
908: /**
909: * Converts validator to fieldName => $settings array
910: *
911: * @param int|string $fieldName name of field
912: * @param array $defaults default settings
913: * @param string|array $settings settings from data
914: * @return array
915: */
916: protected function _convertValidatorToArray($fieldName, $defaults = [], $settings = [])
917: {
918: if (is_string($settings)) {
919: $fieldName = $settings;
920: $settings = [];
921: }
922: if (!is_array($settings)) {
923: throw new InvalidArgumentException(
924: sprintf('Invalid settings for "%s". Settings must be an array.', $fieldName)
925: );
926: }
927: $settings += $defaults;
928:
929: return [$fieldName => $settings];
930: }
931:
932: /**
933: * Sets a field to require a non-empty value. You can also pass array.
934: * Using an array will let you provide the following keys:
935: *
936: * - `when` individual when condition for field
937: * - `message` individual error message for field
938: *
939: * You can also set `when` and `message` for all passed fields, the individual setting
940: * takes precedence over group settings.
941: *
942: * This is the opposite of `allowEmpty()` which allows a field to be empty.
943: * By using $mode equal to 'create' or 'update', you can make fields required
944: * when records are first created, or when they are updated.
945: *
946: * ### Example:
947: *
948: * ```
949: * $message = 'This field cannot be empty';
950: *
951: * // Email cannot be empty
952: * $validator->notEmpty('email');
953: *
954: * // Email can be empty on update, but not create
955: * $validator->notEmpty('email', $message, 'create');
956: *
957: * // Email can be empty on create, but required on update.
958: * $validator->notEmpty('email', $message, 'update');
959: *
960: * // Email and title can be empty on create, but are required on update.
961: * $validator->notEmpty(['email', 'title'], $message, 'update');
962: *
963: * // Email can be empty on create, title must always be not empty
964: * $validator->notEmpty(
965: * [
966: * 'email',
967: * 'title' => [
968: * 'when' => true,
969: * 'message' => 'Title cannot be empty'
970: * ]
971: * ],
972: * $message,
973: * 'update'
974: * );
975: * ```
976: *
977: * It is possible to conditionally disallow emptiness on a field by passing a callback
978: * as the third argument. The callback will receive the validation context array as
979: * argument:
980: *
981: * ```
982: * $validator->notEmpty('email', 'Email is required', function ($context) {
983: * return $context['newRecord'] && $context['data']['role'] !== 'admin';
984: * });
985: * ```
986: *
987: * Because this and `allowEmpty()` modify the same internal state, the last
988: * method called will take precedence.
989: *
990: * @deprecated 3.7.0 Use allowEmptyString(), allowEmptyArray(), allowEmptyFile(),
991: * allowEmptyDate(), allowEmptyTime() or allowEmptyDateTime() with reversed
992: * conditions instead.
993: * @param string|array $field the name of the field or list of fields
994: * @param string|null $message The message to show if the field is not
995: * @param bool|string|callable $when Indicates when the field is not allowed
996: * to be empty. Valid values are true (always), 'create', 'update'. If a
997: * callable is passed then the field will allowed to be empty only when
998: * the callback returns false.
999: * @return $this
1000: */
1001: public function notEmpty($field, $message = null, $when = false)
1002: {
1003: $defaults = [
1004: 'when' => $when,
1005: 'message' => $message
1006: ];
1007:
1008: if (!is_array($field)) {
1009: $field = $this->_convertValidatorToArray($field, $defaults);
1010: }
1011:
1012: foreach ($field as $fieldName => $setting) {
1013: $settings = $this->_convertValidatorToArray($fieldName, $defaults, $setting);
1014: $fieldName = current(array_keys($settings));
1015: $whenSetting = $settings[$fieldName]['when'];
1016:
1017: if ($whenSetting === 'create' || $whenSetting === 'update') {
1018: $whenSetting = $whenSetting === 'create' ? 'update' : 'create';
1019: } elseif (is_callable($whenSetting)) {
1020: $whenSetting = function ($context) use ($whenSetting) {
1021: return !$whenSetting($context);
1022: };
1023: }
1024:
1025: $this->field($fieldName)->allowEmpty($whenSetting);
1026: if ($settings[$fieldName]['message']) {
1027: $this->_allowEmptyMessages[$fieldName] = $settings[$fieldName]['message'];
1028: }
1029: }
1030:
1031: return $this;
1032: }
1033:
1034: /**
1035: * Add a notBlank rule to a field.
1036: *
1037: * @param string $field The field you want to apply the rule to.
1038: * @param string|null $message The error message when the rule fails.
1039: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1040: * true when the validation rule should be applied.
1041: * @see \Cake\Validation\Validation::notBlank()
1042: * @return $this
1043: */
1044: public function notBlank($field, $message = null, $when = null)
1045: {
1046: $extra = array_filter(['on' => $when, 'message' => $message]);
1047:
1048: return $this->add($field, 'notBlank', $extra + [
1049: 'rule' => 'notBlank',
1050: ]);
1051: }
1052:
1053: /**
1054: * Add an alphanumeric rule to a field.
1055: *
1056: * @param string $field The field you want to apply the rule to.
1057: * @param string|null $message The error message when the rule fails.
1058: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1059: * true when the validation rule should be applied.
1060: * @see \Cake\Validation\Validation::alphaNumeric()
1061: * @return $this
1062: */
1063: public function alphaNumeric($field, $message = null, $when = null)
1064: {
1065: $extra = array_filter(['on' => $when, 'message' => $message]);
1066:
1067: return $this->add($field, 'alphaNumeric', $extra + [
1068: 'rule' => 'alphaNumeric',
1069: ]);
1070: }
1071:
1072: /**
1073: * Add an rule that ensures a string length is within a range.
1074: *
1075: * @param string $field The field you want to apply the rule to.
1076: * @param array $range The inclusive minimum and maximum length you want permitted.
1077: * @param string|null $message The error message when the rule fails.
1078: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1079: * true when the validation rule should be applied.
1080: * @see \Cake\Validation\Validation::alphaNumeric()
1081: * @return $this
1082: */
1083: public function lengthBetween($field, array $range, $message = null, $when = null)
1084: {
1085: if (count($range) !== 2) {
1086: throw new InvalidArgumentException('The $range argument requires 2 numbers');
1087: }
1088: $extra = array_filter(['on' => $when, 'message' => $message]);
1089:
1090: return $this->add($field, 'lengthBetween', $extra + [
1091: 'rule' => ['lengthBetween', array_shift($range), array_shift($range)],
1092: ]);
1093: }
1094:
1095: /**
1096: * Add a credit card rule to a field.
1097: *
1098: * @param string $field The field you want to apply the rule to.
1099: * @param string $type The type of cards you want to allow. Defaults to 'all'.
1100: * You can also supply an array of accepted card types. e.g `['mastercard', 'visa', 'amex']`
1101: * @param string|null $message The error message when the rule fails.
1102: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1103: * true when the validation rule should be applied.
1104: * @see \Cake\Validation\Validation::creditCard()
1105: * @return $this
1106: */
1107: public function creditCard($field, $type = 'all', $message = null, $when = null)
1108: {
1109: $extra = array_filter(['on' => $when, 'message' => $message]);
1110:
1111: return $this->add($field, 'creditCard', $extra + [
1112: 'rule' => ['creditCard', $type, true],
1113: ]);
1114: }
1115:
1116: /**
1117: * Add a greater than comparison rule to a field.
1118: *
1119: * @param string $field The field you want to apply the rule to.
1120: * @param int|float $value The value user data must be greater than.
1121: * @param string|null $message The error message when the rule fails.
1122: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1123: * true when the validation rule should be applied.
1124: * @see \Cake\Validation\Validation::comparison()
1125: * @return $this
1126: */
1127: public function greaterThan($field, $value, $message = null, $when = null)
1128: {
1129: $extra = array_filter(['on' => $when, 'message' => $message]);
1130:
1131: return $this->add($field, 'greaterThan', $extra + [
1132: 'rule' => ['comparison', Validation::COMPARE_GREATER, $value]
1133: ]);
1134: }
1135:
1136: /**
1137: * Add a greater than or equal to comparison rule to a field.
1138: *
1139: * @param string $field The field you want to apply the rule to.
1140: * @param int|float $value The value user data must be greater than or equal to.
1141: * @param string|null $message The error message when the rule fails.
1142: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1143: * true when the validation rule should be applied.
1144: * @see \Cake\Validation\Validation::comparison()
1145: * @return $this
1146: */
1147: public function greaterThanOrEqual($field, $value, $message = null, $when = null)
1148: {
1149: $extra = array_filter(['on' => $when, 'message' => $message]);
1150:
1151: return $this->add($field, 'greaterThanOrEqual', $extra + [
1152: 'rule' => ['comparison', Validation::COMPARE_GREATER_OR_EQUAL, $value]
1153: ]);
1154: }
1155:
1156: /**
1157: * Add a less than comparison rule to a field.
1158: *
1159: * @param string $field The field you want to apply the rule to.
1160: * @param int|float $value The value user data must be less than.
1161: * @param string|null $message The error message when the rule fails.
1162: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1163: * true when the validation rule should be applied.
1164: * @see \Cake\Validation\Validation::comparison()
1165: * @return $this
1166: */
1167: public function lessThan($field, $value, $message = null, $when = null)
1168: {
1169: $extra = array_filter(['on' => $when, 'message' => $message]);
1170:
1171: return $this->add($field, 'lessThan', $extra + [
1172: 'rule' => ['comparison', Validation::COMPARE_LESS, $value]
1173: ]);
1174: }
1175:
1176: /**
1177: * Add a less than or equal comparison rule to a field.
1178: *
1179: * @param string $field The field you want to apply the rule to.
1180: * @param int|float $value The value user data must be less than or equal to.
1181: * @param string|null $message The error message when the rule fails.
1182: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1183: * true when the validation rule should be applied.
1184: * @see \Cake\Validation\Validation::comparison()
1185: * @return $this
1186: */
1187: public function lessThanOrEqual($field, $value, $message = null, $when = null)
1188: {
1189: $extra = array_filter(['on' => $when, 'message' => $message]);
1190:
1191: return $this->add($field, 'lessThanOrEqual', $extra + [
1192: 'rule' => ['comparison', Validation::COMPARE_LESS_OR_EQUAL, $value]
1193: ]);
1194: }
1195:
1196: /**
1197: * Add a equal to comparison rule to a field.
1198: *
1199: * @param string $field The field you want to apply the rule to.
1200: * @param int|float $value The value user data must be equal to.
1201: * @param string|null $message The error message when the rule fails.
1202: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1203: * true when the validation rule should be applied.
1204: * @see \Cake\Validation\Validation::comparison()
1205: * @return $this
1206: */
1207: public function equals($field, $value, $message = null, $when = null)
1208: {
1209: $extra = array_filter(['on' => $when, 'message' => $message]);
1210:
1211: return $this->add($field, 'equals', $extra + [
1212: 'rule' => ['comparison', Validation::COMPARE_EQUAL, $value]
1213: ]);
1214: }
1215:
1216: /**
1217: * Add a not equal to comparison rule to a field.
1218: *
1219: * @param string $field The field you want to apply the rule to.
1220: * @param int|float $value The value user data must be not be equal to.
1221: * @param string|null $message The error message when the rule fails.
1222: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1223: * true when the validation rule should be applied.
1224: * @see \Cake\Validation\Validation::comparison()
1225: * @return $this
1226: */
1227: public function notEquals($field, $value, $message = null, $when = null)
1228: {
1229: $extra = array_filter(['on' => $when, 'message' => $message]);
1230:
1231: return $this->add($field, 'notEquals', $extra + [
1232: 'rule' => ['comparison', Validation::COMPARE_NOT_EQUAL, $value]
1233: ]);
1234: }
1235:
1236: /**
1237: * Add a rule to compare two fields to each other.
1238: *
1239: * If both fields have the exact same value the rule will pass.
1240: *
1241: * @param string $field The field you want to apply the rule to.
1242: * @param string $secondField The field you want to compare against.
1243: * @param string|null $message The error message when the rule fails.
1244: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1245: * true when the validation rule should be applied.
1246: * @see \Cake\Validation\Validation::compareFields()
1247: * @return $this
1248: */
1249: public function sameAs($field, $secondField, $message = null, $when = null)
1250: {
1251: $extra = array_filter(['on' => $when, 'message' => $message]);
1252:
1253: return $this->add($field, 'sameAs', $extra + [
1254: 'rule' => ['compareFields', $secondField, Validation::COMPARE_SAME]
1255: ]);
1256: }
1257:
1258: /**
1259: * Add a rule to compare that two fields have different values.
1260: *
1261: * @param string $field The field you want to apply the rule to.
1262: * @param string $secondField The field you want to compare against.
1263: * @param string|null $message The error message when the rule fails.
1264: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1265: * true when the validation rule should be applied.
1266: * @see \Cake\Validation\Validation::compareFields()
1267: * @return $this
1268: * @since 3.6.0
1269: */
1270: public function notSameAs($field, $secondField, $message = null, $when = null)
1271: {
1272: $extra = array_filter(['on' => $when, 'message' => $message]);
1273:
1274: return $this->add($field, 'notSameAs', $extra + [
1275: 'rule' => ['compareFields', $secondField, Validation::COMPARE_NOT_SAME]
1276: ]);
1277: }
1278:
1279: /**
1280: * Add a rule to compare one field is equal to another.
1281: *
1282: * @param string $field The field you want to apply the rule to.
1283: * @param string $secondField The field you want to compare against.
1284: * @param string|null $message The error message when the rule fails.
1285: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1286: * true when the validation rule should be applied.
1287: * @see \Cake\Validation\Validation::compareFields()
1288: * @return $this
1289: * @since 3.6.0
1290: */
1291: public function equalToField($field, $secondField, $message = null, $when = null)
1292: {
1293: $extra = array_filter(['on' => $when, 'message' => $message]);
1294:
1295: return $this->add($field, 'equalToField', $extra + [
1296: 'rule' => ['compareFields', $secondField, Validation::COMPARE_EQUAL]
1297: ]);
1298: }
1299:
1300: /**
1301: * Add a rule to compare one field is not equal to another.
1302: *
1303: * @param string $field The field you want to apply the rule to.
1304: * @param string $secondField The field you want to compare against.
1305: * @param string|null $message The error message when the rule fails.
1306: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1307: * true when the validation rule should be applied.
1308: * @see \Cake\Validation\Validation::compareFields()
1309: * @return $this
1310: * @since 3.6.0
1311: */
1312: public function notEqualToField($field, $secondField, $message = null, $when = null)
1313: {
1314: $extra = array_filter(['on' => $when, 'message' => $message]);
1315:
1316: return $this->add($field, 'notEqualToField', $extra + [
1317: 'rule' => ['compareFields', $secondField, Validation::COMPARE_NOT_EQUAL]
1318: ]);
1319: }
1320:
1321: /**
1322: * Add a rule to compare one field is greater than another.
1323: *
1324: * @param string $field The field you want to apply the rule to.
1325: * @param string $secondField The field you want to compare against.
1326: * @param string|null $message The error message when the rule fails.
1327: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1328: * true when the validation rule should be applied.
1329: * @see \Cake\Validation\Validation::compareFields()
1330: * @return $this
1331: * @since 3.6.0
1332: */
1333: public function greaterThanField($field, $secondField, $message = null, $when = null)
1334: {
1335: $extra = array_filter(['on' => $when, 'message' => $message]);
1336:
1337: return $this->add($field, 'greaterThanField', $extra + [
1338: 'rule' => ['compareFields', $secondField, Validation::COMPARE_GREATER]
1339: ]);
1340: }
1341:
1342: /**
1343: * Add a rule to compare one field is greater than or equal to another.
1344: *
1345: * @param string $field The field you want to apply the rule to.
1346: * @param string $secondField The field you want to compare against.
1347: * @param string|null $message The error message when the rule fails.
1348: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1349: * true when the validation rule should be applied.
1350: * @see \Cake\Validation\Validation::compareFields()
1351: * @return $this
1352: * @since 3.6.0
1353: */
1354: public function greaterThanOrEqualToField($field, $secondField, $message = null, $when = null)
1355: {
1356: $extra = array_filter(['on' => $when, 'message' => $message]);
1357:
1358: return $this->add($field, 'greaterThanOrEqualToField', $extra + [
1359: 'rule' => ['compareFields', $secondField, Validation::COMPARE_GREATER_OR_EQUAL]
1360: ]);
1361: }
1362:
1363: /**
1364: * Add a rule to compare one field is less than another.
1365: *
1366: * @param string $field The field you want to apply the rule to.
1367: * @param string $secondField The field you want to compare against.
1368: * @param string|null $message The error message when the rule fails.
1369: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1370: * true when the validation rule should be applied.
1371: * @see \Cake\Validation\Validation::compareFields()
1372: * @return $this
1373: * @since 3.6.0
1374: */
1375: public function lessThanField($field, $secondField, $message = null, $when = null)
1376: {
1377: $extra = array_filter(['on' => $when, 'message' => $message]);
1378:
1379: return $this->add($field, 'lessThanField', $extra + [
1380: 'rule' => ['compareFields', $secondField, Validation::COMPARE_LESS]
1381: ]);
1382: }
1383:
1384: /**
1385: * Add a rule to compare one field is less than or equal to another.
1386: *
1387: * @param string $field The field you want to apply the rule to.
1388: * @param string $secondField The field you want to compare against.
1389: * @param string|null $message The error message when the rule fails.
1390: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1391: * true when the validation rule should be applied.
1392: * @see \Cake\Validation\Validation::compareFields()
1393: * @return $this
1394: * @since 3.6.0
1395: */
1396: public function lessThanOrEqualToField($field, $secondField, $message = null, $when = null)
1397: {
1398: $extra = array_filter(['on' => $when, 'message' => $message]);
1399:
1400: return $this->add($field, 'lessThanOrEqualToField', $extra + [
1401: 'rule' => ['compareFields', $secondField, Validation::COMPARE_LESS_OR_EQUAL]
1402: ]);
1403: }
1404:
1405: /**
1406: * Add a rule to check if a field contains non alpha numeric characters.
1407: *
1408: * @param string $field The field you want to apply the rule to.
1409: * @param int $limit The minimum number of non-alphanumeric fields required.
1410: * @param string|null $message The error message when the rule fails.
1411: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1412: * true when the validation rule should be applied.
1413: * @see \Cake\Validation\Validation::containsNonAlphaNumeric()
1414: * @return $this
1415: */
1416: public function containsNonAlphaNumeric($field, $limit = 1, $message = null, $when = null)
1417: {
1418: $extra = array_filter(['on' => $when, 'message' => $message]);
1419:
1420: return $this->add($field, 'containsNonAlphaNumeric', $extra + [
1421: 'rule' => ['containsNonAlphaNumeric', $limit]
1422: ]);
1423: }
1424:
1425: /**
1426: * Add a date format validation rule to a field.
1427: *
1428: * @param string $field The field you want to apply the rule to.
1429: * @param array $formats A list of accepted date formats.
1430: * @param string|null $message The error message when the rule fails.
1431: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1432: * true when the validation rule should be applied.
1433: * @see \Cake\Validation\Validation::date()
1434: * @return $this
1435: */
1436: public function date($field, $formats = ['ymd'], $message = null, $when = null)
1437: {
1438: $extra = array_filter(['on' => $when, 'message' => $message]);
1439:
1440: return $this->add($field, 'date', $extra + [
1441: 'rule' => ['date', $formats]
1442: ]);
1443: }
1444:
1445: /**
1446: * Add a date time format validation rule to a field.
1447: *
1448: * @param string $field The field you want to apply the rule to.
1449: * @param array $formats A list of accepted date formats.
1450: * @param string|null $message The error message when the rule fails.
1451: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1452: * true when the validation rule should be applied.
1453: * @see \Cake\Validation\Validation::datetime()
1454: * @return $this
1455: */
1456: public function dateTime($field, $formats = ['ymd'], $message = null, $when = null)
1457: {
1458: $extra = array_filter(['on' => $when, 'message' => $message]);
1459:
1460: return $this->add($field, 'dateTime', $extra + [
1461: 'rule' => ['datetime', $formats]
1462: ]);
1463: }
1464:
1465: /**
1466: * Add a time format validation rule to a field.
1467: *
1468: * @param string $field The field you want to apply the rule to.
1469: * @param string|null $message The error message when the rule fails.
1470: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1471: * true when the validation rule should be applied.
1472: * @see \Cake\Validation\Validation::time()
1473: * @return $this
1474: */
1475: public function time($field, $message = null, $when = null)
1476: {
1477: $extra = array_filter(['on' => $when, 'message' => $message]);
1478:
1479: return $this->add($field, 'time', $extra + [
1480: 'rule' => 'time'
1481: ]);
1482: }
1483:
1484: /**
1485: * Add a localized time, date or datetime format validation rule to a field.
1486: *
1487: * @param string $field The field you want to apply the rule to.
1488: * @param string $type Parser type, one out of 'date', 'time', and 'datetime'
1489: * @param string|null $message The error message when the rule fails.
1490: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1491: * true when the validation rule should be applied.
1492: * @see \Cake\Validation\Validation::localizedTime()
1493: * @return $this
1494: */
1495: public function localizedTime($field, $type = 'datetime', $message = null, $when = null)
1496: {
1497: $extra = array_filter(['on' => $when, 'message' => $message]);
1498:
1499: return $this->add($field, 'localizedTime', $extra + [
1500: 'rule' => ['localizedTime', $type]
1501: ]);
1502: }
1503:
1504: /**
1505: * Add a boolean validation rule to a field.
1506: *
1507: * @param string $field The field you want to apply the rule to.
1508: * @param string|null $message The error message when the rule fails.
1509: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1510: * true when the validation rule should be applied.
1511: * @see \Cake\Validation\Validation::boolean()
1512: * @return $this
1513: */
1514: public function boolean($field, $message = null, $when = null)
1515: {
1516: $extra = array_filter(['on' => $when, 'message' => $message]);
1517:
1518: return $this->add($field, 'boolean', $extra + [
1519: 'rule' => 'boolean'
1520: ]);
1521: }
1522:
1523: /**
1524: * Add a decimal validation rule to a field.
1525: *
1526: * @param string $field The field you want to apply the rule to.
1527: * @param int|null $places The number of decimal places to require.
1528: * @param string|null $message The error message when the rule fails.
1529: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1530: * true when the validation rule should be applied.
1531: * @see \Cake\Validation\Validation::decimal()
1532: * @return $this
1533: */
1534: public function decimal($field, $places = null, $message = null, $when = null)
1535: {
1536: $extra = array_filter(['on' => $when, 'message' => $message]);
1537:
1538: return $this->add($field, 'decimal', $extra + [
1539: 'rule' => ['decimal', $places]
1540: ]);
1541: }
1542:
1543: /**
1544: * Add an email validation rule to a field.
1545: *
1546: * @param string $field The field you want to apply the rule to.
1547: * @param bool $checkMX Whether or not to check the MX records.
1548: * @param string|null $message The error message when the rule fails.
1549: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1550: * true when the validation rule should be applied.
1551: * @see \Cake\Validation\Validation::email()
1552: * @return $this
1553: */
1554: public function email($field, $checkMX = false, $message = null, $when = null)
1555: {
1556: $extra = array_filter(['on' => $when, 'message' => $message]);
1557:
1558: return $this->add($field, 'email', $extra + [
1559: 'rule' => ['email', $checkMX]
1560: ]);
1561: }
1562:
1563: /**
1564: * Add an IP validation rule to a field.
1565: *
1566: * This rule will accept both IPv4 and IPv6 addresses.
1567: *
1568: * @param string $field The field you want to apply the rule to.
1569: * @param string|null $message The error message when the rule fails.
1570: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1571: * true when the validation rule should be applied.
1572: * @see \Cake\Validation\Validation::ip()
1573: * @return $this
1574: */
1575: public function ip($field, $message = null, $when = null)
1576: {
1577: $extra = array_filter(['on' => $when, 'message' => $message]);
1578:
1579: return $this->add($field, 'ip', $extra + [
1580: 'rule' => 'ip'
1581: ]);
1582: }
1583:
1584: /**
1585: * Add an IPv4 validation rule to a field.
1586: *
1587: * @param string $field The field you want to apply the rule to.
1588: * @param string|null $message The error message when the rule fails.
1589: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1590: * true when the validation rule should be applied.
1591: * @see \Cake\Validation\Validation::ip()
1592: * @return $this
1593: */
1594: public function ipv4($field, $message = null, $when = null)
1595: {
1596: $extra = array_filter(['on' => $when, 'message' => $message]);
1597:
1598: return $this->add($field, 'ipv4', $extra + [
1599: 'rule' => ['ip', 'ipv4']
1600: ]);
1601: }
1602:
1603: /**
1604: * Add an IPv6 validation rule to a field.
1605: *
1606: * @param string $field The field you want to apply the rule to.
1607: * @param string|null $message The error message when the rule fails.
1608: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1609: * true when the validation rule should be applied.
1610: * @see \Cake\Validation\Validation::ip()
1611: * @return $this
1612: */
1613: public function ipv6($field, $message = null, $when = null)
1614: {
1615: $extra = array_filter(['on' => $when, 'message' => $message]);
1616:
1617: return $this->add($field, 'ipv6', $extra + [
1618: 'rule' => ['ip', 'ipv6']
1619: ]);
1620: }
1621:
1622: /**
1623: * Add a string length validation rule to a field.
1624: *
1625: * @param string $field The field you want to apply the rule to.
1626: * @param int $min The minimum length required.
1627: * @param string|null $message The error message when the rule fails.
1628: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1629: * true when the validation rule should be applied.
1630: * @see \Cake\Validation\Validation::minLength()
1631: * @return $this
1632: */
1633: public function minLength($field, $min, $message = null, $when = null)
1634: {
1635: $extra = array_filter(['on' => $when, 'message' => $message]);
1636:
1637: return $this->add($field, 'minLength', $extra + [
1638: 'rule' => ['minLength', $min]
1639: ]);
1640: }
1641:
1642: /**
1643: * Add a string length validation rule to a field.
1644: *
1645: * @param string $field The field you want to apply the rule to.
1646: * @param int $min The minimum length required.
1647: * @param string|null $message The error message when the rule fails.
1648: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1649: * true when the validation rule should be applied.
1650: * @see \Cake\Validation\Validation::minLengthBytes()
1651: * @return $this
1652: */
1653: public function minLengthBytes($field, $min, $message = null, $when = null)
1654: {
1655: $extra = array_filter(['on' => $when, 'message' => $message]);
1656:
1657: return $this->add($field, 'minLengthBytes', $extra + [
1658: 'rule' => ['minLengthBytes', $min]
1659: ]);
1660: }
1661:
1662: /**
1663: * Add a string length validation rule to a field.
1664: *
1665: * @param string $field The field you want to apply the rule to.
1666: * @param int $max The maximum length allowed.
1667: * @param string|null $message The error message when the rule fails.
1668: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1669: * true when the validation rule should be applied.
1670: * @see \Cake\Validation\Validation::maxLength()
1671: * @return $this
1672: */
1673: public function maxLength($field, $max, $message = null, $when = null)
1674: {
1675: $extra = array_filter(['on' => $when, 'message' => $message]);
1676:
1677: return $this->add($field, 'maxLength', $extra + [
1678: 'rule' => ['maxLength', $max]
1679: ]);
1680: }
1681:
1682: /**
1683: * Add a string length validation rule to a field.
1684: *
1685: * @param string $field The field you want to apply the rule to.
1686: * @param int $max The maximum length allowed.
1687: * @param string|null $message The error message when the rule fails.
1688: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1689: * true when the validation rule should be applied.
1690: * @see \Cake\Validation\Validation::maxLengthBytes()
1691: * @return $this
1692: */
1693: public function maxLengthBytes($field, $max, $message = null, $when = null)
1694: {
1695: $extra = array_filter(['on' => $when, 'message' => $message]);
1696:
1697: return $this->add($field, 'maxLengthBytes', $extra + [
1698: 'rule' => ['maxLengthBytes', $max]
1699: ]);
1700: }
1701:
1702: /**
1703: * Add a numeric value validation rule to a field.
1704: *
1705: * @param string $field The field you want to apply the rule to.
1706: * @param string|null $message The error message when the rule fails.
1707: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1708: * true when the validation rule should be applied.
1709: * @see \Cake\Validation\Validation::numeric()
1710: * @return $this
1711: */
1712: public function numeric($field, $message = null, $when = null)
1713: {
1714: $extra = array_filter(['on' => $when, 'message' => $message]);
1715:
1716: return $this->add($field, 'numeric', $extra + [
1717: 'rule' => 'numeric'
1718: ]);
1719: }
1720:
1721: /**
1722: * Add a natural number validation rule to a field.
1723: *
1724: * @param string $field The field you want to apply the rule to.
1725: * @param string|null $message The error message when the rule fails.
1726: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1727: * true when the validation rule should be applied.
1728: * @see \Cake\Validation\Validation::naturalNumber()
1729: * @return $this
1730: */
1731: public function naturalNumber($field, $message = null, $when = null)
1732: {
1733: $extra = array_filter(['on' => $when, 'message' => $message]);
1734:
1735: return $this->add($field, 'naturalNumber', $extra + [
1736: 'rule' => ['naturalNumber', false]
1737: ]);
1738: }
1739:
1740: /**
1741: * Add a validation rule to ensure a field is a non negative integer.
1742: *
1743: * @param string $field The field you want to apply the rule to.
1744: * @param string|null $message The error message when the rule fails.
1745: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1746: * true when the validation rule should be applied.
1747: * @see \Cake\Validation\Validation::naturalNumber()
1748: * @return $this
1749: */
1750: public function nonNegativeInteger($field, $message = null, $when = null)
1751: {
1752: $extra = array_filter(['on' => $when, 'message' => $message]);
1753:
1754: return $this->add($field, 'nonNegativeInteger', $extra + [
1755: 'rule' => ['naturalNumber', true]
1756: ]);
1757: }
1758:
1759: /**
1760: * Add a validation rule to ensure a field is within a numeric range
1761: *
1762: * @param string $field The field you want to apply the rule to.
1763: * @param array $range The inclusive upper and lower bounds of the valid range.
1764: * @param string|null $message The error message when the rule fails.
1765: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1766: * true when the validation rule should be applied.
1767: * @see \Cake\Validation\Validation::range()
1768: * @return $this
1769: */
1770: public function range($field, array $range, $message = null, $when = null)
1771: {
1772: if (count($range) !== 2) {
1773: throw new InvalidArgumentException('The $range argument requires 2 numbers');
1774: }
1775: $extra = array_filter(['on' => $when, 'message' => $message]);
1776:
1777: return $this->add($field, 'range', $extra + [
1778: 'rule' => ['range', array_shift($range), array_shift($range)]
1779: ]);
1780: }
1781:
1782: /**
1783: * Add a validation rule to ensure a field is a URL.
1784: *
1785: * This validator does not require a protocol.
1786: *
1787: * @param string $field The field you want to apply the rule to.
1788: * @param string|null $message The error message when the rule fails.
1789: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1790: * true when the validation rule should be applied.
1791: * @see \Cake\Validation\Validation::url()
1792: * @return $this
1793: */
1794: public function url($field, $message = null, $when = null)
1795: {
1796: $extra = array_filter(['on' => $when, 'message' => $message]);
1797:
1798: return $this->add($field, 'url', $extra + [
1799: 'rule' => ['url', false]
1800: ]);
1801: }
1802:
1803: /**
1804: * Add a validation rule to ensure a field is a URL.
1805: *
1806: * This validator requires the URL to have a protocol.
1807: *
1808: * @param string $field The field you want to apply the rule to.
1809: * @param string|null $message The error message when the rule fails.
1810: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1811: * true when the validation rule should be applied.
1812: * @see \Cake\Validation\Validation::url()
1813: * @return $this
1814: */
1815: public function urlWithProtocol($field, $message = null, $when = null)
1816: {
1817: $extra = array_filter(['on' => $when, 'message' => $message]);
1818:
1819: return $this->add($field, 'urlWithProtocol', $extra + [
1820: 'rule' => ['url', true]
1821: ]);
1822: }
1823:
1824: /**
1825: * Add a validation rule to ensure the field value is within a whitelist.
1826: *
1827: * @param string $field The field you want to apply the rule to.
1828: * @param array $list The list of valid options.
1829: * @param string|null $message The error message when the rule fails.
1830: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1831: * true when the validation rule should be applied.
1832: * @see \Cake\Validation\Validation::inList()
1833: * @return $this
1834: */
1835: public function inList($field, array $list, $message = null, $when = null)
1836: {
1837: $extra = array_filter(['on' => $when, 'message' => $message]);
1838:
1839: return $this->add($field, 'inList', $extra + [
1840: 'rule' => ['inList', $list]
1841: ]);
1842: }
1843:
1844: /**
1845: * Add a validation rule to ensure the field is a UUID
1846: *
1847: * @param string $field The field you want to apply the rule to.
1848: * @param string|null $message The error message when the rule fails.
1849: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1850: * true when the validation rule should be applied.
1851: * @see \Cake\Validation\Validation::uuid()
1852: * @return $this
1853: */
1854: public function uuid($field, $message = null, $when = null)
1855: {
1856: $extra = array_filter(['on' => $when, 'message' => $message]);
1857:
1858: return $this->add($field, 'uuid', $extra + [
1859: 'rule' => 'uuid'
1860: ]);
1861: }
1862:
1863: /**
1864: * Add a validation rule to ensure the field is an uploaded file
1865: *
1866: * For options see Cake\Validation\Validation::uploadedFile()
1867: *
1868: * @param string $field The field you want to apply the rule to.
1869: * @param array $options An array of options.
1870: * @param string|null $message The error message when the rule fails.
1871: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1872: * true when the validation rule should be applied.
1873: * @see \Cake\Validation\Validation::uploadedFile()
1874: * @return $this
1875: */
1876: public function uploadedFile($field, array $options, $message = null, $when = null)
1877: {
1878: $extra = array_filter(['on' => $when, 'message' => $message]);
1879:
1880: return $this->add($field, 'uploadedFile', $extra + [
1881: 'rule' => ['uploadedFile', $options]
1882: ]);
1883: }
1884:
1885: /**
1886: * Add a validation rule to ensure the field is a lat/long tuple.
1887: *
1888: * e.g. `<lat>, <lng>`
1889: *
1890: * @param string $field The field you want to apply the rule to.
1891: * @param string|null $message The error message when the rule fails.
1892: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1893: * true when the validation rule should be applied.
1894: * @see \Cake\Validation\Validation::uuid()
1895: * @return $this
1896: */
1897: public function latLong($field, $message = null, $when = null)
1898: {
1899: $extra = array_filter(['on' => $when, 'message' => $message]);
1900:
1901: return $this->add($field, 'latLong', $extra + [
1902: 'rule' => 'geoCoordinate'
1903: ]);
1904: }
1905:
1906: /**
1907: * Add a validation rule to ensure the field is a latitude.
1908: *
1909: * @param string $field The field you want to apply the rule to.
1910: * @param string|null $message The error message when the rule fails.
1911: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1912: * true when the validation rule should be applied.
1913: * @see \Cake\Validation\Validation::latitude()
1914: * @return $this
1915: */
1916: public function latitude($field, $message = null, $when = null)
1917: {
1918: $extra = array_filter(['on' => $when, 'message' => $message]);
1919:
1920: return $this->add($field, 'latitude', $extra + [
1921: 'rule' => 'latitude'
1922: ]);
1923: }
1924:
1925: /**
1926: * Add a validation rule to ensure the field is a longitude.
1927: *
1928: * @param string $field The field you want to apply the rule to.
1929: * @param string|null $message The error message when the rule fails.
1930: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1931: * true when the validation rule should be applied.
1932: * @see \Cake\Validation\Validation::longitude()
1933: * @return $this
1934: */
1935: public function longitude($field, $message = null, $when = null)
1936: {
1937: $extra = array_filter(['on' => $when, 'message' => $message]);
1938:
1939: return $this->add($field, 'longitude', $extra + [
1940: 'rule' => 'longitude'
1941: ]);
1942: }
1943:
1944: /**
1945: * Add a validation rule to ensure a field contains only ascii bytes
1946: *
1947: * @param string $field The field you want to apply the rule to.
1948: * @param string|null $message The error message when the rule fails.
1949: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1950: * true when the validation rule should be applied.
1951: * @see \Cake\Validation\Validation::ascii()
1952: * @return $this
1953: */
1954: public function ascii($field, $message = null, $when = null)
1955: {
1956: $extra = array_filter(['on' => $when, 'message' => $message]);
1957:
1958: return $this->add($field, 'ascii', $extra + [
1959: 'rule' => 'ascii'
1960: ]);
1961: }
1962:
1963: /**
1964: * Add a validation rule to ensure a field contains only BMP utf8 bytes
1965: *
1966: * @param string $field The field you want to apply the rule to.
1967: * @param string|null $message The error message when the rule fails.
1968: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1969: * true when the validation rule should be applied.
1970: * @see \Cake\Validation\Validation::utf8()
1971: * @return $this
1972: */
1973: public function utf8($field, $message = null, $when = null)
1974: {
1975: $extra = array_filter(['on' => $when, 'message' => $message]);
1976:
1977: return $this->add($field, 'utf8', $extra + [
1978: 'rule' => ['utf8', ['extended' => false]]
1979: ]);
1980: }
1981:
1982: /**
1983: * Add a validation rule to ensure a field contains only utf8 bytes.
1984: *
1985: * This rule will accept 3 and 4 byte UTF8 sequences, which are necessary for emoji.
1986: *
1987: * @param string $field The field you want to apply the rule to.
1988: * @param string|null $message The error message when the rule fails.
1989: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
1990: * true when the validation rule should be applied.
1991: * @see \Cake\Validation\Validation::utf8()
1992: * @return $this
1993: */
1994: public function utf8Extended($field, $message = null, $when = null)
1995: {
1996: $extra = array_filter(['on' => $when, 'message' => $message]);
1997:
1998: return $this->add($field, 'utf8Extended', $extra + [
1999: 'rule' => ['utf8', ['extended' => true]]
2000: ]);
2001: }
2002:
2003: /**
2004: * Add a validation rule to ensure a field is an integer value.
2005: *
2006: * @param string $field The field you want to apply the rule to.
2007: * @param string|null $message The error message when the rule fails.
2008: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
2009: * true when the validation rule should be applied.
2010: * @see \Cake\Validation\Validation::isInteger()
2011: * @return $this
2012: */
2013: public function integer($field, $message = null, $when = null)
2014: {
2015: $extra = array_filter(['on' => $when, 'message' => $message]);
2016:
2017: return $this->add($field, 'integer', $extra + [
2018: 'rule' => 'isInteger'
2019: ]);
2020: }
2021:
2022: /**
2023: * Add a validation rule to ensure that a field contains an array.
2024: *
2025: * @param string $field The field you want to apply the rule to.
2026: * @param string|null $message The error message when the rule fails.
2027: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
2028: * true when the validation rule should be applied.
2029: * @see \Cake\Validation\Validation::isArray()
2030: * @return $this
2031: */
2032: public function isArray($field, $message = null, $when = null)
2033: {
2034: $extra = array_filter(['on' => $when, 'message' => $message]);
2035:
2036: return $this->add($field, 'isArray', $extra + [
2037: 'rule' => 'isArray'
2038: ]);
2039: }
2040:
2041: /**
2042: * Add a validation rule to ensure that a field contains a scalar.
2043: *
2044: * @param string $field The field you want to apply the rule to.
2045: * @param string|null $message The error message when the rule fails.
2046: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
2047: * true when the validation rule should be applied.
2048: * @see \Cake\Validation\Validation::isScalar()
2049: * @return $this
2050: */
2051: public function scalar($field, $message = null, $when = null)
2052: {
2053: $extra = array_filter(['on' => $when, 'message' => $message]);
2054:
2055: return $this->add($field, 'scalar', $extra + [
2056: 'rule' => 'isScalar'
2057: ]);
2058: }
2059:
2060: /**
2061: * Add a validation rule to ensure a field is a 6 digits hex color value.
2062: *
2063: * @param string $field The field you want to apply the rule to.
2064: * @param string|null $message The error message when the rule fails.
2065: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
2066: * true when the validation rule should be applied.
2067: * @see \Cake\Validation\Validation::hexColor()
2068: * @return $this
2069: */
2070: public function hexColor($field, $message = null, $when = null)
2071: {
2072: $extra = array_filter(['on' => $when, 'message' => $message]);
2073:
2074: return $this->add($field, 'hexColor', $extra + [
2075: 'rule' => 'hexColor',
2076: ]);
2077: }
2078:
2079: /**
2080: * Add a validation rule for a multiple select. Comparison is case sensitive by default.
2081: *
2082: * @param string $field The field you want to apply the rule to.
2083: * @param array $options The options for the validator. Includes the options defined in
2084: * \Cake\Validation\Validation::multiple() and the `caseInsensitive` parameter.
2085: * @param string|null $message The error message when the rule fails.
2086: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
2087: * true when the validation rule should be applied.
2088: * @see \Cake\Validation\Validation::multiple()
2089: * @return $this
2090: */
2091: public function multipleOptions($field, array $options = [], $message = null, $when = null)
2092: {
2093: $extra = array_filter(['on' => $when, 'message' => $message]);
2094: $caseInsensitive = isset($options['caseInsensitive']) ? $options['caseInsensitive'] : false;
2095: unset($options['caseInsensitive']);
2096:
2097: return $this->add($field, 'multipleOptions', $extra + [
2098: 'rule' => ['multiple', $options, $caseInsensitive]
2099: ]);
2100: }
2101:
2102: /**
2103: * Add a validation rule to ensure that a field is an array containing at least
2104: * the specified amount of elements
2105: *
2106: * @param string $field The field you want to apply the rule to.
2107: * @param int $count The number of elements the array should at least have
2108: * @param string|null $message The error message when the rule fails.
2109: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
2110: * true when the validation rule should be applied.
2111: * @see \Cake\Validation\Validation::numElements()
2112: * @return $this
2113: */
2114: public function hasAtLeast($field, $count, $message = null, $when = null)
2115: {
2116: $extra = array_filter(['on' => $when, 'message' => $message]);
2117:
2118: return $this->add($field, 'hasAtLeast', $extra + [
2119: 'rule' => function ($value) use ($count) {
2120: if (is_array($value) && isset($value['_ids'])) {
2121: $value = $value['_ids'];
2122: }
2123:
2124: return Validation::numElements($value, Validation::COMPARE_GREATER_OR_EQUAL, $count);
2125: }
2126: ]);
2127: }
2128:
2129: /**
2130: * Add a validation rule to ensure that a field is an array containing at most
2131: * the specified amount of elements
2132: *
2133: * @param string $field The field you want to apply the rule to.
2134: * @param int $count The number maximum amount of elements the field should have
2135: * @param string|null $message The error message when the rule fails.
2136: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
2137: * true when the validation rule should be applied.
2138: * @see \Cake\Validation\Validation::numElements()
2139: * @return $this
2140: */
2141: public function hasAtMost($field, $count, $message = null, $when = null)
2142: {
2143: $extra = array_filter(['on' => $when, 'message' => $message]);
2144:
2145: return $this->add($field, 'hasAtMost', $extra + [
2146: 'rule' => function ($value) use ($count) {
2147: if (is_array($value) && isset($value['_ids'])) {
2148: $value = $value['_ids'];
2149: }
2150:
2151: return Validation::numElements($value, Validation::COMPARE_LESS_OR_EQUAL, $count);
2152: }
2153: ]);
2154: }
2155:
2156: /**
2157: * Returns whether or not a field can be left empty for a new or already existing
2158: * record.
2159: *
2160: * @param string $field Field name.
2161: * @param bool $newRecord whether the data to be validated is new or to be updated.
2162: * @return bool
2163: */
2164: public function isEmptyAllowed($field, $newRecord)
2165: {
2166: $providers = $this->_providers;
2167: $data = [];
2168: $context = compact('data', 'newRecord', 'field', 'providers');
2169:
2170: return $this->_canBeEmpty($this->field($field), $context);
2171: }
2172:
2173: /**
2174: * Returns whether or not a field can be left out for a new or already existing
2175: * record.
2176: *
2177: * @param string $field Field name.
2178: * @param bool $newRecord Whether the data to be validated is new or to be updated.
2179: * @return bool
2180: */
2181: public function isPresenceRequired($field, $newRecord)
2182: {
2183: $providers = $this->_providers;
2184: $data = [];
2185: $context = compact('data', 'newRecord', 'field', 'providers');
2186:
2187: return !$this->_checkPresence($this->field($field), $context);
2188: }
2189:
2190: /**
2191: * Returns whether or not a field matches against a regular expression.
2192: *
2193: * @param string $field Field name.
2194: * @param string $regex Regular expression.
2195: * @param string|null $message The error message when the rule fails.
2196: * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
2197: * true when the validation rule should be applied.
2198: * @return $this
2199: */
2200: public function regex($field, $regex, $message = null, $when = null)
2201: {
2202: $extra = array_filter(['on' => $when, 'message' => $message]);
2203:
2204: return $this->add($field, 'regex', $extra + [
2205: 'rule' => ['custom', $regex]
2206: ]);
2207: }
2208:
2209: /**
2210: * Gets the required message for a field
2211: *
2212: * @param string $field Field name
2213: * @return string|null
2214: */
2215: public function getRequiredMessage($field)
2216: {
2217: if (!isset($this->_fields[$field])) {
2218: return null;
2219: }
2220:
2221: $defaultMessage = 'This field is required';
2222: if ($this->_useI18n) {
2223: $defaultMessage = __d('cake', 'This field is required');
2224: }
2225:
2226: return isset($this->_presenceMessages[$field])
2227: ? $this->_presenceMessages[$field]
2228: : $defaultMessage;
2229: }
2230:
2231: /**
2232: * Gets the notEmpty message for a field
2233: *
2234: * @param string $field Field name
2235: * @return string|null
2236: */
2237: public function getNotEmptyMessage($field)
2238: {
2239: if (!isset($this->_fields[$field])) {
2240: return null;
2241: }
2242:
2243: $defaultMessage = 'This field cannot be left empty';
2244: if ($this->_useI18n) {
2245: $defaultMessage = __d('cake', 'This field cannot be left empty');
2246: }
2247:
2248: $notBlankMessage = null;
2249: foreach ($this->_fields[$field] as $rule) {
2250: if ($rule->get('rule') === 'notBlank' && $rule->get('message')) {
2251: return $rule->get('message');
2252: }
2253: }
2254:
2255: return isset($this->_allowEmptyMessages[$field])
2256: ? $this->_allowEmptyMessages[$field]
2257: : $defaultMessage;
2258: }
2259:
2260: /**
2261: * Returns false if any validation for the passed rule set should be stopped
2262: * due to the field missing in the data array
2263: *
2264: * @param \Cake\Validation\ValidationSet $field The set of rules for a field.
2265: * @param array $context A key value list of data containing the validation context.
2266: * @return bool
2267: */
2268: protected function _checkPresence($field, $context)
2269: {
2270: $required = $field->isPresenceRequired();
2271:
2272: if (!is_string($required) && is_callable($required)) {
2273: return !$required($context);
2274: }
2275:
2276: $newRecord = $context['newRecord'];
2277: if (in_array($required, ['create', 'update'], true)) {
2278: return (
2279: ($required === 'create' && !$newRecord) ||
2280: ($required === 'update' && $newRecord)
2281: );
2282: }
2283:
2284: return !$required;
2285: }
2286:
2287: /**
2288: * Returns whether the field can be left blank according to `allowEmpty`
2289: *
2290: * @param \Cake\Validation\ValidationSet $field the set of rules for a field
2291: * @param array $context a key value list of data containing the validation context.
2292: * @return bool
2293: */
2294: protected function _canBeEmpty($field, $context)
2295: {
2296: $allowed = $field->isEmptyAllowed();
2297:
2298: if (!is_string($allowed) && is_callable($allowed)) {
2299: return $allowed($context);
2300: }
2301:
2302: $newRecord = $context['newRecord'];
2303: if (in_array($allowed, ['create', 'update'], true)) {
2304: $allowed = (
2305: ($allowed === 'create' && $newRecord) ||
2306: ($allowed === 'update' && !$newRecord)
2307: );
2308: }
2309:
2310: return $allowed;
2311: }
2312:
2313: /**
2314: * Returns true if the field is empty in the passed data array
2315: *
2316: * @param mixed $data Value to check against.
2317: * @return bool
2318: * @deprecated 3.7.0 Use isEmpty() instead
2319: */
2320: protected function _fieldIsEmpty($data)
2321: {
2322: return $this->isEmpty($data, static::EMPTY_ALL);
2323: }
2324:
2325: /**
2326: * Returns true if the field is empty in the passed data array
2327: *
2328: * @param mixed $data Value to check against.
2329: * @param int $flags A bitmask of EMPTY_* flags which specify what is empty
2330: * @return bool
2331: */
2332: protected function isEmpty($data, $flags)
2333: {
2334: if ($data === null) {
2335: return true;
2336: }
2337:
2338: if ($data === '' && ($flags & self::EMPTY_STRING)) {
2339: return true;
2340: }
2341:
2342: $arrayTypes = self::EMPTY_ARRAY | self::EMPTY_DATE | self::EMPTY_TIME;
2343: if ($data === [] && ($flags & $arrayTypes)) {
2344: return true;
2345: }
2346:
2347: if (is_array($data)) {
2348: if (($flags & self::EMPTY_FILE)
2349: && isset($data['name'], $data['type'], $data['tmp_name'], $data['error'])
2350: && (int)$data['error'] === UPLOAD_ERR_NO_FILE
2351: ) {
2352: return true;
2353: }
2354:
2355: $allFieldsAreEmpty = true;
2356: foreach ($data as $field) {
2357: if ($field !== null && $field !== '') {
2358: $allFieldsAreEmpty = false;
2359: break;
2360: }
2361: }
2362:
2363: if ($allFieldsAreEmpty) {
2364: if (($flags & self::EMPTY_DATE) && isset($data['year'])) {
2365: return true;
2366: }
2367:
2368: if (($flags & self::EMPTY_TIME) && isset($data['hour'])) {
2369: return true;
2370: }
2371: }
2372: }
2373:
2374: return false;
2375: }
2376:
2377: /**
2378: * Iterates over each rule in the validation set and collects the errors resulting
2379: * from executing them
2380: *
2381: * @param string $field The name of the field that is being processed
2382: * @param \Cake\Validation\ValidationSet $rules the list of rules for a field
2383: * @param array $data the full data passed to the validator
2384: * @param bool $newRecord whether is it a new record or an existing one
2385: * @return array
2386: */
2387: protected function _processRules($field, ValidationSet $rules, $data, $newRecord)
2388: {
2389: $errors = [];
2390: // Loading default provider in case there is none
2391: $this->getProvider('default');
2392: $message = 'The provided value is invalid';
2393:
2394: if ($this->_useI18n) {
2395: $message = __d('cake', 'The provided value is invalid');
2396: }
2397:
2398: foreach ($rules as $name => $rule) {
2399: $result = $rule->process($data[$field], $this->_providers, compact('newRecord', 'data', 'field'));
2400: if ($result === true) {
2401: continue;
2402: }
2403:
2404: $errors[$name] = $message;
2405: if (is_array($result) && $name === static::NESTED) {
2406: $errors = $result;
2407: }
2408: if (is_string($result)) {
2409: $errors[$name] = $result;
2410: }
2411:
2412: if ($rule->isLast()) {
2413: break;
2414: }
2415: }
2416:
2417: return $errors;
2418: }
2419:
2420: /**
2421: * Get the printable version of this object.
2422: *
2423: * @return array
2424: */
2425: public function __debugInfo()
2426: {
2427: $fields = [];
2428: foreach ($this->_fields as $name => $fieldSet) {
2429: $fields[$name] = [
2430: 'isPresenceRequired' => $fieldSet->isPresenceRequired(),
2431: 'isEmptyAllowed' => $fieldSet->isEmptyAllowed(),
2432: 'rules' => array_keys($fieldSet->rules()),
2433: ];
2434: }
2435:
2436: return [
2437: '_presenceMessages' => $this->_presenceMessages,
2438: '_allowEmptyMessages' => $this->_allowEmptyMessages,
2439: '_allowEmptyFlags' => $this->_allowEmptyFlags,
2440: '_useI18n' => $this->_useI18n,
2441: '_providers' => array_keys($this->_providers),
2442: '_fields' => $fields
2443: ];
2444: }
2445: }
2446: