Symfony2表单组件中是否有任何已知的性能限制?

时间:2013-08-19 09:39:46

标签: performance forms symfony

我有这种架构结构:

  • 报告 - > id,预测
  • 预测 - > id,user_id,砖,产品
  • 砖块 - > id,region,plans
  • 计划 - > id,area,targets
  • 目标 - > id,product,valueA,valueB,comments
  • 评论 - > id,target,user,message,createdAt
  • 产品 - > id,forecast,targets,valueC
  • 地区 - > id,name,bricks
  • 区域 - > id,name,plans

我正在使用自定义FormType编辑预测

ForecastGridType:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->add('bricks', 'collection', array(
        'type' => 'forecast_grid_brick',
    ));

    $builder->add('products', 'collection', array(
        'type' => 'forecast_grid_product',
    ));
}

ForecastGridBrickType:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->add('plans', 'collection', array(
        'type' => 'forecast_grid_plan',
    ));
}

ForecastGridProductType:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('valueC', 'number', array(
            'autocomplete'  => false,
            'attr'          => array(
                'class' => 'grid-mini positive-integer'
            ),
        ));
}

ForecastGridPlanType:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->add('targets', 'collection', array(
        'type' => 'forecast_grid_target',
    ));
}

ForecastGridTargetType:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('valueA', 'number', array(
            'autocomplete'  => false,
            'attr'          => array(
                'class' => 'grid-mini positive-integer'
            )
        ))
        ->add('valueB', 'number', array(
            'autocomplete'  => false,
            'attr'          => array(
                'class' => 'grid-mini positive-integer'
            )
        ))
        ->add('comments', 'collection', array(
            'type'          => 'forecast_grid_comment',
            'allow_add'     => true,
            'allow_delete'  => false
        ));
}

ForecastGridCommentType:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('message', 'text', array(
            'autocomplete'  => false,
            'required'      => false,
            'attr'          => array(
                'class'       => 'grid-mini',
                'disabled'    => 'disabled',
            ),
        ));
}

当然所有表单类型都将data_class设置为相应的类,我只是没有包含其他方法来使其尽可能短。

创建和查看表单不是问题,symfony可以快速处理(低于0.5秒)。问题是当我发送表格时:

public function updateAction($id)
{
    $forecast = $this->getDoctrine()
        ->getRepository('AcmeForecastBundle:Forecast')
        ->find($id);

    $this->checkCredentials('canEditForecastGrid(object)', $forecast);

    if (!$forecast) {
        throw new NotFoundHttpException("The Acme\ForecastBundle\Entity\Forecast with id $id can't be found");
    }

    $form = $this->createForm('forecast_grid', $forecast);

    $form->handleRequest($this->getRequest()); // this makes my server hang

    echo 'This part is never reached'; exit;
    if ($form->isValid()) {
        // etc

所以......在POST中我有:

[forecast_grid] => array(
    [products] => array(
        // contains 6 products each with 1 field: valueC, example below
        [0] => array(
            [valueC] => "X"
        )
    ),
    [bricks] => array(
        // contains 10 bricks, each with 1 field: plans, example below
        [0] => array(
            [plans] => array(
                // contains various amount of plans
                // some bricks have 2 plans, some have 30
                // all together there are approx 120 plans in the form
                [0] => array(
                    [targets] => array(
                        // contains 6 targets, 1 for each product
                        // each with 3 fields: valueA, valueB, comments, example:
                        [0] => array(
                             [valueA] = "Y",
                             [valueB] = "Z",
                             [comments] => array(
                                 // contains  1 or 0 comments,
                                 // only one (new) comment is submitted
                                 // existing comments don't need to be 
                                 // submitted becouse of "allow_delete" => false
                                 // option, example below:
                                 [0] => array(
                                     [message] => "My comment"
                                 )
))))))))

所以..我们有120个计划x 6个目标x 2个字段=> 1440个字段,加上6个产品x 1个字段= 6个字段,加上(最多)120个计划x 6个目标x 1个评论= 720个字段。

这给了我们2166个字段。现在太多了?

我做了一些测试和Instatiationg 10000 stdClasses,分配了20个字段并在每个字段上运行preg_match ...瞬间完成。我知道框架的功能不止于此,但我认为这些字段不应该是PHP的问题。

很难调试,当你得到的唯一的东西是max_execution_time错误(没有symfony profiler:<)或你的apache2挂起。

  

致命错误:第943行的(...)/ vendor / symfony / symfony / src / Symfony / Component / Form / Form.php超出最多执行时间30秒

我的问题是:

  • 试图提交一个错误中的许多字段(从未构建symfony2表单组件来处理此类任务)?
  • 或symfony2 处理该表单没有问题,这意味着错误的根源位于其他地方(doctrine2水合作用?)..如果是这样的话......它可能在哪里以及如何测试如果是这样的话?

有些人建议我使用AJAX单独提交每个计划(有6个目标)。我可能会这样做,因为我没有多少时间,但我仍然有兴趣知道答案 - > symfony2表单组件是否有任何已知的性能限制?

1 个答案:

答案 0 :(得分:2)

在考虑并测试了许多方法后,我决定使用AJAX并一次保存一个项目。我已经设法将保存2000+字段的动作时间缩短到5s(这证明了symfony能够提供多少,很好!),我相信仍有改进性能的空间,到这样做我不得不:

  • 将最大输入,最大执行时间,最大上传大小等的php.ini和apache2.conf限制提升到极高值
  • 禁用许多OWASP规则(这会削弱服务器防范各种攻击)
  • 将应用程序逻辑和数据库架构更改为不太可读/可维护(但性能更佳)
  • 花费太多时间研究和测试这样简单的功能

我的结论是:可以做到,但不值得麻烦。最好用AJAX做。

并回答问题:是的,有一个限制。这取决于许多变量,但一般来说,如果你想一次保存1000多个字段,你应该会遇到麻烦。