TimeField.php 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Form;
  11. use Symfony\Component\Form\ValueTransformer\ReversedTransformer;
  12. use Symfony\Component\Form\ValueTransformer\DateTimeToArrayTransformer;
  13. use Symfony\Component\Form\ValueTransformer\DateTimeToStringTransformer;
  14. use Symfony\Component\Form\ValueTransformer\DateTimeToTimestampTransformer;
  15. use Symfony\Component\Form\ValueTransformer\ValueTransformerChain;
  16. /**
  17. * Represents a time field.
  18. *
  19. * Available options:
  20. *
  21. * * widget: How to render the time field ("input" or "choice"). Default: "choice".
  22. * * type: The type of the date stored on the object. Default: "datetime":
  23. * * datetime: A DateTime object;
  24. * * string: A raw string (e.g. 2011-05-01 12:30:00, Y-m-d H:i:s);
  25. * * timestamp: A unix timestamp (e.g. 1304208000).
  26. * * raw: An hour, minute, second array
  27. * * with_seconds Whether or not to create a field for seconds. Default: false.
  28. *
  29. * * hours: An array of hours for the hour select tag.
  30. * * minutes: An array of minutes for the minute select tag.
  31. * * seconds: An array of seconds for the second select tag.
  32. *
  33. * * data_timezone: The timezone of the data. Default: UTC.
  34. * * user_timezone: The timezone of the user entering a new value. Default: UTC.
  35. */
  36. class TimeField extends Form
  37. {
  38. const INPUT = 'input';
  39. const CHOICE = 'choice';
  40. const DATETIME = 'datetime';
  41. const STRING = 'string';
  42. const TIMESTAMP = 'timestamp';
  43. const RAW = 'raw';
  44. protected static $widgets = array(
  45. self::INPUT,
  46. self::CHOICE,
  47. );
  48. protected static $types = array(
  49. self::DATETIME,
  50. self::STRING,
  51. self::TIMESTAMP,
  52. self::RAW,
  53. );
  54. /**
  55. * {@inheritDoc}
  56. */
  57. protected function configure()
  58. {
  59. $this->addOption('widget', self::CHOICE, self::$widgets);
  60. $this->addOption('type', self::DATETIME, self::$types);
  61. $this->addOption('with_seconds', false);
  62. $this->addOption('hours', range(0, 23));
  63. $this->addOption('minutes', range(0, 59));
  64. $this->addOption('seconds', range(0, 59));
  65. $this->addOption('data_timezone', 'UTC');
  66. $this->addOption('user_timezone', 'UTC');
  67. if ($this->getOption('widget') == self::INPUT) {
  68. $this->add(new TextField('hour', array('max_length' => 2)));
  69. $this->add(new TextField('minute', array('max_length' => 2)));
  70. if ($this->getOption('with_seconds')) {
  71. $this->add(new TextField('second', array('max_length' => 2)));
  72. }
  73. } else {
  74. $this->add(new ChoiceField('hour', array(
  75. 'choices' => $this->generatePaddedChoices($this->getOption('hours'), 2),
  76. )));
  77. $this->add(new ChoiceField('minute', array(
  78. 'choices' => $this->generatePaddedChoices($this->getOption('minutes'), 2),
  79. )));
  80. if ($this->getOption('with_seconds')) {
  81. $this->add(new ChoiceField('second', array(
  82. 'choices' => $this->generatePaddedChoices($this->getOption('seconds'), 2),
  83. )));
  84. }
  85. }
  86. $fields = array('hour', 'minute');
  87. if ($this->getOption('with_seconds')) {
  88. $fields[] = 'second';
  89. }
  90. if ($this->getOption('type') == self::STRING) {
  91. $this->setNormalizationTransformer(new ReversedTransformer(
  92. new DateTimeToStringTransformer(array(
  93. 'format' => 'H:i:s',
  94. 'input_timezone' => $this->getOption('data_timezone'),
  95. 'output_timezone' => $this->getOption('data_timezone'),
  96. ))
  97. ));
  98. } else if ($this->getOption('type') == self::TIMESTAMP) {
  99. $this->setNormalizationTransformer(new ReversedTransformer(
  100. new DateTimeToTimestampTransformer(array(
  101. 'input_timezone' => $this->getOption('data_timezone'),
  102. 'output_timezone' => $this->getOption('data_timezone'),
  103. ))
  104. ));
  105. } else if ($this->getOption('type') === self::RAW) {
  106. $this->setNormalizationTransformer(new ReversedTransformer(
  107. new DateTimeToArrayTransformer(array(
  108. 'input_timezone' => $this->getOption('data_timezone'),
  109. 'output_timezone' => $this->getOption('data_timezone'),
  110. 'fields' => $fields,
  111. ))
  112. ));
  113. }
  114. $this->setValueTransformer(new DateTimeToArrayTransformer(array(
  115. 'input_timezone' => $this->getOption('data_timezone'),
  116. 'output_timezone' => $this->getOption('user_timezone'),
  117. // if the field is rendered as choice field, the values should be trimmed
  118. // of trailing zeros to render the selected choices correctly
  119. 'pad' => $this->getOption('widget') == self::INPUT,
  120. 'fields' => $fields,
  121. )));
  122. }
  123. public function isField()
  124. {
  125. return self::INPUT === $this->getOption('widget');
  126. }
  127. public function isWithSeconds()
  128. {
  129. return $this->getOption('with_seconds');
  130. }
  131. /**
  132. * Generates an array of choices for the given values
  133. *
  134. * If the values are shorter than $padLength characters, they are padded with
  135. * zeros on the left side.
  136. *
  137. * @param array $values The available choices
  138. * @param integer $padLength The length to pad the choices
  139. * @return array An array with the input values as keys and the
  140. * padded values as values
  141. */
  142. protected function generatePaddedChoices(array $values, $padLength)
  143. {
  144. $choices = array();
  145. foreach ($values as $value) {
  146. $choices[$value] = str_pad($value, $padLength, '0', STR_PAD_LEFT);
  147. }
  148. return $choices;
  149. }
  150. /**
  151. * Returns whether the hour of the field's data is valid
  152. *
  153. * The hour is valid if it is contained in the list passed to the field's
  154. * option "hours".
  155. *
  156. * @return Boolean
  157. */
  158. public function isHourWithinRange()
  159. {
  160. $date = $this->getNormalizedData();
  161. return null === $date || in_array($date->format('H'), $this->getOption('hours'));
  162. }
  163. /**
  164. * Returns whether the minute of the field's data is valid
  165. *
  166. * The minute is valid if it is contained in the list passed to the field's
  167. * option "minutes".
  168. *
  169. * @return Boolean
  170. */
  171. public function isMinuteWithinRange()
  172. {
  173. $date = $this->getNormalizedData();
  174. return null === $date || in_array($date->format('i'), $this->getOption('minutes'));
  175. }
  176. /**
  177. * Returns whether the second of the field's data is valid
  178. *
  179. * The second is valid if it is contained in the list passed to the field's
  180. * option "seconds".
  181. *
  182. * @return Boolean
  183. */
  184. public function isSecondWithinRange()
  185. {
  186. $date = $this->getNormalizedData();
  187. return null === $date || in_array($date->format('s'), $this->getOption('seconds'));
  188. }
  189. }