$ this-> getUser () не работает / Doctrine пытается создать новую запись вместо обновления существующей - PullRequest
0 голосов
/ 27 января 2020

Я получаю текущего пользователя с $user = $this->getUser();. В следующих строках я изменяю одно поле сущности (field = forename). Когда я сохраняю эту $user сущность, Doctrine пытается insert.

нерабочий код (пытается вставить нового пользователя):

$user = $this->getUser();
$user->setForename('test');
$entityManager->persist($user);
$entityManager->flush();

Работает (doctrine обновляет текущий объект $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;
    }
}

1 Ответ

0 голосов
/ 27 января 2020

Вы не изменяете объект сущности пользователя, который приходит из 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 .

Из документов :

В конце каждого запроса (если ваш брандмауэр не имеет состояния) ваш объект User сериализуется в сеанс. В начале следующего запроса он десериализуется и затем передается вашему провайдеру пользователя для его «refre sh» (например, Doctrine запросов для пользователя fre sh).

Затем два Пользовательские объекты (оригинал из сеанса и обновленный пользовательский объект) сравниваются, чтобы определить, равны ли они.

Вы делаете очень простое сравнение (проверяя, имеют ли они одинаковые значения). Идентификатор, не проверяя, есть ли у объекта какие-либо другие изменения).

Но пользователь, которого возвращает ваш метод, является исходным, который был прочитан из сеанса, а не из Doctrine. Например, в вашем скрипте $fetchedUser.

Если вы просто вернули этот вместо $user (return $fetchedUser;), ваш код, вероятно, будет работать так, как вы ожидаете (хотя опять же, вы можете обойтись без вызова persist(), так как объект уже отслеживается Doctrine).

...