Ver Fonte

[Form] Started to refactor DateField to FormFactory::getDateField(). Validation logic is still missing.

Bernhard Schussek há 14 anos atrás
pai
commit
975b8ebe9b

+ 9 - 11
src/Symfony/Bundle/TwigBundle/Resources/views/form.html.twig

@@ -113,7 +113,13 @@
 
 {% block choice__widget %}
 {% spaceless %}
-    <select {{ block('field_attributes') }}{% if field.isMultipleChoice %} multiple="multiple"{% endif %}>
+    {% if expanded %}
+        {% for choice, child in field %}
+            {{ child.renderer.widget }}
+            {{ child.renderer.label(choice_list.label(choice)) }}
+        {% endfor %}
+    {% else %}
+    <select {{ block('field_attributes') }}{% if multiple %} multiple="multiple"{% endif %}>
         {% if not field.required %}
             <option value="">{{ empty_value }}</option>
         {% endif %}
@@ -125,18 +131,10 @@
         {% set options = choices %}
         {{ block('options') }}
     </select>
+    {% endif %}
 {% endspaceless %}
 {% endblock choice__widget %}
 
-{% block choice_expanded__widget %}
-{% spaceless %}
-    {% for choice, child in field %}
-        {{ child.renderer.widget }}
-        {{ child.renderer.label(choice_list.label(choice)) }}
-    {% endfor %}
-{% endspaceless %}
-{% endblock choice_expanded__widget %}
-
 {% block checkbox__widget %}
 {% spaceless %}
     <input type="checkbox" {{ block('field_attributes') }}{% if value is defined %} value="{{ value }}"{% endif %}{% if field.data %} checked="checked"{% endif %} />
@@ -160,7 +158,7 @@
 
 {% block date__widget %}
 {% spaceless %}
