我用$user = $this->getUser();
获得了当前用户。在接下来的几行中,我将更改实体的一个字段(字段= forename
)。当我坚持使用此$user
实体时,Doctrine会尝试使用insert
。
非工作代码(试图插入新用户):
$user = $this->getUser();
$user->setForename('test');
$entityManager->persist($user);
$entityManager->flush();
正在工作(原则正在更新当前实体$user2
):
$user = $this->getUser();
$user2 = $entityManager->getRepository(User::class)->find($user->getId());
$user->setForename('test');
$entityManager->persist($user2);
$entityManager->flush();
Symfony 4.4,默认配置。
namespace App\Security;
use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
class UserProvider implements UserProviderInterface
{
private $entityManager;
public function __construct(EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
}
public function loadUserByUsername($username)
{
return $this->entityManager->getRepository(User::class)
->findOneBy([
'email' => $username,
]);
}
public function refreshUser(UserInterface $user)
{
if (!$user instanceof User) {
throw new UnsupportedUserException(sprintf('Invalid user class "%s".', get_class($user)));
}
$fetchedUser = $this->loadUserByUsername($user->getEmail());
if ($fetchedUser->getId() == $user->getId()) {
return $user;
}
return $user;
}
public function supportsClass($class)
{
return User::class === $class;
}
}
您不是在更改来自Doctrine的用户实体对象,而是在会话中每个请求开始时读取的用户实体对象。
由于该特定实例尚未从您的存储层读取],因此,Doctrine根本不会对其进行跟踪。因此,不会保留对该实体的任何更改。
(并且正如其他用户所提到的,如果您使用正确的实例,则无论如何,调用persist()
都是多余的。
问题来自您的UserProvider::refreshUser()
方法。
存储反序列化。public function refreshUser(UserInterface $user) { if (!$user instanceof User) { throw new UnsupportedUserException(sprintf('Invalid user class "%s".', get_class($user))); } $fetchedUser = $this->loadUserByUsername($user->getEmail()); if ($fetchedUser->getId() == $user->getId()) { return $user; } return $user; }
此方法接收
UserInterface
的实例,该实例已从session
从docs:
在每个请求结束时(除非您的防火墙是无状态的),您的User对象都被序列化到会话。在下一个请求的开始,它会反序列化,然后传递给您的用户提供程序以“刷新”它(例如,针对新用户的教义查询)。
然后,将两个“用户”对象(会话中的原始对象和刷新的用户对象)进行“比较”,以查看它们是否“相等”。
您正在做一个非常简单的比较(检查它们是否具有相同的ID,而不是检查对象是否具有任何其他更改)。
但是您的方法返回的用户是从会话中读取的原始用户,而不是来自Doctrine的用户。那就是您的脚本$fetchedUser
。
如果您只是返回那个那个
而不是$user
(return $fetchedUser;
),您的代码可能会按预期工作(尽管再次,您可以在不调用persist()
的情况下执行此操作,因为该对象已经被跟踪了)学说)。