Ver código fonte

merged branch stloyd/datetimetype (PR #1419)

Commits
-------

aeaf44a Removed unused code from DateTimeType
3c2539f Throw exception when "date_widget" option is not equal to "time_widget"
305c476 Overwrite child options ("widget", "empty_value") if any given
7bc19f9 Added to `DateTimeType` extension possibility to render form as `single_text` (similar to `DateType` option) (issue #1323 it requires fix for #1205)
17b41b2 Added to `TimeType` extension possibility to render form as `single_text` (similar to DateType option) (issue #1205) Adjusted `DateTimeType` to allow usage of this new feature

Discussion
----------

[Form][DateTimeType] Added "widget" and "empty_value" options

Hey,

I have just added "widget" and "empty_value" options to `DateTimeType`:

* `widget` option will overwrite existing `date_widget` and `time_widget`,
* `empty_value` behave exacly same way as it does for `ChoiceType`, `DateType` and `TimeType`

Also added and `FormException` when `date_widget` is not equal to `time_widget`, now is throwed non intuitive one (this will be changed in next days to allow different values for this options).

Closes #1323
Fabien Potencier 14 anos atrás
pai
commit
cca21a84e3

+ 10 - 6
src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig

@@ -71,12 +71,16 @@
 
 {% block datetime_widget %}
 {% spaceless %}
-    <div {{ block('widget_container_attributes') }}>
-        {{ form_errors(form.date) }}
-        {{ form_errors(form.time) }}
-        {{ form_widget(form.date) }}
-        {{ form_widget(form.time) }}
-    </div>
+    {% if widget == 'single_text' %}
+        {{ block('field_widget') }}
+    {% else %}
+        <div {{ block('widget_container_attributes') }}>
+            {{ form_errors(form.date) }}
+            {{ form_errors(form.time) }}
+            {{ form_widget(form.date) }}
+            {{ form_widget(form.time) }}
+        </div>
+    {% endif %}
 {% endspaceless %}
 {% endblock datetime_widget %}
 

+ 9 - 5
src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/datetime_widget.html.php

@@ -1,5 +1,9 @@
-<div <?php echo $view['form']->renderBlock('container_attributes') ?>>
-    <?php echo $view['form']->widget($form['date'])
-       .' '
-       .$view['form']->widget($form['time']) ?>
-</div>
+<?php if ($widget == 'single_text'): ?>
+    <?php echo $view['form']->renderBlock('field_widget'); ?>
+<?php else: ?>
+    <div <?php echo $view['form']->renderBlock('container_attributes') ?>>
+        <?php echo $view['form']->widget($form['date'])
+            . ' '
+            . $view['form']->widget($form['time']) ?>
+    </div>
+<?php endif ?>

+ 96 - 51
src/Symfony/Component/Form/Extension/Core/Type/DateTimeType.php

@@ -12,8 +12,11 @@
 namespace Symfony\Component\Form\Extension\Core\Type;
 
 use Symfony\Component\Form\AbstractType;
+use Symfony\Component\Form\FormInterface;
 use Symfony\Component\Form\FormBuilder;
+use Symfony\Component\Form\FormView;
 use Symfony\Component\Form\ReversedTransformer;
+use Symfony\Component\Form\Exception\FormException;
 use Symfony\Component\Form\Extension\Core\DataTransformer\DataTransformerChain;
 use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToArrayTransformer;
 use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransformer;
@@ -27,38 +30,6 @@ class DateTimeType extends AbstractType
      */
     public function buildForm(FormBuilder $builder, array $options)
     {
-        // Only pass a subset of the options to children
-        $dateOptions = array_intersect_key($options, array_flip(array(
-            'years',
-            'months',
-            'days',
-            'empty_value',
-            'required',
-        )));
-        $timeOptions = array_intersect_key($options, array_flip(array(
-            'hours',
-            'minutes',
-            'seconds',
-            'with_seconds',
-            'empty_value',
-            'required',
-        )));
-
-        if (isset($options['date_widget'])) {
-            $dateOptions['widget'] = $options['date_widget'];
-        }
-        if (isset($options['date_format'])) {
-            $dateOptions['format'] = $options['date_format'];
-        }
-
-        $dateOptions['input'] = 'array';
-
-        if (isset($options['time_widget'])) {
-            $timeOptions['widget'] = $options['time_widget'];
-        }
-
-        $timeOptions['input'] = 'array';
-
         $parts = array('year', 'month', 'day', 'hour', 'minute');
         $timeParts = array('hour', 'minute');
 
@@ -67,17 +38,63 @@ class DateTimeType extends AbstractType
             $timeParts[] = 'second';
         }
 
-        $builder
-            ->appendClientTransformer(new DataTransformerChain(array(
-                new DateTimeToArrayTransformer($options['data_timezone'], $options['user_timezone'], $parts),
-                new ArrayToPartsTransformer(array(
-                    'date' => array('year', 'month', 'day'),
-                    'time' => $timeParts,
-                )),
-            )))
-            ->add('date', 'date', $dateOptions)
-            ->add('time', 'time', $timeOptions)
-        ;
+        if ($options['date_widget'] !== $options['time_widget']) {
+            throw new FormException(sprintf('Options "date_widget" and "time_widget" need to be identical. Used: "date_widget" = "%s" and "time_widget" = "%s".', $options['date_widget'] ?: 'choice', $options['time_widget'] ?: 'choice'));
+        }
+
+        if ($options['widget'] === 'single_text') {
+            $builder->appendClientTransformer(new DateTimeToStringTransformer($options['data_timezone'], $options['user_timezone'], 'Y-m-d H:i:s'));
+        } else {
+            // Only pass a subset of the options to children
+            $dateOptions = array_intersect_key($options, array_flip(array(
+                'years',
+                'months',
+                'days',
+                'empty_value',
+                'required',
+            )));
+            $timeOptions = array_intersect_key($options, array_flip(array(
+                'hours',
+                'minutes',
+                'seconds',
+                'with_seconds',
+                'empty_value',
+                'required',
+            )));
+
+            // If `widget` is set, overwrite widget options from `date` and `time`
+            if (isset($options['widget'])) {
+                $dateOptions['widget'] = $options['widget'];
+                $timeOptions['widget'] = $options['widget'];
+            } else {
+                if (isset($options['date_widget'])) {
+                    $dateOptions['widget'] = $options['date_widget'];
+                }
+
+                if (isset($options['time_widget'])) {
+                    $timeOptions['widget'] = $options['time_widget'];
+                }
+            }
+
+            if (isset($options['date_format'])) {
+                $dateOptions['format'] = $options['date_format'];
+            }
+
+            $dateOptions['input'] = 'array';
+            $timeOptions['input'] = 'array';
+
+            $builder
+                ->appendClientTransformer(new DataTransformerChain(array(
+                    new DateTimeToArrayTransformer($options['data_timezone'], $options['user_timezone'], $parts),
+                    new ArrayToPartsTransformer(array(
+                        'date' => array('year', 'month', 'day'),
+                        'time' => $timeParts,
+                    )),
+                )))
+                ->add('date', 'date', $dateOptions)
+                ->add('time', 'time', $timeOptions)
+            ;
+        }
 
         if ($options['input'] === 'string') {
             $builder->appendNormTransformer(new ReversedTransformer(
@@ -92,6 +109,16 @@ class DateTimeType extends AbstractType
                 new DateTimeToArrayTransformer($options['data_timezone'], $options['data_timezone'], $parts)
             ));
         }
+
+        $builder->setAttribute('widget', $options['widget']);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function buildView(FormView $view, FormInterface $form)
+    {
+        $view->set('widget', $form->getAttribute('widget'));
     }
 
     /**
@@ -103,10 +130,6 @@ class DateTimeType extends AbstractType
             'input'         => 'datetime',
             'data_timezone' => null,
             'user_timezone' => null,
-            'empty_value'   => null,
-            // Don't modify \DateTime classes by reference, we treat
-            // them like immutable value objects
-            'by_reference'  => false,
             'date_widget'   => null,
             'date_format'   => null,
             'time_widget'   => null,
@@ -119,6 +142,13 @@ class DateTimeType extends AbstractType
             'minutes'       => range(0, 59),
             'seconds'       => range(0, 59),
             'with_seconds'  => false,
+            // Don't modify \DateTime classes by reference, we treat
+            // them like immutable value objects
+            'by_reference'  => false,
+            // This will overwrite "widget" child options
+            'widget'        => null,
+            // This will overwrite "empty_value" child options
+            'empty_value'   => null,
         );
     }
 
@@ -128,34 +158,49 @@ class DateTimeType extends AbstractType
     public function getAllowedOptionValues(array $options)
     {
         return array(
-            'input'         => array(
+            'input'       => array(
                 'datetime',
                 'string',
                 'timestamp',
                 'array',
             ),
-            'date_widget'   => array(
+            'date_widget' => array(
                 null, // inherit default from DateType
                 'single_text',
                 'text',
                 'choice',
             ),
-            'date_format'   => array(
+            'date_format' => array(
                 null, // inherit default from DateType
                 \IntlDateFormatter::FULL,
                 \IntlDateFormatter::LONG,
                 \IntlDateFormatter::MEDIUM,
                 \IntlDateFormatter::SHORT,
              ),
-            'time_widget'   => array(
+            'time_widget' => array(
                 null, // inherit default from TimeType
                 'single_text',
                 'text',
                 'choice',
             ),
+            // This option will overwrite "date_widget" and "time_widget" options
+            'widget'     => array(
+                null, // default, don't overwrite options
+                'single_text',
+                'text',
+                'choice',
+            ),
         );
     }
 
+    /**
+     * {@inheritdoc}
+     */
+    public function getParent(array $options)
+    {
+        return $options['widget'] === 'single_text' ? 'field' : 'form';
+    }
+
     /**
      * {@inheritdoc}
      */

+ 27 - 18
tests/Symfony/Tests/Component/Form/AbstractLayoutTest.php

@@ -810,6 +810,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
 '
         );
     }
+
     public function testDateTimeWithEmptyValueOnTime()
     {
         $form = $this->factory->createNamed('datetime', 'na&me', '2011-02-03', array(
@@ -913,38 +914,46 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
             [@value="Feb 3, 2011"]
         /following-sibling::input
             [@type="text"]
-            [@name="na&me[time]"]
             [@id="na&me_time"]
+            [@name="na&me[time]"]
             [@value="04:05:00"]
     ]
 '
         );
     }
 
-    public function testDateTimeWithSecondsSingleText()
+    public function testDateTimeWithWidgetSingleText()
     {
         $form = $this->factory->createNamed('datetime', 'name', '2011-02-03 04:05:06', array(
             'property_path' => 'name',
             'input' => 'string',
-            'date_widget' => 'single_text',
-            'time_widget' => 'single_text',
-            'with_seconds' => true,
+            'widget' => 'single_text',
         ));
 
         $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/div
-    [
-        ./input
-            [@type="text"]
-            [@id="name_date"]
-            [@name="name[date]"]
-            [@value="Feb 3, 2011"]
-        /following-sibling::input
-            [@type="text"]
-            [@name="name[time]"]
-            [@id="name_time"]
-            [@value="04:05:06"]
-    ]
+'/input
+    [@type="text"]
+    [@name="name"]
+    [@value="2011-02-03 04:05:06"]
+'
+        );
+    }
+
+    public function testDateTimeWithWidgetSingleTextIgnoreDateAndTimeWidgets()
+    {
+        $form = $this->factory->createNamed('datetime', 'na&me', '2011-02-03 04:05:06', array(
+            'property_path' => 'name',
+            'input' => 'string',
+            'date_widget' => 'choice',
+            'time_widget' => 'choice',
+            'widget' => 'single_text',
+        ));
+
+        $this->assertWidgetMatchesXpath($form->createView(), array(),
+'/input
+    [@type="text"]
+    [@name="na&me"]
+    [@value="2011-02-03 04:05:06"]
 '
         );
     }