-    {% if field.isField %}
+    {% if widget == 'text' %}
         {{ block('text__widget') }}
     {% else %}
         {{ date_pattern|replace({ 

+ 0 - 24
src/Symfony/Component/Form/ChoiceList/DayChoiceList.php

@@ -1,24 +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\ChoiceList;
-
-class DayChoiceList extends PaddedChoiceList
-{
-    public function __construct(array $days = array(), array $preferredChoices = array())
-    {
-        if (count($days) === 0) {
-            $days = range(1, 31);
-        }
-
-        parent::__construct($days, 2, '0', STR_PAD_LEFT, $preferredChoices);
-    }
-}

+ 1 - 5
src/Symfony/Component/Form/ChoiceList/MonthChoiceList.php

@@ -20,12 +20,8 @@ class MonthChoiceList extends PaddedChoiceList
      * @return array          The localized months respecting the configured
      *                        locale and date format
      */
-    public function __construct(\IntlDateFormatter $formatter, array $months = array(), array $preferredChoices = array())
+    public function __construct(\IntlDateFormatter $formatter, array $months, array $preferredChoices = array())
     {
-        if (count($months) === 0) {
-            $months = range(1, 12);
-        }
-
         $pattern = $formatter->getPattern();
 
         if (preg_match('/M+/', $pattern, $matches)) {

+ 0 - 24
src/Symfony/Component/Form/ChoiceList/YearChoiceList.php

@@ -1,24 +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\ChoiceList;
-
-class YearChoiceList extends PaddedChoiceList
-{
-    public function __construct(array $years = array(), array $preferredChoices = array())
-    {
-        if (count($years) === 0) {
-            $years = range(date('Y') - 5, date('Y') + 5);
-        }
-
-        parent::__construct($years, 4, '0', STR_PAD_LEFT, $preferredChoices);
-    }
-}

+ 6 - 7
src/Symfony/Component/Form/DateField.php

@@ -17,9 +17,8 @@ use Symfony\Component\Form\ValueTransformer\DateTimeToTimestampTransformer;
 use Symfony\Component\Form\ValueTransformer\ValueTransformerChain;
 use Symfony\Component\Form\ValueTransformer\DateTimeToLocalizedStringTransformer;
 use Symfony\Component\Form\ValueTransformer\DateTimeToArrayTransformer;
-use Symfony\Component\Form\ChoiceList\YearChoiceList;
+use Symfony\Component\Form\ChoiceList\PaddedChoiceList;
 use Symfony\Component\Form\ChoiceList\MonthChoiceList;
-use Symfony\Component\Form\ChoiceList\DayChoiceList;
 
 /**
  * Represents a date field.
@@ -111,9 +110,9 @@ class DateField extends HybridField
         $this->addOption('type', self::DATETIME, self::$types);
         $this->addOption('pattern');
 
-        $this->addOption('years', array());
-        $this->addOption('months', array());
-        $this->addOption('days', array());
+        $this->addOption('years', range(date('Y') - 5, date('Y') + 5));
+        $this->addOption('months', range(1, 12));
+        $this->addOption('days', range(1, 31));
 
         $this->addOption('format', self::MEDIUM, self::$formats);
         $this->addOption('data_timezone', date_default_timezone_get());
@@ -168,13 +167,13 @@ class DateField extends HybridField
             $this->setFieldMode(self::FORM);
 
             $this->add(new ChoiceField('year', array(
-                'choice_list' => new YearChoiceList($this->getOption('years')),
+                'choice_list' => new PaddedChoiceList($this->getOption('years'), 2, '0', STR_PAD_LEFT),
             )));
             $this->add(new ChoiceField('month', array(
                 'choice_list' => new MonthChoiceList($this->formatter, $this->getOption('months')),
             )));
             $this->add(new ChoiceField('day', array(
-                'choice_list' => new DayChoiceList($this->getOption('days')),
+                'choice_list' => new PaddedChoiceList($this->getOption('days'), 2, '0', STR_PAD_LEFT),
             )));
         }
     }

+ 18 - 2
src/Symfony/Component/Form/Form.php

@@ -73,6 +73,8 @@ class Form extends Field implements \IteratorAggregate, FormInterface
 
     private $dataPreprocessor;
 
+    private $modifyByReference;
+
     /**
      * Creates a new form with the options stored in the given context
      *
@@ -130,6 +132,8 @@ class Form extends Field implements \IteratorAggregate, FormInterface
 
             $this->add(new HiddenField($fieldName, array('data' => $token)));
         }
+
+        $this->modifyByReference = $this->getOption('by_reference');
     }
 
     /**
@@ -227,7 +231,7 @@ class Form extends Field implements \IteratorAggregate, FormInterface
             $field->readProperty($data);
         }
 
-        return $field;
+        return $this;
     }
 
     /**
@@ -946,7 +950,7 @@ class Form extends Field implements \IteratorAggregate, FormInterface
         // Don't write into $objectOrArray if $objectOrArray is an object,
         // $isReference is true (see above) and the option "by_reference" is
         // true as well
-        if (!is_object($objectOrArray) || !$isReference || !$this->getOption('by_reference')) {
+        if (!is_object($objectOrArray) || !$isReference || !$this->modifyByReference) {
             parent::writeProperty($objectOrArray);
         }
     }
@@ -987,6 +991,18 @@ class Form extends Field implements \IteratorAggregate, FormInterface
         return $this->dataPreprocessor;
     }
 
+    public function setModifyByReference($modifyByReference)
+    {
+        $this->modifyByReference = $modifyByReference;
+
+        return $this;
+    }
+
+    public function isModifiedByReference()
+    {
+        return $this->modifyByReference;
+    }
+
     /**
      * Merges two arrays without reindexing numeric keys.
      *

+ 143 - 16
src/Symfony/Component/Form/FormFactory.php

@@ -12,16 +12,21 @@
 namespace Symfony\Component\Form;
 
 use Symfony\Component\Form\ValueTransformer\BooleanToStringTransformer;
+use Symfony\Component\Form\ChoiceList\ChoiceListInterface;
 use Symfony\Component\Form\ChoiceList\DefaultChoiceList;
+use Symfony\Component\Form\ChoiceList\PaddedChoiceList;
+use Symfony\Component\Form\ChoiceList\MonthChoiceList;
 use Symfony\Component\Form\DataProcessor\RadioToArrayConverter;
 use Symfony\Component\Form\Renderer\DefaultRenderer;
 use Symfony\Component\Form\Renderer\Theme\ThemeInterface;
 use Symfony\Component\Form\Renderer\Plugin\IdPlugin;
 use Symfony\Component\Form\Renderer\Plugin\NamePlugin;
-use Symfony\Component\Form\Renderer\Plugin\ValuePlugin;
+use Symfony\Component\Form\Renderer\Plugin\ParameterPlugin;
 use Symfony\Component\Form\Renderer\Plugin\ChoicePlugin;
 use Symfony\Component\Form\Renderer\Plugin\ParentNamePlugin;
+use Symfony\Component\Form\Renderer\Plugin\DatePatternPlugin;
 use Symfony\Component\Form\ValueTransformer\ScalarToChoicesTransformer;
+use Symfony\Component\Form\ValueTransformer\DateTimeToArrayTransformer;
 
 class FormFactory
 {
@@ -64,18 +69,18 @@ class FormFactory
 
     public function getCheckboxField($key, array $options = array())
     {
-        $options = array_replace(array(
+        $options = array_merge(array(
             'value' => '1',
         ), $options);
 
         return $this->getField($key, 'checkbox')
             ->setValueTransformer(new BooleanToStringTransformer())
-            ->addRendererPlugin(new ValuePlugin($options['value']));
+            ->addRendererPlugin(new ParameterPlugin('value', $options['value']));
     }
 
     public function getRadioField($key, array $options = array())
     {
-        $options = array_replace(array(
+        $options = array_merge(array(
             'value' => null,
         ), $options);
 
@@ -84,27 +89,20 @@ class FormFactory
         return $field
             ->setValueTransformer(new BooleanToStringTransformer())
             ->addRendererPlugin(new ParentNamePlugin($field))
-            ->addRendererPlugin(new ValuePlugin($options['value']));
+            ->addRendererPlugin(new ParameterPlugin('value', $options['value']));
     }
 
-    public function getChoiceField($key, array $options = array())
+    protected function getChoiceFieldForList($key, ChoiceListInterface $choiceList, array $options = array())
     {
-        $options = array_replace(array(
-            'choices' => array(),
-            'preferred_choices' => array(),
+        $options = array_merge(array(
             'multiple' => false,
             'expanded' => false,
         ), $options);
 
-        $choiceList = new DefaultChoiceList(
-            $options['choices'],
-            $options['preferred_choices']
-        );
-
         if (!$options['expanded']) {
             $field = $this->getField($key, 'choice');
         } else {
-            $field = $this->getForm($key, 'choice_expanded');
+            $field = $this->getForm($key, 'choice');
             $choices = array_merge($choiceList->getPreferredChoices(), $choiceList->getOtherChoices());
 
             foreach ($choices as $choice => $value) {
@@ -120,7 +118,9 @@ class FormFactory
             }
         }
 
-        $field->addRendererPlugin(new ChoicePlugin($choiceList));
+        $field->addRendererPlugin(new ChoicePlugin($choiceList))
+            ->addRendererPlugin(new ParameterPlugin('multiple', $options['multiple']))
+            ->addRendererPlugin(new ParameterPlugin('expanded', $options['expanded']));
 
         if ($options['multiple'] && $options['expanded']) {
             $field->setValueTransformer(new ArrayToChoicesTransformer($choiceList));
@@ -137,4 +137,131 @@ class FormFactory
 
         return $field;
     }
+
+    public function getChoiceField($key, array $options = array())
+    {
+        $options = array_merge(array(
+            'choices' => array(),
+            'preferred_choices' => array(),
+        ), $options);
+
+        $choiceList = new DefaultChoiceList(
+            $options['choices'],
+            $options['preferred_choices']
+        );
+
+        return $this->getChoiceFieldForList($key, $choiceList, $options);
+    }
+
+    protected function getDayField($key, array $options = array())
+    {
+        $options = array_merge(array(
+            'days' => range(1, 31),
+            'preferred_choices' => array(),
+        ), $options);
+
+        $choiceList = new PaddedChoiceList(
+            $options['days'], 2, '0', STR_PAD_LEFT, $options['preferred_choices']
+        );
+
+        return $this->getChoiceFieldForList($key, $choiceList, $options);
+    }
+
+    protected function getMonthField($key, \IntlDateFormatter $formatter, array $options = array())
+    {
+        $options = array_merge(array(
+            'months' => range(1, 12),
+            'preferred_choices' => array(),
+        ), $options);
+
+        $choiceList = new MonthChoiceList(
+            $formatter, $options['months'], $options['preferred_choices']
+        );
+
+        return $this->getChoiceFieldForList($key, $choiceList, $options);
+    }
+
+    protected function getYearField($key, array $options = array())
+    {
+        $options = array_merge(array(
+            'years' => range(date('Y') - 5, date('Y') + 5),
+            'preferred_choices' => array(),
+        ), $options);
+
+        $choiceList = new PaddedChoiceList(
+            $options['years'], 4, '0', STR_PAD_LEFT, $options['preferred_choices']
+        );
+
+        return $this->getChoiceFieldForList($key, $choiceList, $options);
+    }
+
+    public function getDateField($key, array $options = array())
+    {
+        $options = array_merge(array(
+            'widget' => 'choice',
+            'type' => 'datetime',
+            'pattern' => null,
+            'format' => \IntlDateFormatter::MEDIUM,
+            'data_timezone' => date_default_timezone_get(),
+            'user_timezone' => date_default_timezone_get(),
+        ), $options);
+
+        $formatter = new \IntlDateFormatter(
+            \Locale::getDefault(),
+            $options['format'],
+            \IntlDateFormatter::NONE
+        );
+
+        if ($options['widget'] === 'text') {
+            $field = $this->getField($key, 'date')
+                ->setValueTransformer(new DateTimeToLocalizedStringTransformer(array(
+                    'date_format' => $options['format'],
+                    'time_format' => DateTimeToLocalizedStringTransformer::NONE,
+                    'input_timezone' => $options['data_timezone'],
+                    'output_timezone' => $options['user_timezone'],
+                )))
+                ->addRendererPlugin(new ParameterPlugin('widget', 'text'));
+        } else {
+            $field = $this->getForm($key, 'date')
+                ->add($this->getYearField('year', $options))
+                ->add($this->getMonthField('month', $formatter, $options))
+                ->add($this->getDayField('day', $options))
+                ->setValueTransformer(new DateTimeToArrayTransformer(array(
+                    'input_timezone' => $options['data_timezone'],
+                    'output_timezone' => $options['user_timezone'],
+                )))
+                ->addRendererPlugin(new ParameterPlugin('widget', 'choice'))
+                ->addRendererPlugin(new DatePatternPlugin($formatter))
+                // Don't modify \DateTime classes by reference, we treat
+                // them like immutable value objects
+                ->setModifyByReference(false);
+        }
+
+        if ($options['type'] === 'string') {
+            $field->setNormalizationTransformer(new ReversedTransformer(
+                new DateTimeToStringTransformer(array(
+                    'input_timezone' => $options['data_timezone'],
+                    'output_timezone' => $options['data_timezone'],
+                    'format' => 'Y-m-d',
+                ))
+            ));
+        } else if ($options['type'] === 'timestamp') {
+            $field->setNormalizationTransformer(new ReversedTransformer(
+                new DateTimeToTimestampTransformer(array(
+                    'output_timezone' => $options['data_timezone'],
+                    'input_timezone' => $options['data_timezone'],
+                ))
+            ));
+        } else if ($options['type'] === 'raw') {
+            $field->setNormalizationTransformer(new ReversedTransformer(
+                new DateTimeToArrayTransformer(array(
+                    'input_timezone' => $options['data_timezone'],
+                    'output_timezone' => $options['data_timezone'],
+                    'fields' => array('year', 'month', 'day'),
+                ))
+            ));
+        }
+
+        return $field;
+    }
 }

+ 6 - 5
src/Symfony/Component/Form/Renderer/Plugin/ValuePlugin.php

@@ -13,19 +13,20 @@ namespace Symfony\Component\Form\Renderer\Plugin;
 
 use Symfony\Component\Form\Renderer\RendererInterface;
 
-class ValuePlugin implements PluginInterface
+class ParameterPlugin implements PluginInterface
 {
+    private $name;
+
     private $value;
 
-    public function __construct($value = null)
+    public function __construct($name, $value)
     {
+        $this->name = $name;
         $this->value = $value;
     }
 
     public function setUp(RendererInterface $renderer)
     {
-        if (null !== $this->value) {
-            $renderer->setParameter('value', $this->value);
-        }
+        $renderer->setParameter($this->name, $this->value);
     }
 }