I’m using Symfony 2.8 and Doctrine and I have security.yml configured to point to the User class which implements UserInterface. My ORM schema is in YAML.
The problem:
- In database the user has also specified “email” field, Symfony for LOGGED USER is not filling up that field and also “password” field is empty.
When I do $this->get('doctrine.orm.entity_manager')->clear(User::class);
then the entity manager is fetching correctly the entity.
But when the entity is COMING FROM SESSION, then it’s incorrect.
The problem is also that when I try to fetch a fresh entity from database using find() on a repository then, the incorrect element from session is fetched when I will not use the $em->clear(User::class)
How to tell Symfony/Doctrine to construct my entity in that way that it will have all fields filled up, so it will become persistable?
<?php namespace XXXAppBundleModelEntity; use XXXAppBundleModelEntityServerLogging; use DoctrineORMMapping as ORM; use SymfonyComponentSecurityCoreUserUserInterface; /** * User */ class User implements UserInterface { /** * @var integer $id */ protected $id; /** * @var string $username */ protected $username; /** * @var string $email */ protected $email; /** * @var string $password */ protected $password; /** * @var array $roles */ protected $roles = array(); /** * @var DoctrineCommonCollectionsCollection $logEvents */ protected $logEvents; /** * @return int */ public function getId() { return $this->id; } /** * {@inheritdoc} */ public function getUsername() { return $this->username; } /** * @param string $username * @return $this */ public function setUsername($username) { $this->username = $username; return $this; } /** * @return string */ public function getEmail() { return $this->email; } /** * @param string $email * @return $this */ public function setEmail($email) { $this->email = $email; return $this; } /** * {@inheritdoc} */ public function getPassword() { return $this->password; } /** * @param string $password * @return $this */ public function setPassword($password) { $this->password = $password; return $this; } /** * Returns the roles or permissions granted to the user for security. */ public function getRoles() { $roles = $this->roles; // guarantees that a user always has at least one role for security if (empty($roles)) { $roles[] = 'ROLE_USER'; } return array_unique($roles); } public function setRoles(array $roles) { $this->roles = $roles; } /** * Returns the salt that was originally used to encode the password. */ public function getSalt() { // See "Do you need to use a Salt?" at http://symfony.com/doc/current/cookbook/security/entity_provider.html // we're using bcrypt in security.yml to encode the password, so // the salt value is built-in and you don't have to generate one return; } /** * Removes sensitive data from the user. */ public function eraseCredentials() { $this->password = null; $this->email = null; } /** * Appends an entry to administration log * * @param XXXAppBundleModelEntityServerLogging $logEvent * @return $this */ public function appendLog(ServerLogging $logEvent) { if (!$this->logEvents->contains($logEvent)) { $this->logEvents->add($logEvent); } return $this; } /** * Remove a log entry from the history * * @param XXXAppBundleModelEntityServerLogging $logEvent * @return $this */ public function clearLogEntry(ServerLogging $logEvent) { $this->logEvents->removeElement($logEvent); return $this; } }
And ORM configuration:
XXXAppBundleModelEntityUser: type: entity table: users repositoryClass: XXXAppBundleModelRepositoryUserRepository id: id: type: integer scale: 0 length: null unique: false nullable: false precision: 0 id: true generator: strategy: IDENTITY fields: username: type: string scale: 0 length: null unique: true nullable: false precision: 0 email: type: string scale: 0 length: null unique: true nullable: false precision: 0 password: type: string scale: 0 length: null unique: false nullable: false precision: 0 roles: type: json_array scale: 0 length: null unique: false nullable: false precision: 0 oneToMany: logEvents: targetEntity: XXXAppBundleModelEntityServerLogging cascade: - remove - persist fetch: LAZY mappedBy: author inversedBy: null orphanRemoval: false orderBy: null lifecycleCallbacks: { }
Advertisement
Answer
You implemented the UserInterface::eraseCredentials() method in a way that it unsets the email and the password:
public function eraseCredentials() { $this->password = null; $this->email = null; }
Symfony will invoke this method before serializing the object to save it in the session.
The UserInterface::eraseCredentials() is meant to remove sensitive data from the user object so it does not end up in for example the session files, but there is no real need to remove the email, like you are doing. A better example would be if you are storing the plaintext version of the user’s password somewhere on this object, this is something you would never want to end up in session files.