Практическое руководство. Оптимизация производительности форм Symfony?

У меня есть форма, которая является узким местом моего запроса 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 .

Мой OrderType имеет следующие поля:

  $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 ниже как variant_retrieve , purchase_form_creating . Вы можете видеть, что это занимает около 200 мс.

Здесь я поставил результат профилировщиков: SymfonyProfilerПрофилировщик BlackFireПрофилировщик BlackFire

Как вы можете видеть: $this->createForm(...) принимает 1011ms, $form->createView(); занимает 2876 мс, а рендеринг формы в ветке также очень медленный: 4335мс. Как указано профилировщиком blackfire, все сделки в ObjectHydrator::gatherRowData() и UnitOfWork::createEntity() .

Метод createEntity() называется 2223 раза, потому что есть некоторое поле, которое отображается с объектом Variant и имеет тип типа Entity . Но, как видно из кода выше, для варианта нет типов объектов. My VariantType – это простой тип расширенной text формы, который имеет modelTransformer . Чтобы не испортить все, вы можете увидеть код для аналогичного класса типа в документах .

Я нашел с XDebug, что buildView для VariantType был вызван в buildView виде text формы. Но после этого откуда-то buildView VariantType buildView для VariantType и в этом случае он имеет тип формы entity . Как это возможно? Я попытался определить пустой массив в choices и preferred_choices для каждого типа моей формы, но ничего не изменил. Что мне нужно сделать, чтобы предотвратить EntityChoiceList для моей формы?

Описанное поведение выглядит как работа угадывателя. У меня такое ощущение, что нужно показать какой-то дополнительный код (слушатели, VariantType , WebsiteType , PartnerType ).

Предположим, что у какого-то класса есть variant ассоциации Variant и FormType для этого класса есть код ->add('variant') без явно заданного типа (поскольку я вижу, что существует много мест, где тип не указан). Затем в игру входит DoctrineOrmTypeGuesser .

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

Этот код присваивает этому типу entity (!). EntityRepository::findAll() и все варианты из БД гидратируются.

Что касается других способов оптимизации формы:

  • Попробуйте указать тип во всех возможных случаях, чтобы предотвратить угадывание типа;
  • Используйте SELECT с JOINs, чтобы получить заказ, когда новые суб-запросы к БД отправляются для установки базовых данных для каждого отношения карт формы;
  • Сохранять ключи для элементов коллекции при представлении как удаление одного элемента без сохранения ключей приведет к ненужным обновлениям.

У меня также была такая же проблема с типом сущности, мне нужно было перечислять города, там было как болото, а затем 4000, что я в основном делал, чтобы вводить варианты в форму. В контроллере вы запрашиваете Варианты из базы данных, в вызове репозитория, убираете их как массив и вы выбираете только идентификатор, имя или заголовок, а затем вы переходите в форму в качестве значения параметра. При этом часть базы данных будет намного быстрее.