PageRenderTime 28ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/symfony/symfony/src/Symfony/Component/Form/Extension/Core/Type/DateTimeType.php

https://gitlab.com/Isaki/le331.fr
PHP | 290 lines | 203 code | 29 blank | 58 comment | 14 complexity | 01978392adec53db36fb9c35e75d7c29 MD5 | raw file
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.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\Extension\Core\Type;
  11. use Symfony\Component\Form\AbstractType;
  12. use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
  13. use Symfony\Component\Form\FormInterface;
  14. use Symfony\Component\Form\FormBuilderInterface;
  15. use Symfony\Component\Form\FormView;
  16. use Symfony\Component\Form\ReversedTransformer;
  17. use Symfony\Component\Form\Extension\Core\DataTransformer\DataTransformerChain;
  18. use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToArrayTransformer;
  19. use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransformer;
  20. use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToLocalizedStringTransformer;
  21. use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer;
  22. use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToRfc3339Transformer;
  23. use Symfony\Component\Form\Extension\Core\DataTransformer\ArrayToPartsTransformer;
  24. use Symfony\Component\OptionsResolver\Options;
  25. use Symfony\Component\OptionsResolver\OptionsResolver;
  26. class DateTimeType extends AbstractType
  27. {
  28. const DEFAULT_DATE_FORMAT = \IntlDateFormatter::MEDIUM;
  29. const DEFAULT_TIME_FORMAT = \IntlDateFormatter::MEDIUM;
  30. /**
  31. * This is not quite the HTML5 format yet, because ICU lacks the
  32. * capability of parsing and generating RFC 3339 dates, which
  33. * are like the below pattern but with a timezone suffix. The
  34. * timezone suffix is.
  35. *
  36. * * "Z" for UTC
  37. * * "(-|+)HH:mm" for other timezones (note the colon!)
  38. *
  39. * For more information see:
  40. *
  41. * http://userguide.icu-project.org/formatparse/datetime#TOC-Date-Time-Format-Syntax
  42. * http://www.w3.org/TR/html-markup/input.datetime.html
  43. * http://tools.ietf.org/html/rfc3339
  44. *
  45. * An ICU ticket was created:
  46. * http://icu-project.org/trac/ticket/9421
  47. *
  48. * It was supposedly fixed, but is not available in all PHP installations
  49. * yet. To temporarily circumvent this issue, DateTimeToRfc3339Transformer
  50. * is used when the format matches this constant.
  51. */
  52. const HTML5_FORMAT = "yyyy-MM-dd'T'HH:mm:ssZZZZZ";
  53. private static $acceptedFormats = array(
  54. \IntlDateFormatter::FULL,
  55. \IntlDateFormatter::LONG,
  56. \IntlDateFormatter::MEDIUM,
  57. \IntlDateFormatter::SHORT,
  58. );
  59. /**
  60. * {@inheritdoc}
  61. */
  62. public function buildForm(FormBuilderInterface $builder, array $options)
  63. {
  64. $parts = array('year', 'month', 'day', 'hour');
  65. $dateParts = array('year', 'month', 'day');
  66. $timeParts = array('hour');
  67. if ($options['with_minutes']) {
  68. $parts[] = 'minute';
  69. $timeParts[] = 'minute';
  70. }
  71. if ($options['with_seconds']) {
  72. $parts[] = 'second';
  73. $timeParts[] = 'second';
  74. }
  75. $dateFormat = is_int($options['date_format']) ? $options['date_format'] : self::DEFAULT_DATE_FORMAT;
  76. $timeFormat = self::DEFAULT_TIME_FORMAT;
  77. $calendar = \IntlDateFormatter::GREGORIAN;
  78. $pattern = is_string($options['format']) ? $options['format'] : null;
  79. if (!in_array($dateFormat, self::$acceptedFormats, true)) {
  80. throw new InvalidOptionsException('The "date_format" option must be one of the IntlDateFormatter constants (FULL, LONG, MEDIUM, SHORT) or a string representing a custom format.');
  81. }
  82. if ('single_text' === $options['widget']) {
  83. if (self::HTML5_FORMAT === $pattern) {
  84. $builder->addViewTransformer(new DateTimeToRfc3339Transformer(
  85. $options['model_timezone'],
  86. $options['view_timezone']
  87. ));
  88. } else {
  89. $builder->addViewTransformer(new DateTimeToLocalizedStringTransformer(
  90. $options['model_timezone'],
  91. $options['view_timezone'],
  92. $dateFormat,
  93. $timeFormat,
  94. $calendar,
  95. $pattern
  96. ));
  97. }
  98. } else {
  99. // Only pass a subset of the options to children
  100. $dateOptions = array_intersect_key($options, array_flip(array(
  101. 'years',
  102. 'months',
  103. 'days',
  104. 'empty_value',
  105. 'placeholder',
  106. 'required',
  107. 'translation_domain',
  108. 'html5',
  109. 'invalid_message',
  110. 'invalid_message_parameters',
  111. )));
  112. $timeOptions = array_intersect_key($options, array_flip(array(
  113. 'hours',
  114. 'minutes',
  115. 'seconds',
  116. 'with_minutes',
  117. 'with_seconds',
  118. 'empty_value',
  119. 'placeholder',
  120. 'required',
  121. 'translation_domain',
  122. 'html5',
  123. 'invalid_message',
  124. 'invalid_message_parameters',
  125. )));
  126. if (null !== $options['date_widget']) {
  127. $dateOptions['widget'] = $options['date_widget'];
  128. }
  129. if (null !== $options['time_widget']) {
  130. $timeOptions['widget'] = $options['time_widget'];
  131. }
  132. if (null !== $options['date_format']) {
  133. $dateOptions['format'] = $options['date_format'];
  134. }
  135. $dateOptions['input'] = $timeOptions['input'] = 'array';
  136. $dateOptions['error_bubbling'] = $timeOptions['error_bubbling'] = true;
  137. $builder
  138. ->addViewTransformer(new DataTransformerChain(array(
  139. new DateTimeToArrayTransformer($options['model_timezone'], $options['view_timezone'], $parts),
  140. new ArrayToPartsTransformer(array(
  141. 'date' => $dateParts,
  142. 'time' => $timeParts,
  143. )),
  144. )))
  145. ->add('date', 'date', $dateOptions)
  146. ->add('time', 'time', $timeOptions)
  147. ;
  148. }
  149. if ('string' === $options['input']) {
  150. $builder->addModelTransformer(new ReversedTransformer(
  151. new DateTimeToStringTransformer($options['model_timezone'], $options['model_timezone'])
  152. ));
  153. } elseif ('timestamp' === $options['input']) {
  154. $builder->addModelTransformer(new ReversedTransformer(
  155. new DateTimeToTimestampTransformer($options['model_timezone'], $options['model_timezone'])
  156. ));
  157. } elseif ('array' === $options['input']) {
  158. $builder->addModelTransformer(new ReversedTransformer(
  159. new DateTimeToArrayTransformer($options['model_timezone'], $options['model_timezone'], $parts)
  160. ));
  161. }
  162. }
  163. /**
  164. * {@inheritdoc}
  165. */
  166. public function buildView(FormView $view, FormInterface $form, array $options)
  167. {
  168. $view->vars['widget'] = $options['widget'];
  169. // Change the input to a HTML5 datetime input if
  170. // * the widget is set to "single_text"
  171. // * the format matches the one expected by HTML5
  172. // * the html5 is set to true
  173. if ($options['html5'] && 'single_text' === $options['widget'] && self::HTML5_FORMAT === $options['format']) {
  174. $view->vars['type'] = 'datetime';
  175. }
  176. }
  177. /**
  178. * {@inheritdoc}
  179. */
  180. public function configureOptions(OptionsResolver $resolver)
  181. {
  182. $compound = function (Options $options) {
  183. return $options['widget'] !== 'single_text';
  184. };
  185. // Defaults to the value of "widget"
  186. $dateWidget = function (Options $options) {
  187. return $options['widget'];
  188. };
  189. // Defaults to the value of "widget"
  190. $timeWidget = function (Options $options) {
  191. return $options['widget'];
  192. };
  193. $resolver->setDefaults(array(
  194. 'input' => 'datetime',
  195. 'model_timezone' => null,
  196. 'view_timezone' => null,
  197. 'format' => self::HTML5_FORMAT,
  198. 'date_format' => null,
  199. 'widget' => null,
  200. 'date_widget' => $dateWidget,
  201. 'time_widget' => $timeWidget,
  202. 'with_minutes' => true,
  203. 'with_seconds' => false,
  204. 'html5' => true,
  205. // Don't modify \DateTime classes by reference, we treat
  206. // them like immutable value objects
  207. 'by_reference' => false,
  208. 'error_bubbling' => false,
  209. // If initialized with a \DateTime object, FormType initializes
  210. // this option to "\DateTime". Since the internal, normalized
  211. // representation is not \DateTime, but an array, we need to unset
  212. // this option.
  213. 'data_class' => null,
  214. 'compound' => $compound,
  215. ));
  216. // Don't add some defaults in order to preserve the defaults
  217. // set in DateType and TimeType
  218. $resolver->setDefined(array(
  219. 'empty_value', // deprecated
  220. 'placeholder',
  221. 'years',
  222. 'months',
  223. 'days',
  224. 'hours',
  225. 'minutes',
  226. 'seconds',
  227. ));
  228. $resolver->setAllowedValues('input', array(
  229. 'datetime',
  230. 'string',
  231. 'timestamp',
  232. 'array',
  233. ));
  234. $resolver->setAllowedValues('date_widget', array(
  235. null, // inherit default from DateType
  236. 'single_text',
  237. 'text',
  238. 'choice',
  239. ));
  240. $resolver->setAllowedValues('time_widget', array(
  241. null, // inherit default from TimeType
  242. 'single_text',
  243. 'text',
  244. 'choice',
  245. ));
  246. // This option will overwrite "date_widget" and "time_widget" options
  247. $resolver->setAllowedValues('widget', array(
  248. null, // default, don't overwrite options
  249. 'single_text',
  250. 'text',
  251. 'choice',
  252. ));
  253. }
  254. /**
  255. * {@inheritdoc}
  256. */
  257. public function getName()
  258. {
  259. return 'datetime';
  260. }
  261. }