i am having problems with form events in an admin class. I have dynamically added choices in a custom entity type.Choices are added to the database by javascript via a controller.To be able to validate those dynamic choices (added after the form is renderd), i added a PRE_SUBMIT form event to the field in the admin class.So before the form is submitted i load the new choice list from db and remove and add the field back to the form to update its options, as shown here https://gist.github.com/webdevilopers/fef9e296e77bb879d138
In the twig template of the form type i use the sonata_admin.admin variable to get needed data. The problem is when there is an error in the form (on any other field anywhere in the form) the sonata_admin.admin variable form the twig template is null.
thanks for the help
$class = 'LibrinfoVarietiesBundle:SelectChoice';
$repo = $this->getConfigurationPool()->getContainer()->get('doctrine.orm.entity_manager')->getRepository($class);
$admin = $this;
$formBuilder = $formMapper->getFormBuilder();
$formBuilder->addEventListener(FormEvents::SUBMIT, function ($event) use ($formBuilder, $admin, $repo, $class) {
$form = $event->getForm();
$subject = $admin->getSubject($event->getData());
$label = 'librinfo_varieties_admin_variety_regulatory_status_librinfo_core_customchoice';
$choices = $repo->findBy(array(
'label' => $label
));
$choiceViews = array();
foreach ($choices as $choice)
{
$choiceViews[$choice->getvalue()] = $choice;
}
if ($form->has('regulatory_status'))
{
$form->remove('regulatory_status');
}
$customChoice = $formBuilder->getFormFactory()->createNamed('regulatory_status', 'librinfo_customchoice', null, array(
'choices' => $choices,
'class' => $class,
'auto_initialize' => false,
));
$form->add($customChoice);
});
$label = 'librinfo_varieties_admin_variety_regulatory_status_librinfo_core_customchoice';
$choices = $this->repo->findBy(array(
'label' => $label
));
$choiceViews = array();
foreach ($choices as $choice)
{
$choiceViews[$choice->getvalue()] = $choice;
}
$resolver->setDefaults(array(
'choice_label' => 'value',
'class' => 'LibrinfoVarietiesBundle:SelectChoice',
'placeholder' => '',
'choices' => $choiceViews,
));
{% block librinfo_customchoice_widget %}
{% set subject = sonata_admin.admin.subject %}
{% spaceless %}
{{ block('choice_widget') }}
{% if subject.fieldset is defined %}
<a id="{{ subject.fieldset }}_{{ subject.field }}" class="add-choice editable editable-click inline-input" href="#"><i class="fa fa-plus-circle"></i></a>
{% else %}
<a id="{{ block_prefixes.4 }}" class="add-choice editable editable-click inline-input" href="#"><i class="fa fa-plus-circle"></i></a>
{% endif %}
{% endspaceless %}
{% endblock %}
This is because the Sonata FormTypeFieldExtension
is not called when you directly add field to the form object trough events.
But I found a workaround, you have to add the field with the FormMapper first. This will setup sonata admin options.
Then, on your event callback, get back the current options of the field and merge them with your own:
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('date', null, [
'widget' => 'single_text',
])
->add('method', EnumType::class, [
'class' => PaymentMethod::class,
'translation_domain' => 'global',
'prefix_label_with_class' => true,
'attr' => [
'class' => 'payment-method',
],
])
->add('reference', TextType::class, [
'required' => false,
'attr' => [
'class' => 'payment-reference',
]
])
->add('amount')
;
$builder = $formMapper->getFormBuilder();
$factory = $builder->getFormFactory();
$referenceTypeMaker = function (FormEvent $event) use ($factory) {
$form = $event->getForm();
$data = $event->getData();
$paymentMethod = $data instanceof Payment ? $data->getMethod() : $data['method'];
if (PaymentMethod::CREDIT_NOTE === $paymentMethod) {
$form->add($factory->createNamed('reference', CreditNoteRefType::class, null, array_merge(
$form->get('reference')->getConfig()->getOptions(), // Put back original options here.
[
'auto_initialize' => false
]
)));
}
};
$builder->addEventListener(FormEvents::PRE_SET_DATA, $referenceTypeMaker);
$builder->addEventListener(FormEvents::PRE_SUBMIT, $referenceTypeMaker);
}
As you can see on my code sample, the reference
field is a TextType
but can be a CreditNoteRefType
depending on the payment method choice.
Putting back the already defined field options to the new one solve the issue.