如何使用Symfony 4表单更新唯一的实体字段



我正在更新我的用户实体。它是在其唯一电子邮件上定义的唯一实体。 不幸的是,在更新我的实体时,由于此电子邮件唯一验证规则,我触发了验证错误。

我一直在尝试将$user传递给表单,以确保它将其视为用户更新,但没有运气。

这是一个Ajax形式。

知道如何解决这个问题吗?

用户实体

class User implements UserInterface, Serializable
{
/**
* @ORMId
* @ORMColumn(type="integer")
* @ORMGeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string $email
* @ORMColumn(type="string", length=254, nullable=false)
* @AssertEmail()
* @AssertNotBlank
* @AcmeAssertUniqueEmail
*/
private $email;
/**
* @ORMColumn(type="string", length=25, nullable=true)
*/
private $username;
// and so on

我的控制器:

/**
* @Route("/profile", name="profile")
*/
public function profile()
{
$user = $this->getUser();
$formAccount = $this->updateUserAccountForm( $user );
return $this->render('platform/user/profile.html.twig',
array(
'user' => $user,
'form_account' => $formAccount->createView()
)
);
}
/**
* @Route("/profile/updateAccount", name="updateUserAccount", methods={"POST"})
*/
public function updateUserAccount(Request $request, UserPasswordEncoderInterface $passwordEncode)
{
if (!$request->isXmlHttpRequest()) {
return new JsonResponse(array('message' => 'Forbidden'), 400);
}
// Build The Form
$user = $this->getUser();
$form = $this->updateUserAccountForm($user);
$form->handleRequest($request);
if ($form->isValid()) {
$user_form = $form->getData();
// Check if the password is = to DB
$current_password = $passwordEncoder->encodePassword($user, $user_form->getPlainPassword());
if($user->getPassword() != $current_password){
return new JsonResponse(['error' => 'wrong password!']);
}
// Encode the password (We could also do this via Doctrine listener)
$password = $passwordEncoder->encodePassword($user_form, $user_form->getPlainPassword());
$user_form->setPassword($password);
$entityManager = $this->getDoctrine()->getManager();
$entityManager->merge($user_form);
$entityManager->flush();
$em = $this->getDoctrine()->getManager();
$em->persist($user_form);
//            $em->flush();
return new JsonResponse(array('message' => 'Success!'), 200);
}
$errors = [];
foreach ($form->getErrors(true, true) as $formError) {
$errors[] = $formError->getMessage();
}
$errors['userid'] = $user->getId();
$errors['user'] = $user->getUsername();
return new JsonResponse($errors);
}
/**
* Creates a form to update user account.
*
* @param User $entity The entity
*
* @return SymfonyComponentFormFormInterface The form
*/
private function updateUserAccountForm(User $user)
{
$form = $this->createForm( AccountType::class, $user,
array(
'action' => $this->generateUrl('updateUserAccount'),
'method' => 'POST',
));
return $form;
}

和帐户类型.php

class AccountType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('username', TextType::class)
->add('email', EmailType::class, array(
'required' => true,
'constraints' => array(
new NotBlank(),
)))
->add('password', PasswordType::class, array(
'required' => true
))
->add('plainPassword', RepeatedType::class, array(
'type' => PasswordType::class,
'invalid_message' => 'The new password fields must match.',
'required' => false,
'first_options'  => array('label' => 'New Password'),
'second_options' => array('label' => 'Confirm New Password')
))
->add('save', SubmitType::class, array('label' => 'Save ->'));
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
// enable/disable CSRF protection for this form
'csrf_protection' => true,
// the name of the hidden HTML field that stores the token
'csrf_field_name' => '_token',
// an arbitrary string used to generate the value of the token
// using a different string for each form improves its security
'csrf_token_id'   => 'reset_item',
'data_class' => User::class
));
}
}

ajax 调用确实返回序列化的窗体。表单已在配置文件功能中创建并且运行良好。我在调用"$form->isValid(("时收到表单错误消息

我一直在尝试一切以表单类型传递$user,以使Symfony理解它基于预先存在的用户。 但没有运气。

任何帮助都非常感谢!

编辑:这是我的自定义UniqueEmail Validator类:

class UniqueEmailValidator extends ConstraintValidator
{
/**
* @var EntityManager
*/
protected $em;
public function __construct(EntityManagerInterface $entityManager)
{
$this->em = $entityManager;
}
public function validate($value, Constraint $constraint)
{
// Do we have a pre registered user in DB from email form landing page?
$userRepository = $this->em->getRepository(User::class);
$existingUser = $userRepository->findOneByEmail($value);
if ($existingUser && $existingUser->getIsActive()) {
$this->context->buildViolation($constraint->message)
->setParameter('{{ string }}', $value)
->addViolation();
}
}
}

据我所知,当您提交表单时,您在电子邮件字段上设置的UniqueEmail约束会尝试使用您定义的规则验证提交的值。 假设您只想更新用户名,表单将与数据库中存储的电子邮件字段的当前值一起发送。当然,它会触发验证错误。

通常,最好对用户表中的电子邮件列设置唯一约束。因此,即使您不修改电子邮件字段,您也可以正确更新您的用户实体。此外,您将无法在数据库中创建新用户,该用户具有与现有用户相同的电子邮件。我想这就是你想要的。

教义可以帮助你实现这一目标。

在实体级别使用@UniqueConstraint:

<?php
/**
* @Entity
* @Table(name="user_table",uniqueConstraints= {@UniqueConstraint(name="search_idx", columns={"email"})})
*/
class User implements UserInterface, Serializable
{
}

在字段级别使用具有唯一属性的@Column(我更喜欢这个,但取决于情况(:

/**
* @var string $email
* @ORMColumn(type="string", length=32, unique=true, nullable=false)
* @AssertEmail()
* @AssertNotBlank
*/
private $email;

看看并尝试看看它是否解决了您的问题。

最新更新