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

Debug toolbar