У меня есть форма для сущности Пользователь с полем электронной почты:
->add('email', EmailType::class, [
'constraints' => [
new NotBlank(),
new Email([
'checkMX' => true,
])
],
'required' => true
])
когда я редактирую электронную почту на что-то вроде [email protected]
и отправить форму, она показывает мне ошибку «Это значение не является действительным адресом электронной почты». Это нормально, но после этого Symfony заполняет неправильный адрес электронной почты в токене, и когда я иду на любую другую страницу или просто перезагружаю страницу, я получаю это:
ВНИМАНИЕ Безопасность Имя пользователя не может быть найдено в выбранном пользователе.
поставщик.
Я думаю, что вопрос: почему Symfony заполнить неправильный Email, который не прошел проверку в токене и как я мог предотвратить это?
контроллер:
public function meSettingsAction(Request $request)
{
$user = $this->getUser();
$userUnSubscribed = $this->getDoctrine()->getRepository('AppBundle:UserUnsubs')->findOneBy(
[
'email' => $user->getEmail(),
]
);
$form = $this->createForm(UserSettingsType::class, $user);
$form->get('subscribed')->setData(!(bool)$userUnSubscribed);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
/**
* @var $user User
*/
$user = $form->getData();
/** @var UploadedFile $avatar */
$avatar = $request->files->get('user_settings')['photo'];
$em = $this->getDoctrine()->getManager();
if ($avatar) {
$avatar_content = file_get_contents($avatar->getRealPath());
$avatarName = uniqid().'.jpg';
$oldAvatar = $user->getPhoto();
$user
->setState(User::PHOTO_STATE_UNCHECKED)
->setPhoto($avatarName);
$gearmanClient = $this->get('gearman.client');
$gearmanClient->doBackgroundDependsOnEnv(
'avatar_content_upload',
serialize(['content' => $avatar_content, 'avatarName' => $avatarName, 'oldAvatar' => $oldAvatar])
);
}
$subscribed = $form->get('subscribed')->getData();
if ((bool)$userUnSubscribed && $subscribed) {
$em->remove($userUnSubscribed);
} elseif (!(bool)$userUnSubscribed && !$subscribed) {
$userUnSubscribed = new UserUnsubs();
$userUnSubscribed->setEmail($form->get('email')->getData())->setTs(time());
$em->persist($userUnSubscribed);
}
$user->setLastTs(time());
$em = $this->getDoctrine()->getManager();
$em->persist($user);
$em->flush();
$this->get('user.manager')->refresh($user);
return $this->redirectToRoute('me');
}
return $this->render(
':user:settings.html.twig',
[
'form' => $form->createView(),
]
);
}
UPD:
это работает нормально, если я изменяю в OAuthProvider:
/**
* @param \Symfony\Component\Security\Core\User\UserInterface $user
*
* @return \Symfony\Component\Security\Core\User\UserInterface
*/
public function refreshUser(UserInterface $user)
{
return $this->loadUserByUsername($user->getName());
}
чтобы:
/**
* @param \Symfony\Component\Security\Core\User\UserInterface $user
*
* @return \Symfony\Component\Security\Core\User\UserInterface
*/
public function refreshUser(UserInterface $user)
{
return $this->userManager($user->getId());
}
но это похоже на грязный хак.
Благодарю.
Это сложный вопрос, благодаря хранилищу стало легче изолировать проблему. Вы связываете пользовательский объект из токена аутентификации с createForm()
метод. После
$form->handleRequest($request)
Вызовите адрес электронной почты, чтобы токен пользователя обновился.
Сначала я решил решить эту проблему путем реализации EquatableInterface.html в User
объект, но это не сработало, так как сравниваемый объект уже имел неправильный адрес электронной почты.
Также может быть полезно реализовать интерфейс EquatableInterface, который определяет метод проверки, равен ли пользователь текущему пользователю. Этот интерфейс требует метода isEqualTo ().)
Тогда я думал о принудительной перезагрузке пользователя из базы данных и обнулении токена безопасности, но мне пришло в голову, что может быть достаточно просто обновить текущий объект пользователя из базы данных в случае сбоя формы:
$this->get('doctrine')->getManager()->refresh($this->getUser());`
В вашем контроллере это решит вашу проблему.
/**
* @Route("/edit_me", name="edit")
* @Security("has_role('ROLE_USER')")
*/
public function editMyselfAction(Request $request) {
$form = $this->createForm(User::class, $this->getUser());
if ($request->isMethod(Request::METHOD_POST)) {
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$user = $form->getData();
$em = $this->getDoctrine()->getManager();
$em->persist($user);
$em->flush();
} else {
$this->get('doctrine')->getManager()->refresh($this->getUser());
}
}
return $this->render(':security:edit.html.twig',['form' => $form->createView()]);
}
Альтернативное решение
выпуск в репозитории Symfony привели к некоторому ценному вкладу о Избегание сущностей в формах а также
Развязка вашего пользователя безопасности что обеспечивает более сложный подход к решению вашей проблемы.
Ваш токен пользователя, похоже, обновляется формой, даже если ограничение электронной почты останавливает сброс.
Можете ли вы проверить, прошла ли ваша форма функцию isValid?
Вы можете попытаться избежать этого с помощью прослушивателя событий или валидатора.
С событием SUBMIT вы сможете проверить целостность электронной почты, а затем добавить FormError, чтобы избежать refreshUser.