代码之家  ›  专栏  ›  技术社区  ›  Bapt

Symfony 2.5:实体类型,防止在提交表单时提取所有记录

  •  6
  • Bapt  · 技术社区  · 7 年前

    我有一个包含一些经典字段的表单,以及用户实体的下拉列表(使用AngularJs处理,而不是使用经典表单视图)。 当我提交表单时,整个对象(以及通过下拉菜单选择的用户)将通过Ajax请求发送给我的控制器。

    class MyRestController{
    
        public function MyRestAction(...){
            ...
            $myObject = new MyObject();
    
            $myForm = $this->createForm(new MyFormType(), $myObject);
    
            $myForm->handleRequest($request);
    
            ...
        }
    }
    
    class MyFormType extends AbstractType{
    
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder
                ->add(...),
                ->add(...),
                ->add(...),
                ->add('user', 'entity', array(
                    'required' => true,
                    'class' => 'User',
                    'property' => 'id',
                ))
            ;
                ...
        }
    
    }
    

    然后我坚持整个对象并刷新它。它工作得很好。 但是这个过程非常缓慢。。。

    当调用getChoicesForValue函数(EntityChoiceList.php)时,问题来自HandlerRequest函数。在我的例子中,该进程对用户实体执行findAll()请求,从数据库中获取所有记录(数千条)。

    在此函数中,如果EntityChoiceList具有如下entityLoader,则会进行条件检查:

    if ($this->idAsValue && $this->entityLoader) {
        // do a findById()
    } else {
        // do a findAll()
    }
    

    (我确实简化了代码,这更复杂,但您可以在EntityChoiceList.php文件中找到整个代码)。 调试完我的应用程序后,我可以看到 $this->idAsValue true $this->entityLoader null ,解释了为什么它会执行findAll()。

    因此,我想知道是否有一个选项或任何东西可以使这个过程更快,并防止获取所有记录?

    谢谢

    编辑:

    我想我可以自己尝试替换HandlerRequest和水合物对象,但我希望有另一种方法保持经典过程。

    1 回复  |  直到 7 年前
        1
  •  2
  •   Bapt    7 年前

    最后,我找到了一个解决方案。 我将实体类型替换为简单的文本类型,然后创建了自己的DataTransformer类,以便将用户字符串id转换为真实的用户对象。 通过这种方式,用户对象被正确水合,而无需获取数千条记录,显著提高了加载速度。

    以下就是我所做的:

    我更改了:

    class MyFormType extends AbstractType{
    
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder
                ->add('user', 'entity', array(
                    'required' => true,
                    'class' => 'User',
                    'property' => 'id',
                ))
            ;
        }
    
    }
    

    收件人:

    class MyFormType extends AbstractType{
    
        private $manager;
    
        public function __construct(ObjectManager $manager)
        {
            $this->manager = $manager;
        }
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder
                ->add('user', 'text', array(
                    'required' => true,
                ))
            ;
           // we use a specific ModelTransformer (UserTransformer) created by ourself (see below)
           $builder->get('user')->addModelTransformer(new UserTransformer($this->manager));
        }
    
    }
    

    我创建了自己的UserTransformer类,如下所示:

    class UserTransformer implements DataTransformerInterface
    {
        private $manager;
    
        public function __construct(ObjectManager $manager)
        {
            $this->manager = $manager;
        }
    
        public function transform($user)
        {
            if (null === $user) {
                return '';
            }
    
            return $user->getId();
        }
    
        public function reverseTransform($id)
        {
            if (!$id) {
                return null;
            }
    
            $user= $this->manager
                ->getRepository(User::class)
                ->find($id)
            ;
    
            if (null === $user) {
                throw new TransformationFailedException(sprintf(
                    'There is no User with the id "%s" !',
                    $id
                ));
            }
            return $user;
        }
    }
    

    最后,我将EntityManager传递给如下表单:

    class MyRestController{
    
        public function MyRestAction(...){
            ...
            $myObject = new MyObject();
    
            $manager = $this->getDoctrine()->getManager();
            $myForm = $this->createForm(new MyFormType($manager), $myObject);
    
            $myForm->handleRequest($request);
    
            ...
        }
    }
    

    我在Symfony文档中找到了该解决方案: https://symfony.com/doc/2.7/form/data_transformers.html

    它工作得很好,现在我的应用程序速度快了10倍!