Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

reverseTransform in DataTransformer doesn't work

I created a custom form field type "duration", and 2 fields "hour" and "minutes"

class DurationType extends AbstractType
{

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults([]);
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('hours', new DurationSmallType(), [])
            ->add('minutes', new DurationSmallType(), [])
        ;
    }

    public function finishView(FormView $view, FormInterface $form, array $options)
    {
    }

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

DurationSmallType:

class DurationSmallType extends AbstractType
{

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

Template for both types:

{% block duration_small_widget -%}
<div class="input-group" style="display: inline-block;width:100px;height: 34px;margin-right: 20px;">
    <input type="text" {{ block('widget_attributes') }} class="form-control" style="width:50px;" {% if value is not empty %}value="{{ value }}" {% endif %}>
    <span class="input-group-addon" style="height: 34px;"></span>
</div>
{%- endblock duration_small_widget %}

{% block duration_widget -%}

    {{ form_widget(form.hours) }}
    {{ form_widget(form.minutes) }}

{%- endblock duration_widget %}

In Entity duration saved in minutes (as integer) and I create a DataTransformer in form builder:

class EventType extends AbstractType
    {
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $dataTransformer = new DurationToMinutesTransformer();

        $builder
            ->add('name', NULL, array('label' => 'Название'))
            ->add('type', NULL, array('label' => 'Раздел'))
            ->add($builder
                ->create('duration', new DurationType(), array('label' => 'Продолжительность'))
                ->addModelTransformer($dataTransformer)
            )
        ->add('enabled', NULL, array('label' => 'Включено'));
    }

    /**
     * @param OptionsResolverInterface $resolver
     */
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'TourConstructor\MainBundle\Entity\Event',
            'csrf_protection' => true,
            'csrf_field_name' => '_token',
            'intention' => 'events_token'
        ));
    }

    /**
     * @return string
     */
    public function getName()
    {
        return 'mybundle_event';
    }
}

DurationToMinutesTransformer:

class DurationToMinutesTransformer implements DataTransformerInterface
{
    public function transform($value)
    {

        if (!$value) {
            return null;
        }

        $hours = ceil($value / 60);
        $minutes = $value % 60;

        return [
            "hours" => $hours,
            "minutes" => $minutes
        ];
    }

    public function reverseTransform($value)
    {
        if (!$value) {
            return null;
        }

        return $value["hours"]*60 + $value["minutes"];
    }
}

Transform - work, I have hours and minutes in edit field, but reverseTransform doesn't work, after submit I have duration field as Array.

Symfony error:

Symfony\Component\Validator\ConstraintViolation
Object(Symfony\Component\Form\Form).children[duration].children[hours] = 3

Caused by:

Symfony\Component\Form\Exception\TransformationFailedException
Compound forms expect an array or NULL on submission.

Symfony\Component\Validator\ConstraintViolation
Object(Symfony\Component\Form\Form).children[duration].children[minutes] = 0

Caused by:

Symfony\Component\Form\Exception\TransformationFailedException
Compound forms expect an array or NULL on submission.

Please, help me.

like image 987
Alexey Ivanov Avatar asked Jan 18 '15 11:01

Alexey Ivanov


1 Answers

I find error, DurationSmallType need option compound=false, default is true and symfony try to use my 2 field as inside form. And I remove modelTransformer from entity form and place it in DurationType.

Finaly code of my forms builders:

EventType:

class EventType extends AbstractType
    {
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $dataTransformer = new DurationToMinutesTransformer();

        $builder
            ->add('name', NULL, array('label' => 'Название'))
            ->add('type', NULL, array('label' => 'Раздел'))
            ->add($builder
                ->create('duration', new DurationType(), array('label' => 'Продолжительность'))
                ->addModelTransformer($dataTransformer)
            )
        ->add('enabled', NULL, array('label' => 'Включено'));
    }

    /**
     * @param OptionsResolverInterface $resolver
     */
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'TourConstructor\MainBundle\Entity\Event',
            'csrf_protection' => true,
            'csrf_field_name' => '_token',
            'intention' => 'events_token'
        ));
    }

    /**
     * @return string
     */
    public function getName()
    {
        return 'mybundle_event';
    }
}

DurationType:

class DurationType extends AbstractType
{

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {

        $resolver->setDefaults(array(
            'html5' => true,
            'error_bubbling' => false,
            'compound' => true,
        ));
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('hours', new DurationSmallType(), [
                "label"=>"ч."
            ])
            ->add('minutes', new DurationSmallType(), [
                "label"=>"мин."
            ])
            ->addViewTransformer(new DurationToMinutesTransformer())
        ;
    }

    public function finishView(FormView $view, FormInterface $form, array $options)
    {

    }

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

DurationSmallType:

class DurationSmallType extends AbstractType
{

    /**
     * {@inheritdoc}
     */
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'compound' => false,
        ));
    }

    public function getName()
    {
        return 'duration_small';
    }
}
like image 98
Alexey Ivanov Avatar answered Oct 21 '22 06:10

Alexey Ivanov