Correct way to use FormEvents to customise fields in SonataAdmin

≯℡__Kan透↙ 提交于 2019-11-27 18:50:24

问题


I have a Sonata Admin class with some form fields in it, but I'd like to use the FormEvents::PRE_SET_DATA event to dynamically add another form field based on the bound data.

However, I'm running into several problems:

1) The only way I can find to add the form field to the correct 'formGroup' in the admin is by adding the new field twice (once via the formMapper and once via the form itself)... this seems very wrong and I cannot control where in the formGroup it appears.

2) The added element doesn't seem to know that it has a connected Admin (probably because it is added using Form::add()). This means, amongst other things, that it renders differently to the other fields in the form since it triggers the {% if sonata_admin is not defined or not sonata_admin_enabled or not sonata_admin.field_description %} condition in form_admin_fields.html.twig

So, this leads me to believe that I'm doing this all wrong and there must be a better way.

So...

What is the correct way to use a FormEvent to add a field to a form group, ideally in a preferred position within that group, when using SonataAdmin?

Here's some code, FWIW...

protected function configureFormFields(FormMapper $formMapper)
{
    $admin = $this;
    $formMapper->getFormBuilder()->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($admin, $formMapper) {
        $subject = $event->getData();

        // do something fancy with $subject
        $formOptions = array(/* some cool stuff*/);

        // If I don't add the field with the $formMapper then the new field doesn't appear on the rendered form
        $formMapper
            ->with('MyFormGroup')
                ->add('foo', null, $formOptions)
            ->end()
        ;

        // If I don't add the field with Form::add() then I get a Twig Exception: 
        // Key "foo" for array with keys "..." does not exist in my_form_template.html.twig at line xx
        $event
            ->getForm()
            ->add('foo', null, $formOptions)
        ;
    });

    $formMapper
        ->with('MyFormGroup')
            ->add('fieldOne')
            ->add('fieldTwo')
        ->end()
    ;
}

The aim is to add the new foo field between fieldOne and fieldTwo in MyFormGroup.


Edit: here's what I came up with with the help of Cassiano's answer

protected function configureFormFields(FormMapper $formMapper)
{
    $builder = $formMapper->getFormBuilder();
    $ff = $builder->getFormFactory();
    $admin = $this;
    $formMapper->getFormBuilder()->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($ff, $admin) {
        $subject = $event->getData();

        // do something fancy with $subject
        $formOptions = array(
            'auto_initialize'       => false,
            'class'                 => 'My\ProjectBundle\Entity\MyEntity',
            /* some cool stuff*/
        );

        $event->getForm()->add($ff->createNamed('foo', 'entity', null, $formOptions));
    });

    $formMapper
        ->with('MyFormGroup')
            ->add('fieldOne')
            ->add('foo')  // adding it here gets the field in the right place, it's then redefined by the event code
            ->add('fieldTwo')
        ->end()
    ;
}

回答1:


No time here for a long answer, I will paste a piece of code and I don't know if fits exactly in your case, in my it's part of multi dependent selects (country, state, city, neighbor).

use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormEvent;
use Doctrine\ORM\EntityRepository;

protected function configureFormFields(FormMapper $formMapper)
{
    $formMapper->add('myfield');

    $builder = $formMapper->getFormBuilder();
    $ff = $builder->getFormFactory();
    $func = function (FormEvent $e) use ($ff) {
        $form = $e->getForm();
        if ($form->has('myfield')) {
            $form->remove('myfield');
        }
        $form->add($ff->createNamed('myfield', 'entity', null, array(
            'class' => '...',
            'attr' => array('class' => 'form-control'),
            'auto_initialize' => false,
            'query_builder' => function (EntityRepository $repository) use ($pais) {
                $qb = $repository->createQueryBuilder('estado');
                if ($pais instanceof ...) {
                    $qb = $qb->where('myfield.other = :other')
                            ->setParameter('other', $other);
                } elseif(is_numeric($other)) {
                    $qb = $qb->where('myfield.other = :other_id')
                            ->setParameter('other_id', $other);
                }
                return $qb;
            }
        )));
    };
    $builder->addEventListener(FormEvents::PRE_SET_DATA, $func);
    $builder->addEventListener(FormEvents::PRE_BIND, $func);
}


来源:https://stackoverflow.com/questions/26246192/correct-way-to-use-formevents-to-customise-fields-in-sonataadmin

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!