2014-10-07 101 views
3

当使用Symfony构建表单时,表单的构建非常缓慢并且内存高峰。内存管理Symfony形式和Doctrine

表单使用一些子表单构建,并使用一些one-to-many关系。当表单的数据变大(更多的实体在许多方面)表单较慢,内存使用量变得越来越大这似乎okey虽然时间和内存使用量似乎没有。

例如,在许多方面具有大约71个实体时,内存使用量大约为116 MB,需要14秒来加载。

我已经推断完成(从75到4)查询,虽然内存尖峰仍然发生形式设立

$form = $this->createForm(new TapsAndAppliancesType(), $taps);

任何提示和技巧,以加快这一时刻的数向上?

+0

不使用type'entity'只是'选择'用'id => label'写出[DataTransformers](http://symfony.com/doc/current/cookbook/form/data_transformers.html)。然后,您只需使用普通的值并且只在最后选择某些内容时将其转换为所需的实体 – SBH 2014-10-07 11:01:05

回答

4

我假设您在表单中使用类型entity。它们非常沉重,因为首先所有实体都是作为对象提取的,然后简化为id => label风格。

所以,你可以写自己的entityChoice类型,它与id => label -array作品(所以没有什么取为在弗里斯特地方的对象),并添加一个DataTransformer这种类型:

use Symfony\Component\Form\AbstractType; 
use Symfony\Component\Form\FormBuilderInterface; 
use Symfony\Component\OptionsResolver\OptionsResolverInterface; 

use MyNamespace\EntityToIdTransformer; 

class EntityChoiceType extends AbstractType 
{ 
    public function buildForm(FormBuilderInterface $builder, array $options) 
    { 
     $builder->addModelTransformer(new EntityToIdTransformer($options['repository'])); 
    } 

    public function setDefaultOptions(OptionsResolverInterface $resolver) 
    { 
     $resolver->setDefaults(array(
      'empty_value' => false, 
      'empty_data' => null, 
     )); 

     $resolver->setRequired(array(
      'repository' 
     )); 
    } 

    public function getParent() 
    { 
     return 'choice'; 
    } 

    public function getName() 
    { 
     return 'entityChoice'; 
    } 
} 

而作为DataTransformer:

use Doctrine\ORM\EntityRepository; 
use Symfony\Component\Form\DataTransformerInterface; 
use Symfony\Component\Form\Exception\TransformationFailedException; 

class EntityToIdTransformer implements DataTransformerInterface 
{ 
    private $entityRepository; 

    public function __construct(EntityRepository $entityRepository) 
    { 
     $this->entityRepository = $entityRepository; 
    } 

    /** 
    * @param object|array $entity 
    * @return int|int[] 
    * 
    * @throws TransformationFailedException 
    */ 
    public function transform($entity) 
    { 
     if ($entity === null) { 
      return null; 
     } 
     elseif (is_array($entity) || $entity instanceof \Doctrine\ORM\PersistentCollection) { 
      $ids = array(); 
      foreach ($entity as $subEntity) { 
       $ids[] = $subEntity->getId(); 
      } 

      return $ids; 
     } 
     elseif (is_object($entity)) { 
      return $entity->getId(); 
     } 

     throw new TransformationFailedException((is_object($entity)? get_class($entity) : '').'('.gettype($entity).') is not a valid class for EntityToIdTransformer'); 
    } 

    /** 
    * @param int|array $id 
    * @return object|object[] 
    * 
    * @throws TransformationFailedException 
    */ 
    public function reverseTransform($id) 
    { 
     if ($id === null) { 
      return null; 
     } 
     elseif (is_numeric($id)) { 
      $entity = $this->entityRepository->findOneBy(array('id' => $id)); 

      if ($entity === null) { 
       throw new TransformationFailedException('A '.$this->entityRepository->getClassName().' with id #'.$id.' does not exist!'); 
      } 

      return $entity; 
     } 
     elseif (is_array($id)) { 

      if (empty($id)) { 
       return array(); 
      } 

      $entities = $this->entityRepository->findBy(array('id' => $id)); // its array('id' => array(...)), resulting in many entities!! 

      if (count($id) != count($entities)) { 
       throw new TransformationFailedException('Some '.$this->entityRepository->getClassName().' with ids #'.implode(', ', $id).' do not exist!'); 
      } 

      return $entities; 
     } 

     throw new TransformationFailedException(gettype($id).' is not a valid type for EntityToIdTransformer'); 
    } 
} 

最后注册FormType作为新类型的service.yml

services: 
    myNamespace.form.type.entityChoice: 
     class: MyNamespace\EntityChoiceType 
     tags: 
      - { name: form.type, alias: entityChoice } 

可以再用$repository使用它在您形式

$formBuilder->add('appliance', 'entityChoice', array(
    'label'  => 'My Label', 
    'repository' => $repository, 
    'choices'  => $repository->getLabelsById(), 
    'multiple' => false, 
    'required' => false, 
    'empty_value' => '(none)', 
)) 

为您所需的存储库,并'choices'为阵列的一个实例与id => label

+0

我允许自己在此[Gist]中重用和尝试改进此答案(https://gist.github的.com/lologhi/bb900f061f8205841f6a) – LaurentG 2015-10-26 01:45:12