Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DataTransformer - split DateTime into two fields

Tags:

forms

php

symfony

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).

My question is: before I had the date and time split up into two different fields:

$builder->add('date_end', 'datetime', array(
        'label' => 'Date/Time',
        'date_widget' => 'single_text',
        'time_widget' => 'single_text',
        'date_format' => 'dd.MM.yyyy',
        'with_seconds' => false,
        'required' => false,
    ) )

Which worked fine. How can I accomplish this with the new DataTransformer?

Within my entity-type:

public function buildForm(FormBuilder $builder, array $options) {

    builder->add('date_end', 'dateTime', array(
        'label' => 'Date/Time',
        'required' => false,
    ) )
}

The corresponding DateTimeType I created:

class DateTimeType extends AbstractType {
    private $om;

    public function __construct(ObjectManager $om) {
        $this->om = $om;
    }

    public function buildForm(FormBuilder $builder, array $options) {
        $transformer = new DateTimeTransformer($this->om);
        $builder->appendClientTransformer($transformer);
    }

    public function getDefaultOptions(array $options) {
        return array(
            'invalid_message' => 'TODO INVALID',
        );
    }

    public function getParent(array $options) {
        return 'text';
    }

    public function getName(){
        return 'dateTime';
    }
}

My transformer so far:

/**
 * @param  \DateTime|null $dateTime
 * @return string|null
 */
public function transform($dateTime) {
    if (null === $dateTime) {
        return null;
    }

    return $dateTime->format('Y-m-d H:i');
}

/**
 * @param  string $value
 * @return string|null
 */
public function reverseTransform($value)
{
    if ( (null === $value) || empty($value) ) {
        return null;
    }
    return new \DateTime( $value );

}
like image 539
insertusernamehere Avatar asked Mar 17 '26 00:03

insertusernamehere


1 Answers

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.

like image 66
pinkeen Avatar answered Mar 18 '26 14:03

pinkeen



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!