/lib/validator/sfValidatorDate.class.php

https://github.com/bheneka/gitta · PHP · 261 lines · 166 code · 24 blank · 71 comment · 31 complexity · 5aec369a6cb2b564cae2ea5771a813e6 MD5 · raw file

  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. * sfValidatorDate validates a date. It also converts the input value to a valid date.
  11. *
  12. * @package symfony
  13. * @subpackage validator
  14. * @author Fabien Potencier <fabien.potencier@symfony-project.com>
  15. * @version SVN: $Id$
  16. */
  17. class sfValidatorDate extends sfValidatorBase
  18. {
  19. /**
  20. * Configures the current validator.
  21. *
  22. * Available options:
  23. *
  24. * * date_format: A regular expression that dates must match
  25. * Note that the regular expression must use named subpatterns like (?P<year>)
  26. * Working example: ~(?P<day>\d{2})/(?P<month>\d{2})/(?P<year>\d{4})~
  27. * * with_time: true if the validator must return a time, false otherwise
  28. * * date_output: The format to use when returning a date (default to Y-m-d)
  29. * * datetime_output: The format to use when returning a date with time (default to Y-m-d H:i:s)
  30. * * date_format_error: The date format to use when displaying an error for a bad_format error (use date_format if not provided)
  31. * * max: The maximum date allowed (as a timestamp or accecpted date() format)
  32. * * min: The minimum date allowed (as a timestamp or accecpted date() format)
  33. * * date_format_range_error: The date format to use when displaying an error for min/max (default to d/m/Y H:i:s)
  34. *
  35. * Available error codes:
  36. *
  37. * * bad_format
  38. * * min
  39. * * max
  40. *
  41. * @param array $options An array of options
  42. * @param array $messages An array of error messages
  43. *
  44. * @see sfValidatorBase
  45. */
  46. protected function configure($options = array(), $messages = array())
  47. {
  48. $this->addMessage('bad_format', '"%value%" does not match the date format (%date_format%).');
  49. $this->addMessage('max', 'The date must be before %max%.');
  50. $this->addMessage('min', 'The date must be after %min%.');
  51. $this->addOption('date_format', null);
  52. $this->addOption('with_time', false);
  53. $this->addOption('date_output', 'Y-m-d');
  54. $this->addOption('datetime_output', 'Y-m-d H:i:s');
  55. $this->addOption('date_format_error');
  56. $this->addOption('min', null);
  57. $this->addOption('max', null);
  58. $this->addOption('date_format_range_error', 'd/m/Y H:i:s');
  59. }
  60. /**
  61. * @see sfValidatorBase
  62. */
  63. protected function doClean($value)
  64. {
  65. // check date format
  66. if (is_string($value) && $regex = $this->getOption('date_format'))
  67. {
  68. if (!preg_match($regex, $value, $match))
  69. {
  70. throw new sfValidatorError($this, 'bad_format', array('value' => $value, 'date_format' => $this->getOption('date_format_error') ? $this->getOption('date_format_error') : $this->getOption('date_format')));
  71. }
  72. $value = $match;
  73. }
  74. // convert array to date string
  75. if (is_array($value))
  76. {
  77. $value = $this->convertDateArrayToString($value);
  78. }
  79. // convert timestamp to date number format
  80. if (is_numeric($value))
  81. {
  82. $cleanTime = (integer) $value;
  83. $clean = date('YmdHis', $cleanTime);
  84. }
  85. // convert string to date number format
  86. else
  87. {
  88. try
  89. {
  90. $date = new DateTime($value);
  91. $date->setTimezone(new DateTimeZone(date_default_timezone_get()));
  92. $clean = $date->format('YmdHis');
  93. }
  94. catch (Exception $e)
  95. {
  96. throw new sfValidatorError($this, 'invalid', array('value' => $value));
  97. }
  98. }
  99. // check max
  100. if ($max = $this->getOption('max'))
  101. {
  102. // convert timestamp to date number format
  103. if (is_numeric($max))
  104. {
  105. $maxError = date($this->getOption('date_format_range_error'), $max);
  106. $max = date('YmdHis', $max);
  107. }
  108. // convert string to date number
  109. else
  110. {
  111. $dateMax = new DateTime($max);
  112. $max = $dateMax->format('YmdHis');
  113. $maxError = $dateMax->format($this->getOption('date_format_range_error'));
  114. }
  115. if ($clean > $max)
  116. {
  117. throw new sfValidatorError($this, 'max', array('value' => $value, 'max' => $maxError));
  118. }
  119. }
  120. // check min
  121. if ($min = $this->getOption('min'))
  122. {
  123. // convert timestamp to date number
  124. if (is_numeric($min))
  125. {
  126. $minError = date($this->getOption('date_format_range_error'), $min);
  127. $min = date('YmdHis', $min);
  128. }
  129. // convert string to date number
  130. else
  131. {
  132. $dateMin = new DateTime($min);
  133. $min = $dateMin->format('YmdHis');
  134. $minError = $dateMin->format($this->getOption('date_format_range_error'));
  135. }
  136. if ($clean < $min)
  137. {
  138. throw new sfValidatorError($this, 'min', array('value' => $value, 'min' => $minError));
  139. }
  140. }
  141. if ($clean === $this->getEmptyValue())
  142. {
  143. return $cleanTime;
  144. }
  145. $format = $this->getOption('with_time') ? $this->getOption('datetime_output') : $this->getOption('date_output');
  146. return isset($date) ? $date->format($format) : date($format, $cleanTime);
  147. }
  148. /**
  149. * Converts an array representing a date to a timestamp.
  150. *
  151. * The array can contains the following keys: year, month, day, hour, minute, second
  152. *
  153. * @param array $value An array of date elements
  154. *
  155. * @return int A timestamp
  156. */
  157. protected function convertDateArrayToString($value)
  158. {
  159. // all elements must be empty or a number
  160. foreach (array('year', 'month', 'day', 'hour', 'minute', 'second') as $key)
  161. {
  162. if (isset($value[$key]) && !preg_match('#^\d+$#', $value[$key]) && !empty($value[$key]))
  163. {
  164. throw new sfValidatorError($this, 'invalid', array('value' => $value));
  165. }
  166. }
  167. // if one date value is empty, all others must be empty too
  168. $empties =
  169. (!isset($value['year']) || !$value['year'] ? 1 : 0) +
  170. (!isset($value['month']) || !$value['month'] ? 1 : 0) +
  171. (!isset($value['day']) || !$value['day'] ? 1 : 0)
  172. ;
  173. if ($empties > 0 && $empties < 3)
  174. {
  175. throw new sfValidatorError($this, 'invalid', array('value' => $value));
  176. }
  177. else if (3 == $empties)
  178. {
  179. return $this->getEmptyValue();
  180. }
  181. if (!checkdate(intval($value['month']), intval($value['day']), intval($value['year'])))
  182. {
  183. throw new sfValidatorError($this, 'invalid', array('value' => $value));
  184. }
  185. if ($this->getOption('with_time'))
  186. {
  187. // if second is set, minute and hour must be set
  188. // if minute is set, hour must be set
  189. if (
  190. $this->isValueSet($value, 'second') && (!$this->isValueSet($value, 'minute') || !$this->isValueSet($value, 'hour'))
  191. ||
  192. $this->isValueSet($value, 'minute') && !$this->isValueSet($value, 'hour')
  193. )
  194. {
  195. throw new sfValidatorError($this, 'invalid', array('value' => $value));
  196. }
  197. $clean = sprintf(
  198. "%04d-%02d-%02d %02d:%02d:%02d",
  199. intval($value['year']),
  200. intval($value['month']),
  201. intval($value['day']),
  202. isset($value['hour']) ? intval($value['hour']) : 0,
  203. isset($value['minute']) ? intval($value['minute']) : 0,
  204. isset($value['second']) ? intval($value['second']) : 0
  205. );
  206. }
  207. else
  208. {
  209. $clean = sprintf(
  210. "%04d-%02d-%02d %02d:%02d:%02d",
  211. intval($value['year']),
  212. intval($value['month']),
  213. intval($value['day']),
  214. 0,
  215. 0,
  216. 0
  217. );
  218. }
  219. return $clean;
  220. }
  221. protected function isValueSet($values, $key)
  222. {
  223. return isset($values[$key]) && !in_array($values[$key], array(null, ''), true);
  224. }
  225. /**
  226. * @see sfValidatorBase
  227. */
  228. protected function isEmpty($value)
  229. {
  230. if (is_array($value))
  231. {
  232. $filtered = array_filter($value);
  233. return empty($filtered);
  234. }
  235. return parent::isEmpty($value);
  236. }
  237. }