PageRenderTime 37ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/src/Validation/Validator.php

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