sfValidatorSchema.class.php 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  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. * sfValidatorSchema represents an array of fields.
  11. *
  12. * A field is a named validator.
  13. *
  14. * @package symfony
  15. * @subpackage validator
  16. * @author Fabien Potencier <fabien.potencier@symfony-project.com>
  17. * @version SVN: $Id: sfValidatorSchema.class.php 16274 2009-03-12 18:17:24Z fabien $
  18. */
  19. class sfValidatorSchema extends sfValidatorBase implements ArrayAccess
  20. {
  21. protected
  22. $fields = array(),
  23. $preValidator = null,
  24. $postValidator = null;
  25. /**
  26. * Constructor.
  27. *
  28. * The first argument can be:
  29. *
  30. * * null
  31. * * an array of named sfValidatorBase instances
  32. *
  33. * @param mixed $fields Initial fields
  34. * @param array $options An array of options
  35. * @param array $messages An array of error messages
  36. *
  37. * @see sfValidatorBase
  38. */
  39. public function __construct($fields = null, $options = array(), $messages = array())
  40. {
  41. if (is_array($fields))
  42. {
  43. foreach ($fields as $name => $validator)
  44. {
  45. $this[$name] = $validator;
  46. }
  47. }
  48. else if (!is_null($fields))
  49. {
  50. throw new InvalidArgumentException('sfValidatorSchema constructor takes an array of sfValidatorBase objects.');
  51. }
  52. parent::__construct($options, $messages);
  53. }
  54. /**
  55. * Configures the validator.
  56. *
  57. * Available options:
  58. *
  59. * * allow_extra_fields: if false, the validator adds an error if extra fields are given in the input array of values (default to false)
  60. * * filter_extra_fields: if true, the validator filters extra fields from the returned array of cleaned values (default to true)
  61. *
  62. * Available error codes:
  63. *
  64. * * extra_fields
  65. *
  66. * @param array $options An array of options
  67. * @param array $messages An array of error messages
  68. *
  69. * @see sfValidatorBase
  70. */
  71. protected function configure($options = array(), $messages = array())
  72. {
  73. $this->addOption('allow_extra_fields', false);
  74. $this->addOption('filter_extra_fields', true);
  75. $this->addMessage('extra_fields', 'Unexpected extra form field named "%field%".');
  76. $this->addMessage('post_max_size', 'The form submission cannot be processed. It probably means that you have uploaded a file that is too big.');
  77. }
  78. /**
  79. * @see sfValidatorBase
  80. */
  81. public function clean($values)
  82. {
  83. return $this->doClean($values);
  84. }
  85. /**
  86. * @see sfValidatorBase
  87. */
  88. protected function doClean($values)
  89. {
  90. if (is_null($values))
  91. {
  92. $values = array();
  93. }
  94. if (!is_array($values))
  95. {
  96. throw new InvalidArgumentException('You must pass an array parameter to the clean() method');
  97. }
  98. $clean = array();
  99. $unused = array_keys($this->fields);
  100. $errorSchema = new sfValidatorErrorSchema($this);
  101. // check that post_max_size has not been reached
  102. if (isset($_SERVER['CONTENT_LENGTH']) && (int) $_SERVER['CONTENT_LENGTH'] > $this->getBytes(ini_get('post_max_size')))
  103. {
  104. $errorSchema->addError(new sfValidatorError($this, 'post_max_size'));
  105. throw $errorSchema;
  106. }
  107. // pre validator
  108. try
  109. {
  110. $this->preClean($values);
  111. }
  112. catch (sfValidatorErrorSchema $e)
  113. {
  114. $errorSchema->addErrors($e);
  115. }
  116. catch (sfValidatorError $e)
  117. {
  118. $errorSchema->addError($e);
  119. }
  120. // validate given values
  121. foreach ($values as $name => $value)
  122. {
  123. // field exists in our schema?
  124. if (!array_key_exists($name, $this->fields))
  125. {
  126. if (!$this->options['allow_extra_fields'])
  127. {
  128. $errorSchema->addError(new sfValidatorError($this, 'extra_fields', array('field' => $name)));
  129. }
  130. else if (!$this->options['filter_extra_fields'])
  131. {
  132. $clean[$name] = $value;
  133. }
  134. continue;
  135. }
  136. unset($unused[array_search($name, $unused, true)]);
  137. // validate value
  138. try
  139. {
  140. $clean[$name] = $this->fields[$name]->clean($value);
  141. }
  142. catch (sfValidatorError $e)
  143. {
  144. $clean[$name] = null;
  145. $errorSchema->addError($e, (string) $name);
  146. }
  147. }
  148. // are non given values required?
  149. foreach ($unused as $name)
  150. {
  151. // validate value
  152. try
  153. {
  154. $clean[$name] = $this->fields[$name]->clean(null);
  155. }
  156. catch (sfValidatorError $e)
  157. {
  158. $clean[$name] = null;
  159. $errorSchema->addError($e, (string) $name);
  160. }
  161. }
  162. // post validator
  163. try
  164. {
  165. $clean = $this->postClean($clean);
  166. }
  167. catch (sfValidatorErrorSchema $e)
  168. {
  169. $errorSchema->addErrors($e);
  170. }
  171. catch (sfValidatorError $e)
  172. {
  173. $errorSchema->addError($e);
  174. }
  175. if (count($errorSchema))
  176. {
  177. throw $errorSchema;
  178. }
  179. return $clean;
  180. }
  181. /**
  182. * Cleans the input values.
  183. *
  184. * This method is the first validator executed by doClean().
  185. *
  186. * It executes the validator returned by getPreValidator()
  187. * on the global array of values.
  188. *
  189. * @param array $values The input values
  190. *
  191. * @throws sfValidatorError
  192. */
  193. public function preClean($values)
  194. {
  195. if (is_null($validator = $this->getPreValidator()))
  196. {
  197. return;
  198. }
  199. $validator->clean($values);
  200. }
  201. /**
  202. * Cleans the input values.
  203. *
  204. * This method is the last validator executed by doClean().
  205. *
  206. * It executes the validator returned by getPostValidator()
  207. * on the global array of cleaned values.
  208. *
  209. * @param array $values The input values
  210. *
  211. * @throws sfValidatorError
  212. */
  213. public function postClean($values)
  214. {
  215. if (is_null($validator = $this->getPostValidator()))
  216. {
  217. return $values;
  218. }
  219. return $validator->clean($values);
  220. }
  221. /**
  222. * Sets the pre validator.
  223. *
  224. * @param sfValidatorBase $validator An sfValidatorBase instance
  225. */
  226. public function setPreValidator(sfValidatorBase $validator)
  227. {
  228. $this->preValidator = clone $validator;
  229. }
  230. /**
  231. * Returns the pre validator.
  232. *
  233. * @return sfValidatorBase A sfValidatorBase instance
  234. */
  235. public function getPreValidator()
  236. {
  237. return $this->preValidator;
  238. }
  239. /**
  240. * Sets the post validator.
  241. *
  242. * @param sfValidatorBase $validator An sfValidatorBase instance
  243. */
  244. public function setPostValidator(sfValidatorBase $validator)
  245. {
  246. $this->postValidator = clone $validator;
  247. }
  248. /**
  249. * Returns the post validator.
  250. *
  251. * @return sfValidatorBase An sfValidatorBase instance
  252. */
  253. public function getPostValidator()
  254. {
  255. return $this->postValidator;
  256. }
  257. /**
  258. * Returns true if the schema has a field with the given name (implements the ArrayAccess interface).
  259. *
  260. * @param string $name The field name
  261. *
  262. * @return bool true if the schema has a field with the given name, false otherwise
  263. */
  264. public function offsetExists($name)
  265. {
  266. return isset($this->fields[$name]);
  267. }
  268. /**
  269. * Gets the field associated with the given name (implements the ArrayAccess interface).
  270. *
  271. * @param string $name The field name
  272. *
  273. * @return sfValidatorBase The sfValidatorBase instance associated with the given name, null if it does not exist
  274. */
  275. public function offsetGet($name)
  276. {
  277. return isset($this->fields[$name]) ? $this->fields[$name] : null;
  278. }
  279. /**
  280. * Sets a field (implements the ArrayAccess interface).
  281. *
  282. * @param string $name The field name
  283. * @param sfValidatorBase $validator An sfValidatorBase instance
  284. */
  285. public function offsetSet($name, $validator)
  286. {
  287. if (!$validator instanceof sfValidatorBase)
  288. {
  289. throw new InvalidArgumentException('A field must be an instance of sfValidatorBase.');
  290. }
  291. $this->fields[$name] = clone $validator;
  292. }
  293. /**
  294. * Removes a field by name (implements the ArrayAccess interface).
  295. *
  296. * @param string $name
  297. */
  298. public function offsetUnset($name)
  299. {
  300. unset($this->fields[$name]);
  301. }
  302. /**
  303. * Returns an array of fields.
  304. *
  305. * @return sfValidatorBase An array of sfValidatorBase instances
  306. */
  307. public function getFields()
  308. {
  309. return $this->fields;
  310. }
  311. /**
  312. * @see sfValidatorBase
  313. */
  314. public function asString($indent = 0)
  315. {
  316. throw new Exception('Unable to convert a sfValidatorSchema to string.');
  317. }
  318. public function __clone()
  319. {
  320. foreach ($this->fields as $name => $field)
  321. {
  322. $this->fields[$name] = clone $field;
  323. }
  324. if (!is_null($this->preValidator))
  325. {
  326. $this->preValidator = clone $this->preValidator;
  327. }
  328. if (!is_null($this->postValidator))
  329. {
  330. $this->postValidator = clone $this->postValidator;
  331. }
  332. }
  333. protected function getBytes($value)
  334. {
  335. $value = trim($value);
  336. switch (strtolower($value[strlen($value) - 1]))
  337. {
  338. // The 'G' modifier is available since PHP 5.1.0
  339. case 'g':
  340. $value *= 1024;
  341. case 'm':
  342. $value *= 1024;
  343. case 'k':
  344. $value *= 1024;
  345. }
  346. return $value;
  347. }
  348. }