Ver código fonte

[Form] Ported DateTimeField to FormFactory

Bernhard Schussek 14 anos atrás
pai
commit
8e2d0bae90

+ 0 - 171
src/Symfony/Component/Form/DateTimeField.php

@@ -1,171 +0,0 @@
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-use Symfony\Component\Form\ValueTransformer\ReversedTransformer;
-use Symfony\Component\Form\ValueTransformer\DateTimeToStringTransformer;
-use Symfony\Component\Form\ValueTransformer\DateTimeToTimestampTransformer;
-use Symfony\Component\Form\ValueTransformer\DateTimeToArrayTransformer;
-use Symfony\Component\Form\ValueTransformer\ValueTransformerChain;
-
-/**
- * A field for editing a date and a time simultaneously.
- *
- * Available options:
- *
- *  * date_widget:    How to render the date field ("input" or "choice"). Default: "choice".
- *  * time_widget:    How to render the time field ("input" or "choice"). Default: "choice".
- *  * type:           The type of the date stored on the object. Default: "datetime":
- *                    * datetime:   A DateTime object;
- *                    * string:     A raw string (e.g. 2011-05-01 12:30:00, Y-m-d H:i:s);
- *                    * timestamp:  A unix timestamp (e.g. 1304208000).
- *  * date_pattern:   The pattern for the select boxes when date "widget" is "choice".
- *                    You can use the placeholders "{{ year }}", "{{ month }}" and "{{ day }}".
- *                    Default: locale dependent.
- *  * with_seconds    Whether or not to create a field for seconds. Default: false.
- *
- *  * years:          An array of years for the year select tag.
- *  * months:         An array of months for the month select tag.
- *  * days:           An array of days for the day select tag.
- *  * hours:          An array of hours for the hour select tag.
- *  * minutes:        An array of minutes for the minute select tag.
- *  * seconds:        An array of seconds for the second select tag.
- *
- *  * date_format:    The date format type to use for displaying the date. Default: medium.
- *  * data_timezone:  The timezone of the data. Default: UTC.
- *  * user_timezone:  The timezone of the user entering a new value. Default: UTC.
- *
- * @author Bernhard Schussek <bernhard.schussek@symfony-project.com>
- */
-class DateTimeField extends Form
-{
-    const DATETIME = 'datetime';
-    const STRING = 'string';
-    const TIMESTAMP = 'timestamp';
-
-    protected static $types = array(
-        self::DATETIME,
-        self::STRING,
-        self::TIMESTAMP,
-    );
-
-    protected static $dateFormats = array(
-        DateField::FULL,
-        DateField::LONG,
-        DateField::MEDIUM,
-        DateField::SHORT,
-    );
-
-    protected static $dateWidgets = array(
-        DateField::CHOICE,
-        DateField::INPUT,
-    );
-
-    protected static $timeWidgets = array(
-        TimeField::CHOICE,
-        TimeField::INPUT,
-    );
-
-    /**
-     * {@inheritDoc}
-     */
-    public function __construct($key, array $options = array())
-    {
-        // Override parent option
-        // \DateTime objects are never edited by reference, because
-        // we treat them like value objects
-        $this->addOption('by_reference', false);
-
-        parent::__construct($key, $options);
-    }
-
-    protected function configure()
-    {
-        $this->addOption('date_widget', DateField::CHOICE, self::$dateWidgets);
-        $this->addOption('time_widget', TimeField::CHOICE, self::$timeWidgets);
-        $this->addOption('type', self::DATETIME, self::$types);
-        $this->addOption('date_pattern');
-        $this->addOption('with_seconds', false);
-
-        $this->addOption('years', array());
-        $this->addOption('months', array());
-        $this->addOption('days', array());
-        $this->addOption('hours', array());
-        $this->addOption('minutes', array());
-        $this->addOption('seconds', array());
-
-        $this->addOption('data_timezone', date_default_timezone_get());
-        $this->addOption('user_timezone', date_default_timezone_get());
-        $this->addOption('date_format', DateField::MEDIUM, self::$dateFormats);
-
-        $this->add(new DateField('date', array(
-            'type' => DateField::RAW,
-            'widget' => $this->getOption('date_widget'),
-            'format' => $this->getOption('date_format'),
-            'data_timezone' => $this->getOption('user_timezone'),
-            'user_timezone' => $this->getOption('user_timezone'),
-            'years' => $this->getOption('years'),
-            'months' => $this->getOption('months'),
-            'days' => $this->getOption('days'),
-            'pattern' => $this->getOption('date_pattern'),
-        )));
-        $this->add(new TimeField('time', array(
-            'type' => TimeField::RAW,
-            'widget' => $this->getOption('time_widget'),
-            'data_timezone' => $this->getOption('user_timezone'),
-            'user_timezone' => $this->getOption('user_timezone'),
-            'with_seconds' => $this->getOption('with_seconds'),
-            'hours' => $this->getOption('hours'),
-            'minutes' => $this->getOption('minutes'),
-            'seconds' => $this->getOption('seconds'),
-        )));
-
-        if ($this->getOption('type') == self::STRING) {
-            $this->setNormalizationTransformer(new ReversedTransformer(
-                new DateTimeToStringTransformer(array(
-                    'input_timezone' => $this->getOption('data_timezone'),
-                    'output_timezone' => $this->getOption('data_timezone'),
-                ))
-            ));
-        } else if ($this->getOption('type') == self::TIMESTAMP) {
-            $this->setNormalizationTransformer(new ReversedTransformer(
-                new DateTimeToTimestampTransformer(array(
-                    'input_timezone' => $this->getOption('data_timezone'),
-                    'output_timezone' => $this->getOption('data_timezone'),
-                ))
-            ));
-        }
-
-        $this->setValueTransformer(new DateTimeToArrayTransformer(array(
-            'input_timezone' => $this->getOption('data_timezone'),
-            'output_timezone' => $this->getOption('user_timezone'),
-        )));
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    protected function transform($value)
-    {
-        $value = parent::transform($value);
-
-        return array('date' => $value, 'time' => $value);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    protected function reverseTransform($value)
-    {
-        return parent::reverseTransform(array_merge($value['date'], $value['time']));
-    }
-}

+ 106 - 4
src/Symfony/Component/Form/FormFactory.php

@@ -49,6 +49,7 @@ use Symfony\Component\Form\ValueTransformer\EntityToIdTransformer;
 use Symfony\Component\Form\ValueTransformer\EntitiesToArrayTransformer;
 use Symfony\Component\Form\ValueTransformer\ValueTransformerChain;
 use Symfony\Component\Form\ValueTransformer\ArrayToChoicesTransformer;
+use Symfony\Component\Form\ValueTransformer\ArrayToPartsTransformer;
 use Symfony\Component\Validator\ValidatorInterface;
 use Symfony\Component\Locale\Locale;
 
@@ -678,7 +679,7 @@ class FormFactory
             'widget',
         )));
 
