sfValidatorBase.class.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  1. <?php
  2. /*
  3. * This file is part of the symfony package.
  4. * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
  5. *
  6. * For the full copyright and license information, please view the LICENSE
  7. * file that was distributed with this source code.
  8. */
  9. /**
  10. * sfValidatorBase is the base class for all validators.
  11. *
  12. * It also implements the required option for all validators.
  13. *
  14. * @package symfony
  15. * @subpackage validator
  16. * @author Fabien Potencier <fabien.potencier@symfony-project.com>
  17. * @version SVN: $Id: sfValidatorBase.class.php 17473 2009-04-21 07:59:34Z fabien $
  18. */
  19. abstract class sfValidatorBase
  20. {
  21. protected static
  22. $charset = 'UTF-8';
  23. protected
  24. $requiredOptions = array(),
  25. $defaultMessages = array(),
  26. $defaultOptions = array(),
  27. $messages = array(),
  28. $options = array();
  29. /**
  30. * Constructor.
  31. *
  32. * Available options:
  33. *
  34. * * required: true if the value is required, false otherwise (default to true)
  35. * * trim: true if the value must be trimmed, false otherwise (default to false)
  36. * * empty_value: empty value when value is not required
  37. *
  38. * Available error codes:
  39. *
  40. * * required
  41. * * invalid
  42. *
  43. * @param array $options An array of options
  44. * @param array $messages An array of error messages
  45. */
  46. public function __construct($options = array(), $messages = array())
  47. {
  48. $this->options = array_merge(array('required' => true, 'trim' => false, 'empty_value' => null), $this->options);
  49. $this->messages = array_merge(array('required' => 'Required.', 'invalid' => 'Invalid.'), $this->messages);
  50. $this->configure($options, $messages);
  51. $this->setDefaultOptions($this->getOptions());
  52. $this->setDefaultMessages($this->getMessages());
  53. $currentOptionKeys = array_keys($this->options);
  54. $optionKeys = array_keys($options);
  55. // check option names
  56. if ($diff = array_diff($optionKeys, array_merge($currentOptionKeys, $this->requiredOptions)))
  57. {
  58. throw new InvalidArgumentException(sprintf('%s does not support the following options: \'%s\'.', get_class($this), implode('\', \'', $diff)));
  59. }
  60. // check error code names
  61. if ($diff = array_diff(array_keys($messages), array_keys($this->messages)))
  62. {
  63. throw new InvalidArgumentException(sprintf('%s does not support the following error codes: \'%s\'.', get_class($this), implode('\', \'', $diff)));
  64. }
  65. // check required options
  66. if ($diff = array_diff($this->requiredOptions, array_merge($currentOptionKeys, $optionKeys)))
  67. {
  68. throw new RuntimeException(sprintf('%s requires the following options: \'%s\'.', get_class($this), implode('\', \'', $diff)));
  69. }
  70. $this->options = array_merge($this->options, $options);
  71. $this->messages = array_merge($this->messages, $messages);
  72. }
  73. /**
  74. * Configures the current validator.
  75. *
  76. * This method allows each validator to add options and error messages
  77. * during validator creation.
  78. *
  79. * If some options and messages are given in the sfValidatorBase constructor
  80. * they will take precedence over the options and messages you configure
  81. * in this method.
  82. *
  83. * @param array $options An array of options
  84. * @param array $messages An array of error messages
  85. *
  86. * @see __construct()
  87. */
  88. protected function configure($options = array(), $messages = array())
  89. {
  90. }
  91. /**
  92. * Returns an error message given an error code.
  93. *
  94. * @param string $name The error code
  95. *
  96. * @return string The error message, or the empty string if the error code does not exist
  97. */
  98. public function getMessage($name)
  99. {
  100. return isset($this->messages[$name]) ? $this->messages[$name] : '';
  101. }
  102. /**
  103. * Adds a new error code with a default error message.
  104. *
  105. * @param string $name The error code
  106. * @param string $value The error message
  107. */
  108. public function addMessage($name, $value)
  109. {
  110. $this->messages[$name] = $value;
  111. }
  112. /**
  113. * Changes an error message given the error code.
  114. *
  115. * @param string $name The error code
  116. * @param string $value The error message
  117. */
  118. public function setMessage($name, $value)
  119. {
  120. if (!in_array($name, array_keys($this->messages)))
  121. {
  122. throw new InvalidArgumentException(sprintf('%s does not support the following error code: \'%s\'.', get_class($this), $name));
  123. }
  124. $this->messages[$name] = $value;
  125. }
  126. /**
  127. * Returns an array of current error messages.
  128. *
  129. * @return array An array of messages
  130. */
  131. public function getMessages()
  132. {
  133. return $this->messages;
  134. }
  135. /**
  136. * Changes all error messages.
  137. *
  138. * @param array $values An array of error messages
  139. */
  140. public function setMessages($values)
  141. {
  142. $this->messages = $values;
  143. }
  144. /**
  145. * Gets an option value.
  146. *
  147. * @param string $name The option name
  148. *
  149. * @return mixed The option value
  150. */
  151. public function getOption($name)
  152. {
  153. return isset($this->options[$name]) ? $this->options[$name] : null;
  154. }
  155. /**
  156. * Adds a new option value with a default value.
  157. *
  158. * @param string $name The option name
  159. * @param mixed $value The default value
  160. */
  161. public function addOption($name, $value = null)
  162. {
  163. $this->options[$name] = $value;
  164. }
  165. /**
  166. * Changes an option value.
  167. *
  168. * @param string $name The option name
  169. * @param mixed $value The value
  170. */
  171. public function setOption($name, $value)
  172. {
  173. if (!in_array($name, array_merge(array_keys($this->options), $this->requiredOptions)))
  174. {
  175. throw new InvalidArgumentException(sprintf('%s does not support the following option: \'%s\'.', get_class($this), $name));
  176. }
  177. $this->options[$name] = $value;
  178. }
  179. /**
  180. * Returns true if the option exists.
  181. *
  182. * @param string $name The option name
  183. *
  184. * @return bool true if the option exists, false otherwise
  185. */
  186. public function hasOption($name)
  187. {
  188. return isset($this->options[$name]);
  189. }
  190. /**
  191. * Returns all options.
  192. *
  193. * @return array An array of options
  194. */
  195. public function getOptions()
  196. {
  197. return $this->options;
  198. }
  199. /**
  200. * Changes all options.
  201. *
  202. * @param array $values An array of options
  203. */
  204. public function setOptions($values)
  205. {
  206. $this->options = $values;
  207. }
  208. /**
  209. * Adds a required option.
  210. *
  211. * @param string $name The option name
  212. */
  213. public function addRequiredOption($name)
  214. {
  215. $this->requiredOptions[] = $name;
  216. }
  217. /**
  218. * Returns all required option names.
  219. *
  220. * @param array An array of required option names
  221. */
  222. public function getRequiredOptions()
  223. {
  224. return $this->requiredOptions;
  225. }
  226. /**
  227. * Cleans the input value.
  228. *
  229. * This method is also responsible for trimming the input value
  230. * and checking the required option.
  231. *
  232. * @param mixed $value The input value
  233. *
  234. * @return mixed The cleaned value
  235. *
  236. * @throws sfValidatorError
  237. */
  238. public function clean($value)
  239. {
  240. $clean = $value;
  241. if ($this->options['trim'] && is_string($clean))
  242. {
  243. $clean = trim($clean);
  244. }
  245. // empty value?
  246. if ($this->isEmpty($clean))
  247. {
  248. // required?
  249. if ($this->options['required'])
  250. {
  251. throw new sfValidatorError($this, 'required');
  252. }
  253. return $this->getEmptyValue();
  254. }
  255. return $this->doClean($clean);
  256. }
  257. /**
  258. * Cleans the input value.
  259. *
  260. * Every subclass must implements this method.
  261. *
  262. * @param mixed $value The input value
  263. *
  264. * @return mixed The cleaned value
  265. *
  266. * @throws sfValidatorError
  267. */
  268. abstract protected function doClean($value);
  269. /**
  270. * Sets the charset to use when validating strings.
  271. *
  272. * @param string $charset The charset
  273. */
  274. static public function setCharset($charset)
  275. {
  276. self::$charset = $charset;
  277. }
  278. /**
  279. * Returns the charset to use when validating strings.
  280. *
  281. * @return string The charset (default to UTF-8)
  282. */
  283. static public function getCharset()
  284. {
  285. return self::$charset;
  286. }
  287. /**
  288. * Returns true if the value is empty.
  289. *
  290. * @param mixed $value The input value
  291. *
  292. * @return bool true if the value is empty, false otherwise
  293. */
  294. protected function isEmpty($value)
  295. {
  296. return in_array($value, array(null, '', array()), true);
  297. }
  298. /**
  299. * Returns an empty value for this validator.
  300. *
  301. * @return mixed The empty value for this validator
  302. */
  303. protected function getEmptyValue()
  304. {
  305. return $this->getOption('empty_value');
  306. }
  307. /**
  308. * Returns an array of all error codes for this validator.
  309. *
  310. * @return array An array of possible error codes
  311. *
  312. * @see getDefaultMessages()
  313. */
  314. final public function getErrorCodes()
  315. {
  316. return array_keys($this->getDefaultMessages());
  317. }
  318. /**
  319. * Returns default messages for all possible error codes.
  320. *
  321. * @return array An array of default error codes and messages
  322. */
  323. public function getDefaultMessages()
  324. {
  325. return $this->defaultMessages;
  326. }
  327. /**
  328. * Sets default messages for all possible error codes.
  329. *
  330. * @param array $messages An array of default error codes and messages
  331. */
  332. protected function setDefaultMessages($messages)
  333. {
  334. $this->defaultMessages = $messages;
  335. }
  336. /**
  337. * Returns default option values.
  338. *
  339. * @return array An array of default option values
  340. */
  341. public function getDefaultOptions()
  342. {
  343. return $this->defaultOptions;
  344. }
  345. /**
  346. * Sets default option values.
  347. *
  348. * @param array $options An array of default option values
  349. */
  350. protected function setDefaultOptions($options)
  351. {
  352. $this->defaultOptions = $options;
  353. }
  354. /**
  355. * Returns a string representation of this validator.
  356. *
  357. * @param int $indent Indentation (number of spaces before each line)
  358. *
  359. * @return string The string representation of the validator
  360. */
  361. public function asString($indent = 0)
  362. {
  363. $options = $this->getOptionsWithoutDefaults();
  364. $messages = $this->getMessagesWithoutDefaults();
  365. return sprintf('%s%s(%s%s)',
  366. str_repeat(' ', $indent),
  367. str_replace('sfValidator', '', get_class($this)),
  368. $options ? sfYamlInline::dump($options) : ($messages ? '{}' : ''),
  369. $messages ? ', '.sfYamlInline::dump($messages) : ''
  370. );
  371. }
  372. /**
  373. * Returns all error messages with non default values.
  374. *
  375. * @return string A string representation of the error messages
  376. */
  377. protected function getMessagesWithoutDefaults()
  378. {
  379. $messages = $this->messages;
  380. // remove default option values
  381. foreach ($this->getDefaultMessages() as $key => $value)
  382. {
  383. if (array_key_exists($key, $messages) && $messages[$key] === $value)
  384. {
  385. unset($messages[$key]);
  386. }
  387. }
  388. return $messages;
  389. }
  390. /**
  391. * Returns all options with non default values.
  392. *
  393. * @return string A string representation of the options
  394. */
  395. protected function getOptionsWithoutDefaults()
  396. {
  397. $options = $this->options;
  398. // remove default option values
  399. foreach ($this->getDefaultOptions() as $key => $value)
  400. {
  401. if (array_key_exists($key, $options) && $options[$key] === $value)
  402. {
  403. unset($options[$key]);
  404. }
  405. }
  406. return $options;
  407. }
  408. }