简体   繁体   English

Symfony2:优化表单集合

[英]Symfony2: optimize collection of forms

In a controller of a Symfony2 application, I use collection of elements. 在Symfony2应用程序的控制器中,我使用元素集合。 The more elements there are, the more time it takes. 元素越多,花费的时间越多。 It sounds logical but it seems that there are repeated traitments: 听起来合乎逻辑,但似乎有重复的特征:

  • I create a form from MyCollectionType 我从MyCollectionType创建一个表单
  • in the buildForm method, I add the ElementType that has its own buildForm method. 在buildForm方法中,添加具有自己的buildForm方法的ElementType。

Then when the form is built by Symfony2 with the list of elements I pass, the buildForm method of the ElementType is called one time for each element 然后,当Symfony2使用传递的元素列表构建表单时,每个元素将一次调用ElementType的buildForm方法。

=> is this not possible that the first ELementType is built, then other are cloned? =>是否不可能先构建第一个ELementType,然后再克隆其他一个?

I don't see why there would be any different there between these subforms, the only difference will appear setting the data and not building the form. 我不明白为什么这些子表单之间不会有任何区别,唯一的区别是设置数据而不是构建表单。

Then I notice the same for the buildView method: there are a lot of repeated processing for each element, where only the data (possibly processing of listeners) may vary. 然后,我注意到buildView方法也是如此:每个元素都有很多重复处理,其中只有数据(可能是侦听器的处理)可能会有所不同。 For example, in my application, with a ElementType having 6 fields, and a collection of 700 elements, it takes up to 30s to render the form. 例如,在我的应用程序中,ElementType具有6个字段,并且有700个元素的集合,因此最多需要30秒才能呈现该表单。 Is it due to the way that forms are handled, or can be be optimized ? 是由于处理表单的方式还是可以对其进行优化?

I add the same problem for one of my application, what I did is that I reimplemented a basic form class prototype, the method names are almost the same that the Symfony2 ones and reimplemented in the most simple way, It looks like this: 我为我的一个应用程序添加了相同的问题,我所做的是重新实现了一个基本表单类原型,方法名称与Symfony2的几乎相同,并且以最简单的方式重新实现,如下所示:

class SimpleForm
{
    /**
     * @var ContainerInterface $container Main application DIC
     */
    protected $container;

    /**
     * @var array $options Options of the form
     */
    protected $options = array();

    /**
     * @var array $options Raw datas for the form.
     */
    protected $data = array();

    /**
     * @var array $options Data of the form against user input.
     */
    protected $boundData = array();

    /**
     * @var array $errors List of errors after form valisation
     */
    protected $errors = array();

    /**
     * @var array $options Tells if the datas were bound to the form.
     */
    protected $isBound = false;

    /**
     * @var array $options Tells if the form validation is ok
     */
    protected $isValid = false;

    /**
     * Main constructor.
     *
     * @param ContainerInterface $container The main DIC
     * @param array              $options   Options of the form
     */
    public function __construct(ContainerInterface $container, $options = array())
    {
        $this->container = $container;
        $this->options   = $options;
        $this->buildForm();
    }

    /**
     * Add widgets to the form.
     */
    public function buildForm()
    {
        $this->widgets['keywordType'] = self::$keywordTypes;
    }

    /**
     * @return array
     */
    public function getOptions()
    {
        return $this->options;
    }

    /**
     * @param array $options
     */
    public function setOptions($options)
    {
        $this->options = $options;
    }

    /**
     * @return string
     */
    public function getEnctype()
    {
        return isset($this->options['enctype']) ? $this->options['enctype'] : '';
    }

    /**
     * If the form is bound it return the bound datas, it returns the raws datas otherwise.
     *
     * @return array
     */
    public function getData()
    {
        return $this->isBound ? $this->boundData : $this->data;
    }

    /**
     * @throws \LogicException
     *
     * @return array
     */
    public function getErrors()
    {
        if ($this->isBound == false) {
            throw new \LogicException('The form must be bound before the errors can be retrieved');
        }

        return $this->errors;
    }

    /**
     * @throws \LogicException
     *
     * @return array
     */
    public function hasErrors()
    {
        if ($this->isBound == false) {
            throw new \LogicException('The form must be bound before the errors can be checked');
        }

        return !empty($this->errors);
    }

    /**
     * @throws \LogicException
     *
     * @return array
     */
    public function getBoundData()
    {
        if ($this->isBound == false) {
            throw new \LogicException('The form must be bound before getting the form final datas');
        }

        return $this->boundData;
    }

    /**
     * @param array $data
     *
     * @return SimpleForm
     */
    public function setData($data)
    {
        $this->data = $data;

        return $this;
    }

    /**
     * Bind the submitted values to the form.
     *
     * @param array $values The values to bind
     *
     * @return SimpleForm
     */
    public function bind($values)
    {
        $values = $this->clean($values);
        $this->boundData = Tools::arrayDeepMerge($this->data, $values);
        $this->isBound = true;
        $this->validate();

        return $this;
    }

    /**
     * Clean raw form values before the validation.
     *
     * @param array $values The raw values submitted by the user.
     *
     * @return array
     */
    protected function clean($values)
    {
        // ...

        return $values;
    }

    /**
     * Run the validation against the form.
     *
     * @return boolean
     */
    protected function validate()
    {
        $this->errors = array();

        // ...

        $this->isValid = empty($this->errors);

        return $this->isValid;
    }

    /**
     * Return the validation state of the form.
     *
     * @throws \LogicException
     *
     * @return boolean
     */
    public function isValid()
    {
        if ($this->isBound == false) {
            throw new \LogicException('The form must be bound before getting the validation status');
        }

        return $this->isValid;
    }

    /**
     * Returns the datas that will be necesary for the view.
     *
     * @return array
     */
    public function createView()
    {
        return array(
            'widgets'   => $this->widgets,
            'options'   => $this->options,
            'data'      => $this->boundData, // Don't forget to escape values against XSS
            'enctype'   => $this->getEnctype(),
            'errors'    => $this->errors,
            'name'      => $this->getName(),
        );
    }

    /**
     * @return string The name of the form
     */
    public function getName()
    {
        return 'search';
    }
}

In the Twig templates, I just iterate the data to create the form fields, repopulate values and to display the errors. 在Twig模板中,我仅迭代数据以创建表单字段,重新填充值并显示错误。 The form is the same but is generated in 100ms instead of 30 seconds... For all the other forms I kept on using the Symfony2 ones. 表单是相同的,但是生成时间是100毫秒而不是30秒...对于其他所有表单,我一直使用Symfony2表单。

The answer is simple: You should optimize yours programming skills instead of symfony forms. 答案很简单:您应该优化自己的编程技能,而不是symfony形式。 This is yours next question (of many) about the same issue. 这是您的(相同的)下一个问题。

You want to render over 4200 fields with fieldsets and/or divs around each input, so I suspect that 30 second it's the time in which it renders in the browser. 您想渲染每个输入周围带有字段集和/或div的4200多个字段,因此我怀疑这是30秒在浏览器中渲染的时间。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM