Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/excel/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Symfony 扩展EntityType以允许使用AJAX调用设置额外的选项_Symfony_Jquery Select2 - Fatal编程技术网

Symfony 扩展EntityType以允许使用AJAX调用设置额外的选项

Symfony 扩展EntityType以允许使用AJAX调用设置额外的选项,symfony,jquery-select2,Symfony,Jquery Select2,我尝试创建一个Symfony自定义类型扩展核心“实体””类型 但是我想将它与select2version4.0.0一起使用(ajax现在与“select”html元素一起使用,而不像以前那样与隐藏的“input”一起使用) 此类型应创建一个空选择,而不是扩展“实体”类型的完整实体列表 这通过设置选项(请参阅配置选项)来实现: 通过编辑附加到表单的对象,它应使用对象的当前数据填充select。我解决了这个问题,但只针对视图使用以下buildView方法 Select2识别html“sele

我尝试创建一个Symfony自定义类型扩展核心“实体””类型

但是我想将它与select2version4.0.0一起使用(ajax现在与“select”html元素一起使用,而不像以前那样与隐藏的“input”一起使用)

  • 此类型应创建一个空选择,而不是扩展“实体”类型的完整实体列表
这通过设置选项(请参阅配置选项)来实现:

  • 通过编辑附加到表单的对象,它应使用对象的当前数据填充select。我解决了这个问题,但只针对视图使用以下buildView方法
Select2识别html“select”的内容,并使用ajax进行工作。 但是当表单发回时,Symfony无法识别所选的选项(因为不允许这样做?)

我尝试了几种使用EventListeners或订阅服务器的方法,但找不到有效的配置

使用Select2 3.5.*我解决了表单事件和重写隐藏的formtype的问题,但是在这里扩展entitytype要困难得多

我如何构建我的类型,让它管理我的实体的反向转换

自定义类型:

<?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';
    }
}
问题已解决

解决方案是在PRE_SET_数据和PRE_SUBMIT FormEvents中使用'choices'=>$selectedChoices重新创建表单字段

可以使用$event->getData()从事件中检索所选选项

看看我创建的bundle,它实现了以下方法:


以下是我基于捆绑包的方法,只针对一个表单类型中的实体类型。 用法是

(不要忘记对生成表单和配置选项的父调用)

还有班级本身

abstract class ExtensibleEntityType extends AbstractType
{
    /**
     * @var EntityManagerInterface
     */
    private EntityManagerInterface $entityManager;

    /**
     * ExtensibleEntityType constructor.
     * @param EntityManagerInterface $entityManager
     */
    public function __construct(EntityManagerInterface $entityManager)
    {
        $this->entityManager = $entityManager;
    }

    public function getParent()
    {
        return EntityType::class;
    }

    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        parent::buildForm($builder, $options);
        $builder->addEventListener(FormEvents::PRE_SET_DATA, [$this, 'preSetData']);
        $builder->addEventListener(FormEvents::PRE_SUBMIT, [$this, 'preSubmit'], 50);
    }

    /**
     * @param FormEvent $event
     */
    public function preSetData(FormEvent $event)
    {
        $form = $event->getForm();
        $parent = $event->getForm()->getParent();
        $options = $form->getConfig()->getOptions();
        if (!$options['pre_set_called']) {
            $options['pre_set_called'] = true;
            $options['choices'] = $this->getChoices($options, $event->getData());
            $parent->add($form->getName(), get_class($this), $options);
        }
    }

    /**
     * @param FormEvent $event
     */
    public function preSubmit(FormEvent $event)
    {
        $form = $event->getForm();
        $parent = $event->getForm()->getParent();
        $options = $form->getConfig()->getOptions();
        if (!$options['pre_submit_called']) {
            $options['pre_submit_called'] = true;
            $options['choices'] = $this->getChoices($options, $event->getData());
            $parent->add($form->getName(), get_class($this), $options);
            $newForm = $parent->get($form->getName());
            $newForm->submit($event->getData());
        }
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        parent::configureOptions($resolver);
        $resolver->setDefaults([
            'multiple' => true,
            'expanded' => true,
            'choices' => [],
            'required' => false,
            'pre_set_called' => false,
            'pre_submit_called' => false,
            'validation_groups' => false,
        ]);
    }

    /**
     * @param array $options
     * @param $data
     * @return mixed
     */
    public function getChoices(array $options, $data)
    {
        if ($data instanceof PersistentCollection) {
            return $data->toArray();
        }
        return $this->entityManager->getRepository($options['class'])->findBy(['id' => $data]);
    }
}