+ 36 - 0
tests/Symfony/Tests/Component/Form/Extension/Core/Type/DateTimeTypeTest.php

@@ -160,4 +160,40 @@ class DateTimeTypeTest extends LocalizedTestCase
 
         $this->assertEquals($dateTime->format('Y-m-d H:i:s'), $form->getData());
     }
+
+    public function testSubmit_stringSingleText()
+    {
+        $form = $this->factory->create('datetime', null, array(
+            'data_timezone' => 'UTC',
+            'user_timezone' => 'UTC',
+            'input' => 'string',
+            'widget' => 'single_text',
+        ));
+
+        $form->bind('2010-06-02 03:04:00');
+
+        $this->assertEquals('2010-06-02 03:04:00', $form->getData());
+        $this->assertEquals('2010-06-02 03:04:00', $form->getClientData());
+    }
+
+    /**
+     * @expectedException Symfony\Component\Form\Exception\FormException
+     */
+    public function testDifferentWidgets()
+    {
+        $form = $this->factory->create('datetime', null, array(
+            'date_widget' => 'single_text',
+            'time_widget' => 'choice',
+        ));
+    }
+
+    /**
+     * @expectedException Symfony\Component\Form\Exception\FormException
+     */
+    public function testDefinedOnlyOneWidget()
+    {
+        $form = $this->factory->create('datetime', null, array(
+            'date_widget' => 'single_text',
+        ));
+    }
 }