reverseTransform в DataTransformer не работает

Я создал пользовательский тип поля формы «длительность» и 2 поля «час» и «минуты».

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';
    }
}

ДлительностьСмаллТип:

class DurationSmallType extends AbstractType
{

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

Шаблон для обоих типов:

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

В Entity продолжительность сохраняется в минутах (как целое число), и я создаю DataTransformer в построителе форм:

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';
    }
}

Длительностьтоминутестрансформер:

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

Преобразование - работает, у меня есть часы и минуты в поле редактирования, но reverseTransform не работает, после отправки у меня есть поле длительности как массив.

Ошибка симфонии:

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.

Помогите мне, пожалуйста.


person Alexey Ivanov    schedule 18.01.2015    source источник
comment
что передается методу reverseTransform? отладьте его и посмотрите, что произойдет   -  person Peter Popelyshko    schedule 18.01.2015
comment
Я не знаю, это не исключение, это ошибка на вкладке формы профилировщика.   -  person Alexey Ivanov    schedule 18.01.2015


Ответы (1)


Я нахожу ошибку, DurationSmallType нужна опция component=false, по умолчанию — true, и symfony пытается использовать мои 2 поля как внутреннюю форму. И я удаляю modelTransformer из формы объекта и помещаю его в DurationType.

Окончательный код моих конструкторов форм:

Тип события:

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';
    }
}

Тип продолжительности:

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';
    }
}

ДлительностьСмаллТип:

class DurationSmallType extends AbstractType
{

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

    public function getName()
    {
        return 'duration_small';
    }
}
person Alexey Ivanov    schedule 18.01.2015
comment
установка соединения на false также решила эту проблему для меня. Благодарность ! - person Sébastien; 27.09.2015