下面是我的工作代码,它为与标记(TagType)相关的用户(EntityType)添加了填充AJAX调用(jQuery Select2)选项的功能

<?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';
    }
}
<?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';
    }
}
MyType extends ExtensibleEntityType
abstract class ExtensibleEntityType extends AbstractType
{
    /**
     * @var EntityManagerInterface
     */
    private EntityManagerInterface $entityManager;

    /**
     * ExtensibleEntityType constructor.
     * @param EntityManagerInterface $entityManager
     */
    public function __construct(EntityManagerInterface $entityManager)
    {
        $this->entityManager = $entityManager;
    }

    public function getParent()
    {
        return EntityType::class;
    }

    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        parent::buildForm($builder, $options);
        $builder->addEventListener(FormEvents::PRE_SET_DATA, [$this, 'preSetData']);
        $builder->addEventListener(FormEvents::PRE_SUBMIT, [$this, 'preSubmit'], 50);
    }

    /**
     * @param FormEvent $event
     */
    public function preSetData(FormEvent $event)
    {
        $form = $event->getForm();
        $parent = $event->getForm()->getParent();
        $options = $form->getConfig()->getOptions();
        if (!$options['pre_set_called']) {
            $options['pre_set_called'] = true;
            $options['choices'] = $this->getChoices($options, $event->getData());
            $parent->add($form->getName(), get_class($this), $options);
        }
    }

    /**
     * @param FormEvent $event
     */
    public function preSubmit(FormEvent $event)
    {
        $form = $event->getForm();
        $parent = $event->getForm()->getParent();
        $options = $form->getConfig()->getOptions();
        if (!$options['pre_submit_called']) {
            $options['pre_submit_called'] = true;
            $options['choices'] = $this->getChoices($options, $event->getData());
            $parent->add($form->getName(), get_class($this), $options);
            $newForm = $parent->get($form->getName());
            $newForm->submit($event->getData());
        }
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        parent::configureOptions($resolver);
        $resolver->setDefaults([
            'multiple' => true,
            'expanded' => true,
            'choices' => [],
            'required' => false,
            'pre_set_called' => false,
            'pre_submit_called' => false,
            'validation_groups' => false,
        ]);
    }

    /**
     * @param array $options
     * @param $data
     * @return mixed
     */
    public function getChoices(array $options, $data)
    {
        if ($data instanceof PersistentCollection) {
            return $data->toArray();
        }
        return $this->entityManager->getRepository($options['class'])->findBy(['id' => $data]);
    }
}
class TagType extends AbstractType
{
    //...
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $modifyForm = function ($form, $users) {
            $form->add('users', EntityType::class, [
                'class' => User::class,
                'multiple' => true,
                'expanded' => false,
                'choices' => $users,
            ]);
        };
        $builder->addEventListener(
            FormEvents::PRE_SET_DATA,
            function (FormEvent $event) use ($modifyForm) {
                $modifyForm($event->getForm(), $event->getData()->getUsers());
            }
        );
        $userRepo = $this->userRepo; // constructor injection
        $builder->addEventListener(
            FormEvents::PRE_SUBMIT,
            function (FormEvent $event) use ($modifyForm, $userRepo) {
                $userIds = $event->getData()['users'] ?? null;
                $users = $userIds ? $userRepo->createQueryBuilder('user')
                    ->where('user.id IN (:userIds)')->setParameter('userIds', $userIds)
                    ->getQuery()->getResult() : [];
                $modifyForm($event->getForm(), $users);
            }
        );
    }
    //...
}