sfValidatorBase.class.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  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 16345 2009-03-16 16:53:51Z fabien $
  18. */
  19. abstract class sfValidatorBase
  20. {
  21. protected static
  22. $charset = 'UTF-8',
  23. $invalidMessage = 'Invalid.',
  24. $requiredMessage = 'Required.';
  25. protected
  26. $requiredOptions = array(),
  27. $defaultMessages = array(),
  28. $defaultOptions = array(),
  29. $messages = array(),
  30. $options = array();
  31. /**
  32. * Constructor.
  33. *
  34. * Available options:
  35. *
  36. * * required: true if the value is required, false otherwise (default to true)
  37. * * trim: true if the value must be trimmed, false otherwise (default to false)
  38. * * empty_value: empty value when value is not required
  39. *
  40. * Available error codes:
  41. *
  42. * * required
  43. * * invalid
  44. *
  45. * @param array $options An array of options
  46. * @param array $messages An array of error messages
  47. */
  48. public function __construct($options = array(), $messages = array())
  49. {
  50. $this->options = array_merge(array('required' => true, 'trim' => false, 'empty_value' => null), $this->options);
  51. $this->messages = array_merge(array('required' => self::$requiredMessage, 'invalid' => self::$invalidMessage), $this->messages);
  52. $this->configure($options, $messages);
  53. $this->setDefaultOptions($this->getOptions());
  54. $this->setDefaultMessages($this->getMessages());
  55. // check option names
  56. if ($diff = array_diff(array_keys($options), array_merge(array_keys($this->options), $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(array_keys($this->options), array_keys($options))))
  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. * Sets the default invalid message
  228. *
  229. * @param string $message
  230. */
  231. static public function setInvalidMessage($message)
  232. {
  233. self::$invalidMessage = $message;
  234. }
  235. /**
  236. * Sets the default required message
  237. *
  238. * @param string $message
  239. */
  240. static public function setRequiredMessage($message)
  241. {
  242. self::$requiredMessage = $message;
  243. }
  244. /**
  245. * Cleans the input value.
  246. *
  247. * This method is also responsible for trimming the input value
  248. * and checking the required option.
  249. *
  250. * @param mixed $value The input value
  251. *
  252. * @return mixed The cleaned value
  253. *
  254. * @throws sfValidatorError
  255. */
  256. public function clean($value)
  257. {
  258. $clean = $value;
  259. if ($this->options['trim'] && is_string($clean))
  260. {
  261. $clean = trim($clean);
  262. }
  263. // empty value?
  264. if ($this->isEmpty($clean))
  265. {
  266. // required?
  267. if ($this->options['required'])
  268. {
  269. throw new sfValidatorError($this, 'required');
  270. }
  271. return $this->getEmptyValue();
  272. }
  273. return $this->doClean($clean);
  274. }
  275. /**
  276. * Cleans the input value.
  277. *
  278. * Every subclass must implements this method.
  279. *
  280. * @param mixed $value The input value
  281. *
  282. * @return mixed The cleaned value
  283. *
  284. * @throws sfValidatorError
  285. */
  286. abstract protected function doClean($value);
  287. /**
  288. * Sets the charset to use when validating strings.
  289. *
  290. * @param string $charset The charset
  291. */
  292. static public function setCharset($charset)
  293. {
  294. self::$charset = $charset;
  295. }
  296. /**
  297. * Returns the charset to use when validating strings.
  298. *
  299. * @return string The charset (default to UTF-8)
  300. */
  301. static public function getCharset()
  302. {
  303. return self::$charset;
  304. }
  305. /**
  306. * Returns true if the value is empty.
  307. *
  308. * @param mixed $value The input value
  309. *
  310. * @return bool true if the value is empty, false otherwise
  311. */
  312. protected function isEmpty($value)
  313. {
  314. return in_array($value, array(null, '', array()), true);
  315. }
  316. /**
  317. * Returns an empty value for this validator.
  318. *
  319. * @return mixed The empty value for this validator
  320. */
  321. protected function getEmptyValue()
  322. {
  323. return $this->getOption('empty_value');
  324. }
  325. /**
  326. * Returns an array of all error codes for this validator.
  327. *
  328. * @return array An array of possible error codes
  329. *
  330. * @see getDefaultMessages()
  331. */
  332. final public function getErrorCodes()
  333. {
  334. return array_keys($this->getDefaultMessages());
  335. }
  336. /**
  337. * Returns default messages for all possible error codes.
  338. *
  339. * @return array An array of default error codes and messages
  340. */
  341. public function getDefaultMessages()
  342. {
  343. return $this->defaultMessages;
  344. }
  345. /**
  346. * Sets default messages for all possible error codes.
  347. *
  348. * @param array $messages An array of default error codes and messages
  349. */
  350. protected function setDefaultMessages($messages)
  351. {
  352. $this->defaultMessages = $messages;
  353. }
  354. /**
  355. * Returns default option values.
  356. *
  357. * @return array An array of default option values
  358. */
  359. public function getDefaultOptions()
  360. {
  361. return $this->defaultOptions;
  362. }
  363. /**
  364. * Sets default option values.
  365. *
  366. * @param array $options An array of default option values
  367. */
  368. protected function setDefaultOptions($options)
  369. {
  370. $this->defaultOptions = $options;
  371. }
  372. /**
  373. * Returns a string representation of this validator.
  374. *
  375. * @param int $indent Indentation (number of spaces before each line)
  376. *
  377. * @return string The string representation of the validator
  378. */
  379. public function asString($indent = 0)
  380. {
  381. $options = $this->getOptionsWithoutDefaults();
  382. $messages = $this->getMessagesWithoutDefaults();
  383. return sprintf('%s%s(%s%s)',
  384. str_repeat(' ', $indent),
  385. str_replace('sfValidator', '', get_class($this)),
  386. $options ? sfYamlInline::dump($options) : ($messages ? '{}' : ''),
  387. $messages ? ', '.sfYamlInline::dump($messages) : ''
  388. );
  389. }
  390. /**
  391. * Returns all error messages with non default values.
  392. *
  393. * @return string A string representation of the error messages
  394. */
  395. protected function getMessagesWithoutDefaults()
  396. {
  397. $messages = $this->messages;
  398. // remove default option values
  399. foreach ($this->getDefaultMessages() as $key => $value)
  400. {
  401. if (array_key_exists($key, $messages) && $messages[$key] === $value)
  402. {
  403. unset($messages[$key]);
  404. }
  405. }
  406. return $messages;
  407. }
  408. /**
  409. * Returns all options with non default values.
  410. *
  411. * @return string A string representation of the options
  412. */
  413. protected function getOptionsWithoutDefaults()
  414. {
  415. $options = $this->options;
  416. // remove default option values
  417. foreach ($this->getDefaultOptions() as $key => $value)
  418. {
  419. if (array_key_exists($key, $options) && $options[$key] === $value)
  420. {
  421. unset($options[$key]);
  422. }
  423. }
  424. return $options;
  425. }
  426. }