我有一个包含一些经典字段的表单,以及一个用户实体的下拉列表(使用 AngularJs 处理,而不是使用经典表单 View )。 当我提交表单时,整个对象(以及通过下拉列表选择的用户)通过 Ajax 请求发送到我的 Controller 。
class MyRestController{
public function MyRestAction(...){
...
$myObject = new MyObject();
$myForm = $this->createForm(new MyFormType(), $myObject);
$myForm->handleRequest($request);
...
}
}
class MyFormType extends AbstractType{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add(...),
->add(...),
->add(...),
->add('user', 'entity', array(
'required' => true,
'class' => 'User',
'property' => 'id',
))
;
...
}
}
然后我持久化整个对象并刷新它。它工作得很好。 但是这个过程出奇地慢......
当调用 getChoicesForValue 函数 (EntityChoiceList.php) 时,问题来自 handleRequest 函数。在我的例子中,该过程对用户实体执行 findAll() 请求,从数据库中获取所有记录(数千条)。
在这个函数中,有一个条件检查 EntityChoiceList 是否有这样的 entityLoader:
if ($this->idAsValue && $this->entityLoader) {
// do a findById()
} else {
// do a findAll()
}
(我确实简化了代码,这更复杂,但您可以在 EntityChoiceList.php 文件中找到整个代码)。
在调试我的应用程序之后,我可以看到 $this->idAsValue
是 true
,而 $this->entityLoader
是 null
,解释它执行 findAll() 的原因。
所以我想知道是否有一个选项或任何东西可以使这个过程更快并防止获取所有记录?
谢谢。
编辑:
我想我可以尝试自己替换 handleRequest 和 hydrate 对象,但我希望有另一种方法来保持经典过程。
最佳答案
最后,我找到了解决办法。 我用一个简单的文本类型替换了我的实体类型,然后创建了我自己的 DataTransformer 类,以便将用户字符串 id 转换为真正的用户对象。 通过这种方式,无需获取数千条记录,用户对象就得到了正确的水化,显着提高了加载速度。
这正是我所做的:
我改变了:
class MyFormType extends AbstractType{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('user', 'entity', array(
'required' => true,
'class' => 'User',
'property' => 'id',
))
;
}
}
到:
class MyFormType extends AbstractType{
private $manager;
public function __construct(ObjectManager $manager)
{
$this->manager = $manager;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('user', 'text', array(
'required' => true,
))
;
// we use a specific ModelTransformer (UserTransformer) created by ourself (see below)
$builder->get('user')->addModelTransformer(new UserTransformer($this->manager));
}
}
然后我像这样创建了自己的 UserTransformer 类:
class UserTransformer implements DataTransformerInterface
{
private $manager;
public function __construct(ObjectManager $manager)
{
$this->manager = $manager;
}
public function transform($user)
{
if (null === $user) {
return '';
}
return $user->getId();
}
public function reverseTransform($id)
{
if (!$id) {
return null;
}
$user= $this->manager
->getRepository(User::class)
->find($id)
;
if (null === $user) {
throw new TransformationFailedException(sprintf(
'There is no User with the id "%s" !',
$id
));
}
return $user;
}
}
最后我将 EntityManager 传递给这样的表单:
class MyRestController{
public function MyRestAction(...){
...
$myObject = new MyObject();
$manager = $this->getDoctrine()->getManager();
$myForm = $this->createForm(new MyFormType($manager), $myObject);
$myForm->handleRequest($request);
...
}
}
我在此处的 Symfony 文档中找到了该解决方案: https://symfony.com/doc/2.7/form/data_transformers.html
它运行完美,现在我的应用程序快了 10 倍!
关于php - Symfony 2.5 : Entity Type, 在提交表单时阻止获取所有记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48933487/