Symfony2:如何使用表单修改当前用户的实体


Symfony2: How to modify the current user's entity using a form?

我正在尝试添加一个简单的表单来允许我的用户编辑他们的个人资料。我的问题是:

由于"链接"到表单的实体与当前用户对象相同($user === $entity,见下文(,如果表单验证失败,则视图将使用修改后的用户对象(即使用无效表单的值(呈现。

这是我的(经典(控制器:

public function profileAction()
{
    $em = $this->getDoctrine()->getEntityManager();
    $user = $this->get('security.context')->getToken()->getUser();
    $entity = $em->getRepository('AcmeSecurityBundle:User')->find($user->id);
    // $user === $entity => true
    $form = $this->createForm(new ProfileType(), $entity);
    $request = $this->getRequest();
    if ($request->getMethod() === 'POST')
    {
        $form->bindRequest($request);
        if ($form->isValid()) {
            $em->persist($entity);
            $em->flush();
            return $this->redirect($this->generateUrl('profile'));
        }
    }
    return $this->render('AcmeSecurityBundle:User:profile.html.twig', array(
        'entity'      => $entity,
        'form'   => $form->createView(),
    ));
}

所以我想知道如何有两个不同的对象$user$entity。我使用了clone(),它适用于视图渲染部分($user对象未被修改(,但它在数据库中创建了一个新记录,而不是更新旧记录。

PS:我知道我应该使用FOSUserBundle。但我真的很想在这里理解我的错误:)

我使用了与 FOSUserBundle 相同的解决方案,当表单验证失败时,它会在我的实体上调用$em->refresh()

public function profileAction()
{
    $em = $this->getDoctrine()->getEntityManager();
    $user = $this->get('security.context')->getToken()->getUser();
    $entity = $em->getRepository('AcmeSecurityBundle:User')->find($user->id);
    if (!$entity) {
        throw $this->createNotFoundException('Unable to find User entity.');
    }
    $form = $this->createForm(new ProfileType(), $entity);
    $request = $this->getRequest();
    if ($request->getMethod() === 'POST')
    {
        $form->bindRequest($request);
        if ($form->isValid()) {
            $em->persist($entity);
            $em->flush();
            return $this->redirect($this->generateUrl('profile'));
        }
        $em->refresh($user); // Add this line
    }
    return $this->render('AcmeSecurityBundle:User:profile.html.twig', array(
        'entity'      => $entity,
        'form'   => $form->createView(),
    ));
}

请注意,如果您使用的是"如何使用原则处理文件上传"中所谓的">虚拟"字段(在我的例子中为"picture_file"(,则需要手动清除它:

$em->refresh($user);
$user->picture_file = null; // here

一种方法是始终重定向:

    if ($form->isValid()) {
        $em->persist($entity);
        $em->flush();
    }
    return $this->redirect($this->generateUrl('profile'));

当然,您会丢失错误消息和更改。

另一种方法是仅为您的用户提供程序定义实体管理器。 $user将不再与$entity相同.有点额外的开销,但它肯定会使问题消失,并且会阻止与其他可能修改全部或部分用户实体的表单进行类似的交互。

以类似的方式,您可以通过仅为配置文件窗体创建实体管理器来减少开销。 使用此方法,仅在编辑配置文件时会产生开销。

最后,您可以问自己,在这种特殊情况下,显示数据不太正确是否真的重要。 真的会打扰什么吗? 除了你,还有人会注意到吗?

在Symfony说明书中查看如何使用多个实体管理器

另一个想法是在用户提供程序中克隆用户实体。 这将使其与实体经理分离。

您还可以使用 $entityManager->detach($user); 从实体管理器中删除用户。

为什么令牌用户无论如何都是一个实体?考虑创建一个完全独立的 User 类,其中用户提供程序从数据库中提取的信息最少。这就是我所做的。