У меня есть форма, которая является узким местом моего запроса 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 мс.
Здесь я поставил результат профилировщиков:
Как вы можете видеть: $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
.
Этот код присваивает этому типу entity
(!). EntityRepository::findAll()
и все варианты из БД гидратируются.
Что касается других способов оптимизации формы:
У меня также была такая же проблема с типом сущности, мне нужно было перечислять города, там было как болото, а затем 4000, что я в основном делал, чтобы вводить варианты в форму. В контроллере вы запрашиваете Варианты из базы данных, в вызове репозитория, убираете их как массив и вы выбираете только идентификатор, имя или заголовок, а затем вы переходите в форму в качестве значения параметра. При этом часть базы данных будет намного быстрее.