操作方法:优化 Symfony 的表单性能?

2022-08-30 20:09:36

我有一个表单,这是我的ajax请求的瓶颈。

    $order = $this->getDoctrine()
        ->getRepository('AcmeMyBundle:Order')
        ->find($id);
    $order = $order ? $order : new Order();

    $form = $this->createForm(new OrderType(), $order);

    $formView = $form->createView();

    return $this->render(
        'AcmeMyBundle:Ajax:order_edit.html.twig',
        array(
            'form' => $formView,
        )
    );

为了更干净的代码,我删除了语句。stopwatch

我的订单类型有下一个字段:

    $builder
        ->add('status') // enum (string)
        ->add('paid_status') // enum (string)
        ->add('purchases_price') // int
        ->add('discount_price') // int
        ->add('delivery_price') // int
        ->add('delivery_real_price', null, array('required' => false)) // int
        ->add('buyer_name') // string
        ->add('buyer_phone') // string
        ->add('buyer_email') // string
        ->add('buyer_address') // string
        ->add('comment') // string
        ->add('manager_comment') // string
        ->add('delivery_type') // enum (string)
        ->add('delivery_track_id') // string
        ->add('payment_method') // enum (string)
        ->add('payment_id') // string
        ->add('reward') // int
        ->add('reward_status') // enum (string)
        ->add('container') // string
        ->add('partner') // Entity: User
        ->add('website', 'website') // Entity: Website
        ->add('products', 'collection', array( // Entity: Purchase
            'type' => 'purchase',
            'allow_add' => true,
            'allow_delete' => true,
            'by_reference' => false,
            'property_path' => 'purchases',
            'error_bubbling' => false,
        ));

购买类型

    $builder
        ->add('amount')
        ->add('price')
        ->add('code', 'variant', array(
            'property_path' => 'variantEntity',
            'data_class' => '\Acme\MyBundle\Entity\Simpla\Variant'
        ))
    ;

此外,购买类型有一个监听器,在这里并不重要。它在下面的 Symfony 分析器中表示为 , 。您可以看到大约需要200ms。variant_retrievepurchase_form_creating

在这里,我放置了分析器的结果:SymfonyProfilerBlackFire ProfilerBlackFire Profiler

如您所见:需要1011ms,需要2876ms,在树枝中的形式渲染也非常慢:4335ms。正如黑火分析器所说,所有交易都在 和 .$this->createForm(...)$form->createView();ObjectHydrator::gatherRowData()UnitOfWork::createEntity()

方法调用 2223 次,因为存在一些与实体映射并具有表单类型的字段。但是,从上面的代码中可以看出,没有变体的类型。我的是具有.为了不搞砸所有内容,您可以在文档中看到类似Type类代码。createEntity()VariantEntityentityVariantTypetextmodelTransformer

我发现 XDebug 已经调用了 's 与表单类型.但是在那之后,从某个地方再次调用了for,在这种情况下,它具有表单类型。这怎么可能?我试图在我的每个表单类型中和每个表单类型上定义空数组,但它没有改变任何东西。我需要做些什么来防止我的表单被加载?buildViewVariantTypePurchasebuildViewtextbuildViewVariantTypeentitychoicespreferred_choicesEntityChoiceList


答案 1

所描述的行为看起来像是猜测者的工作。我觉得有必要显示一些额外的代码(侦听器,,,)。VariantTypeWebsiteTypePartnerType

让我们假设某个类与某个类有关联,并且对于这个类具有代码而没有显式指定类型(正如我所看到的,有很多地方没有指定类型)。然后是游戏。variantVariantFormType->add('variant')DoctrineOrmTypeGuesser

https://github.com/symfony/symfony/blob/2.7/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php#L46

此代码将类型 (!) 分配给此子级。调用和 DB 的所有变体都已水合。entityEntityRepository::findAll()

至于另一种表单优化方法:

  • 尝试在所有可能的情况下指定类型,以防止类型猜测;
  • 将 SELECT 与 JOIN 结合使用可获取订单,因为会向 DB 发送新的子请求,以便为每个表单映射关系设置基础数据;
  • 在提交时保留集合元素的键,因为删除单个元素而不保留键将触发不必要的更新。

答案 2

我在实体类型上也有同样的问题,我需要列出城市,就像泥潭然后4000,我所做的基本上是将选择注入到表单中。在控制器中,您要求数据库中的 Variants,在存储库调用中,将它们作为数组冻结,然后仅选择 id 和名称或标题,然后作为选项值传递到表单中。这样,数据库部分将更快。


推荐