2014-10-07 99 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