-        $children = array('hour', 'minute');
+        $parts = array('hour', 'minute');
         $field = $this->getForm($key, $options)
             ->add($this->getHourField('hour', $childOptions))
             ->add($this->getMinuteField('minute', $childOptions))
@@ -687,7 +688,7 @@ class FormFactory
             ->setModifyByReference(false);
 
         if ($options['with_seconds']) {
-            $children[] = 'second';
+            $parts[] = 'second';
             $field->add($this->getSecondField('second', $childOptions));
         }
 
@@ -711,7 +712,7 @@ class FormFactory
                 new DateTimeToArrayTransformer(array(
                     'input_timezone' => $options['data_timezone'],
                     'output_timezone' => $options['data_timezone'],
-                    'fields' => $children,
+                    'fields' => $parts,
                 ))
             ));
         }
@@ -723,11 +724,112 @@ class FormFactory
                 // if the field is rendered as choice field, the values should be trimmed
                 // of trailing zeros to render the selected choices correctly
                 'pad' => $options['widget'] === 'text',
-                'fields' => $children,
+                'fields' => $parts,
             )))
             ->setRendererVar('widget', $options['widget'])
             ->setRendererVar('with_seconds', $options['with_seconds']);
 
         return $field;
     }
+
+    public function getDateTimeField($key, array $options = array())
+    {
+        $options = array_merge(array(
+            'template' => 'datetime',
+            'type' => 'datetime',
+            'with_seconds' => false,
+            'data_timezone' => date_default_timezone_get(),
+            'user_timezone' => date_default_timezone_get(),
+        ), $options);
+
+        // Only pass a subset of the options to children
+        $dateFieldOptions = array_intersect_key($options, array_flip(array(
+            'years',
+            'months',
+            'days',
+        )));
+        $timeFieldOptions = array_intersect_key($options, array_flip(array(
+            'hours',
+            'minutes',
+            'seconds',
+            'with_seconds',
+        )));
+
+        if (isset($options['date_pattern'])) {
+            $dateFieldOptions['pattern'] = $options['date_pattern'];
+        }
+        if (isset($options['date_widget'])) {
+            $dateFieldOptions['widget'] = $options['date_widget'];
+        }
+        if (isset($options['date_format'])) {
+            $dateFieldOptions['format'] = $options['date_format'];
+        }
+
+        $dateFieldOptions['type'] = 'array';
+
+        if (isset($options['time_pattern'])) {
+            $timeFieldOptions['pattern'] = $options['time_pattern'];
+        }
+        if (isset($options['time_widget'])) {
+            $timeFieldOptions['widget'] = $options['time_widget'];
+        }
+        if (isset($options['time_format'])) {
+            $timeFieldOptions['format'] = $options['time_format'];
+        }
+
+        $timeFieldOptions['type'] = 'array';
+
+        $parts = array('year', 'month', 'day', 'hour', 'minute');
+        $timeParts = array('hour', 'minute');
+
+        if ($options['with_seconds']) {
+            $parts[] = 'second';
+            $timeParts[] = 'second';
+        }
+
+        $field = $this->getForm($key, $options)
+            ->setValueTransformer(new ValueTransformerChain(array(
+                new DateTimeToArrayTransformer(array(
+                    'input_timezone' => $options['data_timezone'],
+                    'output_timezone' => $options['user_timezone'],
+                )),
+                new ArrayToPartsTransformer(array(
+                    'date' => array('year', 'month', 'day'),
+                    'time' => $timeParts,
+                )),
+            )))
+            ->add($this->getDateField('date', $dateFieldOptions))
+            ->add($this->getTimeField('time', $timeFieldOptions))
+            // Don't modify \DateTime classes by reference, we treat
+            // them like immutable value objects
+            ->setModifyByReference(false)
+            ->setData(null); // hack: should be invoked automatically
+
+        if ($options['type'] == 'string') {
+            $field->setNormalizationTransformer(new ReversedTransformer(
+                new DateTimeToStringTransformer(array(
+                    'format' => 'Y-m-d H:i:s',
+                    'input_timezone' => $options['data_timezone'],
+                    'output_timezone' => $options['data_timezone'],
+                ))
+            ));
+        } else if ($options['type'] == 'timestamp') {
+            $field->setNormalizationTransformer(new ReversedTransformer(
+                new DateTimeToTimestampTransformer(array(
+                    'input_timezone' => $options['data_timezone'],
+                    'output_timezone' => $options['data_timezone'],
+                ))
+            ));
+        } else if ($options['type'] === 'array') {
+            $field->setNormalizationTransformer(new ReversedTransformer(
+                new DateTimeToArrayTransformer(array(
+                    'input_timezone' => $options['data_timezone'],
+                    'output_timezone' => $options['data_timezone'],
+                    'fields' => $parts,
+                ))
+            ));
+        }
+
+        return $field;
+    }
 }

