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
This commit is contained in:
Fabien Potencier 2011-06-24 07:48:05 +02:00
commit cca21a84e3
5 changed files with 178 additions and 80 deletions

View File

@ -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 %}

View File

@ -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 ?>

View File

@ -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}
*/

View File

@ -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"]
'
);
}

View File

@ -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',
));
}
}