如何处理包含 500 多个项目的 Symfony 表单集合

Posted

技术标签:

【中文标题】如何处理包含 500 多个项目的 Symfony 表单集合【英文标题】:How to handle Symfony form collection with 500+ items 【发布时间】:2013-09-14 03:57:43 【问题描述】:

我有需要处理 500 多个实体实例的表单集合。在我将超时时间增加到 60 秒并增加 max_input_vars 表单工作后,但令人讨厌的是它有多慢。渲染表单很慢,但提交这么大的表单很麻烦。

我正在考虑创建纯 html 表单,但还有一些其他缺点作为验证很糟糕。 那么,有没有什么合适的方法可以通过 symfony 表单来处理这么多数据呢?

控制器:

public function ratesCardAction() 
    $bannerList = $this->data;

    $em = $this->getDoctrine()->getManager();
    $form = $this->createForm(new AdvertiserRatesType($bannerList));
    if ('POST' == $this->getRequest()->getMethod()) 
        $form->handleRequest($this->getRequest());
        $advertiserCampaign = $form->getData();
        if ($form->isValid()) 
            foreach ($advertiserCampaign['campaignsAdZones'] as $campaignAdZone) 
               $em->persist($campaignAdZone);
            
            $em->flush();
        
    

    return array(
        'form'   => $form->createView()
    );




class AdvertiserRatesType extends AbstractType 

    public function buildForm(FormBuilderInterface $builder, array $options)
    
        $builder ->add('campaignsAdZones', 'collection', array(
            'type'   => new AdvertiserRatePerCountryType(),
            'data'   => $this->rates,
            'empty_data'  => null,
            'options'  => array(
                'attr' => array('class' => 'campaignAdZoneItem')
            )
        ))
        ;
    


...

嵌入表单如下:

public function buildForm(FormBuilderInterface $builder, array $options)

    $builder->add('class', 'entity', array(
                'class' => 'AcmeCmsBundle:PublisherTypes',
                'property' => 'class',
                'read_only' => true,
                'disabled' => true
            )
        )
        ->add('country', 'entity', array(
                'class' => 'AcmeCmsBundle:Countries',
                'property' => 'name',
            )
        )
        ->add('text1')
        ->add('text2')
    ;


public function setDefaultOptions(OptionsResolverInterface $resolver)

    $resolver->setDefaults(array(
        'data_class' => 'Acme\CmsBundle\Entity\Rates'
    ));

【问题讨论】:

您在哪个特定的地方拥有 500 多个实体(500 个国家/地区,500 种类型,或收藏 500 项)?对数据库的调用有多少? 我有 500 件收藏品。所以,我的 POST 请求数据有 500 个 Acme\CmsBundle\Entity\Rates 对象实例: array(0=>Acme\CmsBundle\Entity\Rates, 1=>Acme\CmsBundle\Entity\Rates, .... 500=> Acme\CmsBundle\Entity\Rates) 您应该尝试使用分页之类的方式将表单拆分成小块。 您是否尝试过使用分析器来确定原因?你看过 Doctrine 生成的 sql 语句吗?因此,真的不值得放弃 Symfony Form / Doctrine。想到的一个原因是您的代码尝试更新每条记录,无论它是否被用户修改。另外,如果可能的话,对数组而不是对象使用水合,只获取所需的列而不是全部。 嗨@TadasSasnauskas,我也有类似的问题。您能否详细说明如何仅获取所需的列而不是全部? 【参考方案1】:

我可以建议使用 Doctrine 查询缓存吗?通常情况下,缓存是一种常见的解决方案。

https://coderwall.com/p/ry1y0a http://docs.doctrine-project.org/en/latest/reference/caching.html

还可以查看其他 Symfony 缓存,并毫不犹豫地测试尽可能多的 php 缓存解决方案(请参阅最后一个链接)。

【讨论】:

我 Symfony 的 Form Componetn 是这里的瓶颈。 500+ 条记录对 Doctrine 来说没有问题。【参考方案2】:

确实使用整个实体来收集超过 500 个项目是一种矫枉过正;)

首先:使用纯数组代替实体,在setDefaultOptions方法中设置'data_class' => null

第二:您不想在一个页面表单上创建超过 500 个新项目,是吗? ;) 如果出于某种原因确实需要它并且必须这样做......目前$advertiserCampaign = $form->getData(); 在您的代码中将返回超过 500 个对象 - 重。取而代之的是,$advertiserCampaign = $form->getData(); 应该返回 500 个数据数组,然后在 foreach 中您应该创建新对象并将数据绑定到它(例如使用 datatransfomer)。 验证仍然可以毫无问题地处理 - 只需为表单类中的每个字段设置验证器即可。

第三:我希望$this->rates 不是另一个对象集合——对吧?如果是 - 使用原始数组而不是重物。

第四:一页上有 500 个对象/表单?真的吗?可能会以某种方式重构吗?也许分页和例如每页20个表格? 如果你真的,真的需要在一个请求中保存一个表单中的 500 个对象,那么我建议使用一些队列处理程序,如 RabbitMQ 或 Gearman 将所有 500 个对象保存在数据库中。

我希望能有所帮助。

【讨论】:

以上是关于如何处理包含 500 多个项目的 Symfony 表单集合的主要内容,如果未能解决你的问题,请参考以下文章

如何处理尚未记录的现有项目? [关闭]

Symfony:如何处理表单中的日期字段

使用 Symfony 时如何处理连接表中的附加列?

XCode 如何处理带有多个目标的#import 标头语句?

如何处理 ListView 中的多个倒数计时器?

将复杂项目从 Ant 迁移到 Maven - 如何处理不寻常的文件夹结构?