+ 20 - 20
tests/Symfony/Tests/Component/Form/DateTimeFieldTest.php

@@ -21,12 +21,12 @@ class DateTimeFieldTest extends DateTimeTestCase
 {
     public function testSubmit_dateTime()
     {
-        $field = new DateTimeField('name', array(
+        $field = $this->factory->getDateTimeField('name', array(
             'data_timezone' => 'UTC',
             'user_timezone' => 'UTC',
-            'date_widget' => DateField::CHOICE,
-            'time_widget' => TimeField::CHOICE,
-            'type' => DateTimeField::DATETIME,
+            'date_widget' => 'choice',
+            'time_widget' => 'choice',
+            'type' => 'datetime',
         ));
 
         $field->submit(array(
@@ -48,12 +48,12 @@ class DateTimeFieldTest extends DateTimeTestCase
 
     public function testSubmit_string()
     {
-        $field = new DateTimeField('name', array(
+        $field = $this->factory->getDateTimeField('name', array(
             'data_timezone' => 'UTC',
             'user_timezone' => 'UTC',
-            'type' => DateTimeField::STRING,
-            'date_widget' => DateField::CHOICE,
-            'time_widget' => TimeField::CHOICE,
+            'type' => 'string',
+            'date_widget' => 'choice',
+            'time_widget' => 'choice',
         ));
 
         $field->submit(array(
@@ -73,12 +73,12 @@ class DateTimeFieldTest extends DateTimeTestCase
 
     public function testSubmit_timestamp()
     {
-        $field = new DateTimeField('name', array(
+        $field = $this->factory->getDateTimeField('name', array(
             'data_timezone' => 'UTC',
             'user_timezone' => 'UTC',
-            'type' => DateTimeField::TIMESTAMP,
-            'date_widget' => DateField::CHOICE,
-            'time_widget' => TimeField::CHOICE,
+            'type' => 'timestamp',
+            'date_widget' => 'choice',
+            'time_widget' => 'choice',
         ));
 
         $field->submit(array(
@@ -100,12 +100,12 @@ class DateTimeFieldTest extends DateTimeTestCase
 
     public function testSubmit_withSeconds()
     {
-        $field = new DateTimeField('name', array(
+        $field = $this->factory->getDateTimeField('name', array(
             'data_timezone' => 'UTC',
             'user_timezone' => 'UTC',
-            'date_widget' => DateField::CHOICE,
-            'time_widget' => TimeField::CHOICE,
-            'type' => DateTimeField::DATETIME,
+            'date_widget' => 'choice',
+            'time_widget' => 'choice',
+            'type' => 'datetime',
             'with_seconds' => true,
         ));
 
@@ -131,13 +131,13 @@ class DateTimeFieldTest extends DateTimeTestCase
 
     public function testSubmit_differentTimezones()
     {
-        $field = new DateTimeField('name', array(
+        $field = $this->factory->getDateTimeField('name', array(
             'data_timezone' => 'America/New_York',
             'user_timezone' => 'Pacific/Tahiti',
-            'date_widget' => DateField::CHOICE,
-            'time_widget' => TimeField::CHOICE,
+            'date_widget' => 'choice',
+            'time_widget' => 'choice',
             // don't do this test with DateTime, because it leads to wrong results!
-            'type' => DateTimeField::STRING,
+            'type' => 'string',
             'with_seconds' => true,
         ));