1: <?php
2: namespace TIC\FormBundle\Form\Type;
3:
4: #use Symfony\Component\Form\AbstractType as BaseType;
5: use TIC\FormBundle\Base\TICWidgetType as BaseType;
6:
7: use Symfony\Component\OptionsResolver\OptionsResolver;
8: use Symfony\Component\OptionsResolver\Options;
9: use Symfony\Component\Form\FormBuilderInterface;
10: use Symfony\Component\Form\FormInterface;
11: use Symfony\Component\Form\FormView;
12:
13: use TIC\FormBundle\Form\DataTransformer\StringToTimeTransformer;
14:
15: /**
16: * Sélecteur d'horaire (popup sans calendrier).
17: * Intégration du composant JS bootstrap-datetimepicker
18: *
19: * @TODO le widget 'text' avec l'option 'html5' pourrait passer en type 'number'
20: * @TODO le widget 'text' pourrait utiliser le NumberType (tic_number)
21: * @TODO les options 'hours','minutes','seconds' ne s'applique que sur le widget 'choice'...
22: * @TODO l'option 'with_minutes' à false est gérée par peu de widgets en plus d'être un peu inutile
23: * @TODO l'option 'with_seconds' pour fonctionner en 'html5' doit définir un 'step' < 60
24: *
25: * @TODO contraintes choice : hours = range(9,18,1) ; minutes = range(0,55,5)
26: * @TODO contraintes number : [hours] min=9,max=18,step=1 ; [minutes] min=0,max=55,step=5
27: * @TODO contraintes time : min "9:30" ; max "18:15" ; step "300" => 5mn
28: * @TODO contraintes picker : minDate/maxDate? ; enabledHours/disabledHours ; stepping=5(mn) ; disabledTimeIntervals
29: */
30: class TimeType extends BaseType
31: {
32: protected $form_parent = \Symfony\Component\Form\Extension\Core\Type\TimeType::class;
33: protected $default_prefix = '<clock>';
34: protected $default_suffix = '<clock>';
35:
36:
37: /**
38: * {@inheritdoc}
39: */
40: public function configureOptions(OptionsResolver $resolver): void
41: {
42: parent::configureOptions($resolver);
43:
44: $resolver->setDefaults(array(
45: // options tic_widget (BaseType)
46: 'placeholder' => false, // true, false, String (ex: "widget.date.ph_format_t")
47: 'suffix' => true, // traduisible, html autorisé, raccourci <glyph-name>
48:
49: // options symfony (TimeType)
50: 'input' => 'string', // datetime_immutable|datetime|timestamp|string|array(hour,minute,second)
51: 'with_minutes'=> true, // à forcer ? (peu d'utilité à false & non supporté par tous les widgets)
52: 'with_seconds'=> false,
53: # 'hours' => range(8, 20, 1),
54: # 'minutes' => range(0, 60, 5),
55: # 'secondes' => range(0, 60, 10),
56: 'widget' => 'single_text', // choice | text | single_text
57: 'html5' => true,
58:
59: // options extras (DateTimePicker.js)
60: 'with_js' => true, // seulement si widget laissé avec single_text
61: 'culture' => \Locale::getPrimaryLanguage(\Locale::getDefault()),
62: 'buttons' => true, // array('today','clear','close') | true=ALL | false=NONE
63:
64: # 'defTime' => null,
65: # 'minTime' => null,
66: # 'maxTime' => null,
67: # 'stepTime' => null,
68: ));
69:
70: $resolver->setAllowedTypes('with_js', array('bool'));
71: $resolver->setAllowedTypes('culture', array('string'));
72: $resolver->setAllowedTypes('buttons', array('bool', 'array'));
73:
74: $resolver->setNormalizer('with_js', function (Options $options, $with_js) {
75: if ($options['widget'] != 'single_text') $with_js = false;
76: return $with_js;
77: });
78: $resolver->setNormalizer('buttons', function (Options $options, $buttons) {
79: if (is_bool($buttons)) $buttons = ($buttons) ? array('today', 'clear', 'close') : array();
80: return $buttons;
81: });
82:
83: // annulation du normalizer appliqué dans le champs parent TimeType
84: $resolver->setNormalizer('placeholder', function (Options $options, $value) { return $value; });
85: }
86:
87:
88: /**
89: * {@inheritdoc}
90: */
91: public function buildForm(FormBuilderInterface $builder, array $options): void
92: {
93: if ('string' === $options['input'] && ! $options['strict']) {
94: $builder->resetModelTransformers();
95: $builder->addModelTransformer(new StringToTimeTransformer($options['model_timezone'], $options['model_timezone']));
96: }
97: }
98:
99:
100: /**
101: * {@inheritdoc}
102: */
103: public function finishView(FormView $view, FormInterface $form, array $options): void
104: {
105: parent::finishView($view, $form, $options);
106:
107: // attributs HTML pour input "text"
108: if ($options['widget'] == 'text') {
109: $child_options = array('attr' => array('maxlength' => 2, 'size' => 2));
110: if ($options['html5']) {
111: $child_options['type'] = 'number';
112: $child_options['attr']['size'] = 4;
113: $child_options['attr']['min'] = 0;
114: $child_options['attr']['max'] = 60;
115: }
116: $view->vars['text_options'] = $child_options;
117: }
118:
119: // paramètres JS pour le composant DateTimePicker
120: if ($options['with_js']) {
121: $view->vars['with_js'] = true;
122: $view->vars['format'] = $options['with_seconds'] ? 'LTS' : 'LT';
123: $view->vars['culture'] = $options['culture'];
124: $view->vars['buttons'] = $options['buttons'];
125: $view->vars['group_class'].= ' date';
126: }
127:
128: // spécification de la taille du widget (ajout de classe bootstrap)
129: $this->setViewInputSizing($view);
130: }
131:
132:
133: }
134: