Extending EntityType to allow extra choices set with AJAX calls

一个人想着一个人 提交于 2019-11-29 14:53:03

问题


I try to create a Symfony Custom type extending the core "entity" type.

But I want to use it with Select2 version 4.0.0 (ajax now works with "select" html element and not with hidden "input" like before).

  • This type should create an empty select instead of the full list of entities by the extended "entity" type.

This works by setting the option (see configureOption):

'choices'=>array()
  • By editing the object attached to the form it should populate the select with the current data of the object. I solved this problem but just for the view with the following buildView method ...

Select2 recognize the content of the html "select", and does its work with ajax. But when the form is posted back, Symfony doesn't recognize the selected choices, (because there were not allowed ?)

Symfony\Component\Form\Exception\TransformationFailedException

    Unable to reverse value for property path "user": The choice "28" does not exist or is not unique

I tried several methods using EventListeners or Subscribers but I can't find a working configuration.

With Select2 3.5.* I solved the problem with form events and overriding the hidden formtype, but here extending the entitytype is much more difficult.

How can I build my type to let it manage the reverse transformation of my entites ?

Custom type :

<?php
namespace AppBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

use Symfony\Component\Form\ChoiceList\View\ChoiceView;

class AjaxEntityType extends AbstractType
{
    protected $router;

    public function __construct($router)
    {
        $this->router = $router;
    }

   /**
    * {@inheritdoc}
    */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {   
        $builder->setAttribute('attr',array_merge($options['attr'],array('class'=>'select2','data-ajax--url'=>$this->router->generate($options['route']))));
    }

    /**
    * {@inheritdoc}
    */
    public function buildView(FormView $view, FormInterface $form, array $options)
    {
        $view->vars['attr'] = $form->getConfig()->getAttribute('attr');
        $choices = array();
        $data=$form->getData();
        if($data instanceOf \Doctrine\ORM\PersistentCollection){$data = $data->toArray();}
        $values='';
        if($data != null){
            if(is_array($data)){
                foreach($data as $entity){
                    $choices[] = new ChoiceView($entity->getAjaxName(),$entity->getId(),$entity,array('selected'=>true));
                }
            }
            else{
                $choices[] = new ChoiceView($data->getAjaxName(),$data->getId(),$data,array('selected'=>true));
            }
        }

        $view->vars['choices']=$choices;
    }

   /**
    * {@inheritdoc}
    */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setRequired(array('route'));
        $resolver->setDefaults(array('choices'=>array(),'choices_as_value'=>true));
    }

    public function getParent() {
        return 'entity';
    }

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

Parent form

<?php
namespace AppBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class AlarmsType extends AbstractType
{
   /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('name','text',array('required'=>false))
            ->add('user','ajax_entity',array("class"=>"AppBundle:Users","route"=>"ajax_users"))
            ->add('submit','submit');
    }

    /**
     * @param OptionsResolver $resolver
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array('data_class' => 'AppBundle\Entity\Alarms','validation_groups'=>array('Default','form_user')));
    }

    /**
     * @return string
     */
    public function getName()
    {
        return 'alarms';
    }
}

回答1:


Problem solved.

The solution is to recreate the form field with 'choices'=>$selectedChoices in both PRE_SET_DATA and PRE_SUBMIT FormEvents.

Selected choices can be retrived from the event with $event->getData()

Have a look on the bundle I created, it implements this method :

Alsatian/FormBundle - ExtensibleSubscriber



来源:https://stackoverflow.com/questions/30178424/extending-entitytype-to-allow-extra-choices-set-with-ajax-calls

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