I recently build a DataTransformer
that will accept a variety of different date formats in the end (like 12/12/2012 or 12.12.2012 or 2012-12-12).
I'm assuming you are using Symfony 2.0. I've read that form component has changed somewhat in 2.1.
I had a similar problem - I wanted to have a datetime field that uses separate widgets for date and time (hour) input.
First of all, you have to create a separate form type for this field (which actually is a form in itself).
My code looks similar to this (altered for this example):
class MyDateTimeType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('date', 'date', array(
'label' => 'label.form.date',
'input' => 'datetime',
'widget' => 'single_text',
'format' => 'yyyy-MM-dd',
'error_bubbling' => true
))
->add('time', 'time', array(
'label' => 'label.form.time',
'input' => 'datetime',
'widget' => 'choice',
'error_bubbling' => true
));
$builder->appendClientTransformer(new DateTimeToDateTimeArrayTransformer());
}
public function getDefaultOptions(array $options)
{
return array(
'label' => 'label.form.date',
'error_bubbling' => false
);
}
public function getParent(array $options)
{
return 'form';
}
public function getName()
{
return 'my_datetime';
}
}
As you can see it is a form (don't let it confuse you) but we will use it as a single logical field. That's where the data transformer comes in. It has to split a single DateTime
instance into date and time to obtain data for the two subfields when displaying the form and vice-versa when the form is submitted.
The error_bubbling settings ensure that the errors generated by subfields attach to our new subfield and don't propagate to the top-level form, but you may have diferrent goal.
My data transformer looks like this:
class DateTimeToDateTimeArrayTransformer implements DataTransformerInterface
{
public function transform($datetime)
{
if(null !== $datetime)
{
$date = clone $datetime;
$date->setTime(12, 0, 0);
$time = clone $datetime;
$time->setDate(1970, 1, 1);
}
else
{
$date = null;
$time = null;
}
$result = array(
'date' => $date,
'time' => $time
);
return $result;
}
public function reverseTransform($array)
{
$date = $array['date'];
$time = $array['time'];
if(null == $date || null == $time)
return null;
$date->setTime($time->format('G'), $time->format('i'));
return $date;
}
}
Finally you can use it like that:
$builder->add('startDate', 'my_datetime', array(
'label' => 'label.form.date'
));
You have to register it as a service to use it by alias, otherwise instantiate it directly (new MyDateTimeType()
).
This may not be the prettiest solution but so is the form component in Symfony 2.0.