Symfony2: Как изменить сущность текущего пользователя, используя форму? - PullRequest
3 голосов
/ 22 марта 2012

Я пытаюсь добавить простую форму, чтобы мои пользователи могли редактировать свой профиль. Моя проблема:

Поскольку сущность, «связанная» с формой, совпадает с текущим пользовательским объектом ($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. Но мне бы очень хотелось понять мою ошибку здесь:)

Ответы [ 2 ]

9 голосов
/ 23 марта 2012

Я использовал то же решение, что и 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(),
    ));
}

Обратите внимание, что если вы используете то, что называется " virtual " в " Как обрабатывать загрузку файлов с помощью Doctrine " (в моем случае "picture_file" вам потребуется очистить вручную:

$em->refresh($user);
$user->picture_file = null; // here
1 голос
/ 22 марта 2012

Один из подходов состоит в том, чтобы всегда перенаправлять:

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

Конечно, вы теряете сообщения об ошибках и изменения.

Другой подход заключается в определении менеджера сущностей только для вашего UserProvider. $user больше не будет таким же, как $entity. Немного лишних накладных расходов, но это, безусловно, решает проблему и предотвращает подобные взаимодействия с другими формами, которые могут изменить всю или часть пользовательской сущности.

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

Наконец, вы можете спросить себя, действительно ли имело значение, что отображаемые данные были не совсем правильными в данном конкретном случае. Это действительно что-то беспокоит? Кто-нибудь заметит, кроме вас?

См. Как работать с несколькими менеджерами сущностей в Symfony Cookbook

Другая идея заключается в клонировании вашей пользовательской сущности в вашем провайдере. Это отделит его от менеджера сущностей.

Вы также можете использовать $entityManager->detach($user); для удаления пользователя из менеджера сущностей.

И почему пользователь токена в любом случае является сущностью? Рассмотрите возможность создания полностью независимого класса User с минимальным объемом информации, извлекаемой из базы данных вашим провайдером. Это то, что я делаю.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...