CakeValidationSet.php 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. <?php
  2. /**
  3. * CakeValidationSet.
  4. *
  5. * Provides the Model validation logic.
  6. *
  7. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  8. * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  9. *
  10. * Licensed under The MIT License
  11. * For full copyright and license information, please see the LICENSE.txt
  12. * Redistributions of files must retain the above copyright notice.
  13. *
  14. * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  15. * @link http://cakephp.org CakePHP(tm) Project
  16. * @package Cake.Model.Validator
  17. * @since CakePHP(tm) v 2.2.0
  18. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  19. */
  20. App::uses('CakeValidationRule', 'Model/Validator');
  21. /**
  22. * CakeValidationSet object. Holds all validation rules for a field and exposes
  23. * methods to dynamically add or remove validation rules
  24. *
  25. * @package Cake.Model.Validator
  26. * @link http://book.cakephp.org/2.0/en/data-validation.html
  27. */
  28. class CakeValidationSet implements ArrayAccess, IteratorAggregate, Countable {
  29. /**
  30. * Holds the CakeValidationRule objects
  31. *
  32. * @var array
  33. */
  34. protected $_rules = array();
  35. /**
  36. * List of methods available for validation
  37. *
  38. * @var array
  39. */
  40. protected $_methods = array();
  41. /**
  42. * I18n domain for validation messages.
  43. *
  44. * @var string
  45. */
  46. protected $_validationDomain = null;
  47. /**
  48. * Whether the validation is stopped
  49. *
  50. * @var boolean
  51. */
  52. public $isStopped = false;
  53. /**
  54. * Holds the fieldname
  55. *
  56. * @var string
  57. */
  58. public $field = null;
  59. /**
  60. * Holds the original ruleSet
  61. *
  62. * @var array
  63. */
  64. public $ruleSet = array();
  65. /**
  66. * Constructor
  67. *
  68. * @param string $fieldName The fieldname
  69. * @param array $ruleset
  70. */
  71. public function __construct($fieldName, $ruleSet) {
  72. $this->field = $fieldName;
  73. if (!is_array($ruleSet) || (is_array($ruleSet) && isset($ruleSet['rule']))) {
  74. $ruleSet = array($ruleSet);
  75. }
  76. foreach ($ruleSet as $index => $validateProp) {
  77. $this->_rules[$index] = new CakeValidationRule($validateProp);
  78. }
  79. $this->ruleSet = $ruleSet;
  80. }
  81. /**
  82. * Sets the list of methods to use for validation
  83. *
  84. * @param array $methods Methods list
  85. * @return void
  86. */
  87. public function setMethods(&$methods) {
  88. $this->_methods =& $methods;
  89. }
  90. /**
  91. * Sets the I18n domain for validation messages.
  92. *
  93. * @param string $validationDomain The validation domain to be used.
  94. * @return void
  95. */
  96. public function setValidationDomain($validationDomain) {
  97. $this->_validationDomain = $validationDomain;
  98. }
  99. /**
  100. * Runs all validation rules in this set and returns a list of
  101. * validation errors
  102. *
  103. * @param array $data Data array
  104. * @param boolean $isUpdate Is record being updated or created
  105. * @return array list of validation errors for this field
  106. */
  107. public function validate($data, $isUpdate = false) {
  108. $this->reset();
  109. $errors = array();
  110. foreach ($this->getRules() as $name => $rule) {
  111. $rule->isUpdate($isUpdate);
  112. if ($rule->skip()) {
  113. continue;
  114. }
  115. $checkRequired = $rule->checkRequired($this->field, $data);
  116. if (!$checkRequired && array_key_exists($this->field, $data)) {
  117. if ($rule->checkEmpty($this->field, $data)) {
  118. break;
  119. }
  120. $rule->process($this->field, $data, $this->_methods);
  121. }
  122. if ($checkRequired || !$rule->isValid()) {
  123. $errors[] = $this->_processValidationResponse($name, $rule);
  124. if ($rule->isLast()) {
  125. break;
  126. }
  127. }
  128. }
  129. return $errors;
  130. }
  131. /**
  132. * Resets internal state for all validation rules in this set
  133. *
  134. * @return void
  135. */
  136. public function reset() {
  137. foreach ($this->getRules() as $rule) {
  138. $rule->reset();
  139. }
  140. }
  141. /**
  142. * Gets a rule for a given name if exists
  143. *
  144. * @param string $name
  145. * @return CakeValidationRule
  146. */
  147. public function getRule($name) {
  148. if (!empty($this->_rules[$name])) {
  149. return $this->_rules[$name];
  150. }
  151. }
  152. /**
  153. * Returns all rules for this validation set
  154. *
  155. * @return array
  156. */
  157. public function getRules() {
  158. return $this->_rules;
  159. }
  160. /**
  161. * Sets a CakeValidationRule $rule with a $name
  162. *
  163. * ## Example:
  164. *
  165. * {{{
  166. * $set
  167. * ->setRule('required', array('rule' => 'notEmpty', 'required' => true))
  168. * ->setRule('inRange', array('rule' => array('between', 4, 10))
  169. * }}}
  170. *
  171. * @param string $name The name under which the rule should be set
  172. * @param CakeValidationRule|array $rule The validation rule to be set
  173. * @return CakeValidationSet this instance
  174. */
  175. public function setRule($name, $rule) {
  176. if (!($rule instanceof CakeValidationRule)) {
  177. $rule = new CakeValidationRule($rule);
  178. }
  179. $this->_rules[$name] = $rule;
  180. return $this;
  181. }
  182. /**
  183. * Removes a validation rule from the set
  184. *
  185. * ## Example:
  186. *
  187. * {{{
  188. * $set
  189. * ->removeRule('required')
  190. * ->removeRule('inRange')
  191. * }}}
  192. *
  193. * @param string $name The name under which the rule should be unset
  194. * @return CakeValidationSet this instance
  195. */
  196. public function removeRule($name) {
  197. unset($this->_rules[$name]);
  198. return $this;
  199. }
  200. /**
  201. * Sets the rules for a given field
  202. *
  203. * ## Example:
  204. *
  205. * {{{
  206. * $set->setRules(array(
  207. * 'required' => array('rule' => 'notEmpty', 'required' => true),
  208. * 'inRange' => array('rule' => array('between', 4, 10)
  209. * ));
  210. * }}}
  211. *
  212. * @param array $rules The rules to be set
  213. * @param boolean $mergeVars [optional] If true, merges vars instead of replace. Defaults to true.
  214. * @return ModelField
  215. */
  216. public function setRules($rules = array(), $mergeVars = true) {
  217. if ($mergeVars === false) {
  218. $this->_rules = array();
  219. }
  220. foreach ($rules as $name => $rule) {
  221. $this->setRule($name, $rule);
  222. }
  223. return $this;
  224. }
  225. /**
  226. * Fetches the correct error message for a failed validation
  227. *
  228. * @param string $name the name of the rule as it was configured
  229. * @param CakeValidationRule $rule the object containing validation information
  230. * @return string
  231. */
  232. protected function _processValidationResponse($name, $rule) {
  233. $message = $rule->getValidationResult();
  234. if (is_string($message)) {
  235. return $message;
  236. }
  237. $message = $rule->message;
  238. if ($message !== null) {
  239. $args = null;
  240. if (is_array($message)) {
  241. $result = $message[0];
  242. $args = array_slice($message, 1);
  243. } else {
  244. $result = $message;
  245. }
  246. if (is_array($rule->rule) && $args === null) {
  247. $args = array_slice($rule->rule, 1);
  248. }
  249. $args = $this->_translateArgs($args);
  250. $message = __d($this->_validationDomain, $result, $args);
  251. } elseif (is_string($name)) {
  252. if (is_array($rule->rule)) {
  253. $args = array_slice($rule->rule, 1);
  254. $args = $this->_translateArgs($args);
  255. $message = __d($this->_validationDomain, $name, $args);
  256. } else {
  257. $message = __d($this->_validationDomain, $name);
  258. }
  259. } else {
  260. $message = __d('cake', 'This field cannot be left blank');
  261. }
  262. return $message;
  263. }
  264. /**
  265. * Applies translations to validator arguments.
  266. *
  267. * @param array $args The args to translate
  268. * @return array Translated args.
  269. */
  270. protected function _translateArgs($args) {
  271. foreach ((array)$args as $k => $arg) {
  272. if (is_string($arg)) {
  273. $args[$k] = __d($this->_validationDomain, $arg);
  274. }
  275. }
  276. return $args;
  277. }
  278. /**
  279. * Returns whether an index exists in the rule set
  280. *
  281. * @param string $index name of the rule
  282. * @return boolean
  283. */
  284. public function offsetExists($index) {
  285. return isset($this->_rules[$index]);
  286. }
  287. /**
  288. * Returns a rule object by its index
  289. *
  290. * @param string $index name of the rule
  291. * @return CakeValidationRule
  292. */
  293. public function offsetGet($index) {
  294. return $this->_rules[$index];
  295. }
  296. /**
  297. * Sets or replace a validation rule
  298. *
  299. * @param string $index name of the rule
  300. * @param CakeValidationRule|array rule to add to $index
  301. * @return void
  302. */
  303. public function offsetSet($index, $rule) {
  304. $this->setRule($index, $rule);
  305. }
  306. /**
  307. * Unsets a validation rule
  308. *
  309. * @param string $index name of the rule
  310. * @return void
  311. */
  312. public function offsetUnset($index) {
  313. unset($this->_rules[$index]);
  314. }
  315. /**
  316. * Returns an iterator for each of the rules to be applied
  317. *
  318. * @return ArrayIterator
  319. */
  320. public function getIterator() {
  321. return new ArrayIterator($this->_rules);
  322. }
  323. /**
  324. * Returns the number of rules in this set
  325. *
  326. * @return integer
  327. */
  328. public function count() {
  329. return count($this->_rules);
  330. }
  331. }