'add model transformer for a certain form field in form events
The only way that works I have found is to add model transformer in buildForm method of a form type, as these codes below:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$transformer = new IssueToNumberTransformer($entityManager);
$builder->add(
$builder->create('issue', 'text')->addModelTransformer($transformer)
);
}
But I have a form field which displays when a another form field has a valid value, so I'd rather create the form field in FormEvent::PRE_SET_DATA event.
1. one wrong way
->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($builder) {
/** @var $order \VMSP\OrderBundle\Entity\OrderInterface */
$order = $event->getData();
$form = $event->getForm();
/** @var $serviceType \VMSP\StoreBundle\Entity\ServiceType */
$serviceType = $order->getServiceType();
//only home service needs user's address
if ($serviceType && $serviceType->getType() == ServiceType::TYPE_HOME_SERVICE) {
//won't work
$form->add(
$builder->create('address','hidden')
->addModelTransformer($this->addressTransformer),
array(
'label' => 'vmsp_order.contact.form.address',
)
);
}
}
somebody suggested
$form->add(
$builder->create('address', 'hidden')
->addModelTransformer($this->addressTransformer),
array( 'label' => 'vmsp_order.contact.form.address')
);
unfortunately, it throws this error:
Expected argument of type "string, integer or Symfony\Component\Form\FormInterface", "Symfony\Component\Form\FormBuilder" given
2. another wrong way
if ($serviceType && $serviceType->getType() == ServiceType::TYPE_HOME_SERVICE) {
$form->add(
'address',
'hidden',
array('label' => 'vmsp_order.contact.form.address')
);
$form->get('address')
->getConfig()
->addModelTransformer($this->addressTransformer);
}
got error:
FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.
I list the two wrong ways above, because I find lots of post saying these ways are right, of course, they are not. this post is a same question like symfony2-form-events-and-model-transformers , but that answer is not what I need, so my question is, any way to add model transformer in form events for a certain form field?
Solution 1:[1]
Your "1. one wrong way" doesn't work because $builder->addModelTransformer() returns a FormConfigBuilderInterface but $form->add() expects a FormInterface (see your error message).
To make it work, just add getForm() :
$form->add(
$builder->create('address','hidden')
->addModelTransformer($this->addressTransformer)
->getForm() // Creates the form
...
Solution 2:[2]
I recommend to do it in reverse mode. Configurate your hidden address field and remove it later if neccessary:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$transformer = new IssueToNumberTransformer($entityManager);
$builder->add(
$builder->create('issue', 'text')->addModelTransformer($transformer)
)->add('address','hidden')
->addModelTransformer($this->addressTransformer);
}
Then, check in listener if the hidden field should be removed:
->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($builder) {
/** @var $order \VMSP\OrderBundle\Entity\OrderInterface */
$order = $event->getData();
$form = $event->getForm();
/** @var $serviceType \VMSP\StoreBundle\Entity\ServiceType */
$serviceType = $order->getServiceType();
//only home service needs user's address
if (!$serviceType || $serviceType->getType() != ServiceType::TYPE_HOME_SERVICE) {
//will work
$form->remove('address');
}
}
I am wondering why the first wrong way does not working? Which error appears?
Solution 3:[3]
Thanks to @gblock I managed to get the job done to add a ModelTransformer in a form event. But I'm going to provide a better example.
I needed for instance to set these extra options before it worked: I needed the DateTimeToStringTransformer in my Form Event because the date format relied on data from the entity
'data_class' => null,
'auto_initialize' => false,
Short example:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($builder) {
$form = $event->getForm();
$timeStampField = $builder->create('timestamp', TextType::class, [
'data_class' => null,
'auto_initialize' => false,
])
->addModelTransformer(new DateTimeToStringTransformer(null, null, 'd-m-Y H:i'))
->getForm()
;
$form->add($timeStampField);
});
}
Long example:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
// Some other fields not relying on the entity
;
// Important! Pass the builder into the event listener with -> "use ($builder)"
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($builder) {
$form = $event->getForm();
$entity = $event->getData() ?: new MyEntity();
// In this example: set some stuff related to entity being "editable"
$isEditable = $entity->isEditable();
// In this example: we want different timestamp for an un-editable entity
$dateTimeFormat = $isEditable ? 'd-m-Y H:i' : 'd-m-Y H:i:s';
$timeStampField = $builder->create('timestamp', TextType::class, [
'label' => 'time',
'data' => $entity->getDate(),
// For this example: we want to have our un-editable entities to be "mapped: false"
'mapped' => $isEditable,
/**
* These options are important in this case:
* data_class: null
* auto_initialize: false
*/
'data_class' => null,
'auto_initialize' => false,
])
->addModelTransformer(new DateTimeToStringTransformer(null, null, $dateTimeFormat))
// Important line: In FormEvent we really need it to be "Form" and not "FormBuilder"
->getForm()
;
$form->add($timeStampField);
});
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | gblock |
| Solution 2 | Rawburner |
| Solution 3 |
