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.
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';
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With