Symfony2:优化表单集合

时间:2015-09-17 12:01:59

标签: forms performance symfony collections

在Symfony2应用程序的控制器中,我使用了元素集合。元素越多,花费的时间就越多。这听起来合乎逻辑,但似乎有重复的特征:

  • 我从MyCollectionType
  • 创建一个表单
  • 在buildForm方法中,我添加了具有自己的buildForm方法的ElementType。

然后当Symfony2使用我传递的元素列表构建表单时,为每个元素调用ElementType的buildForm方法

=>这是不可能建立第一个ELementType,然后克隆其他?

我不明白为什么这些子表单之间会有任何不同之处,唯一的区别就是设置数据而不是构建表单。

然后我注意到buildView方法的相同内容:每个元素都有很多重复处理,其中只有数据(可能是侦听器的处理)可能会有所不同。 例如,在我的应用程序中,ElementType有6个字段,700个元素的集合,渲染表单最多需要30秒。 是由于处理表单的方式还是可以优化的?

2 个答案:

答案 0 :(得分:0)

我为我的一个应用程序添加了同样的问题,我所做的是我重新实现了一个基本的表单类原型,方法名称几乎与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';
    }
}

在Twig模板中,我只是迭代数据以创建表单字段,重新填充值并显示错误。表单是相同的,但生成时间为100毫秒而不是30秒...对于我使用Symfony2的所有其他表单。

答案 1 :(得分:-2)

答案很简单:你应该优化你的编程技巧,而不是symfony表格。这是关于同一问题的下一个问题(很多)。

你想要在每个输入周围渲染超过4200个字段集和/或div的字段,所以我怀疑它是在浏览器中呈现的时间是30秒。