FOSUserBundle Overrides Mapping to Remove Username Required

I want to remove the username need in the FOSUserBundle. My users will only log in using their email address and I will add real name fields as part of the user object. I realized that I needed to redo the entire mapping as described here. I think I did it right, but when I try to submit a registration form, I get an error message:

"Only field names displayed with Doctrine can be checked for uniqueness."

The strange thing is that I did not try to assert a unique constraint for anything in the user entity.

Here is my complete user entity file:

<?php // src/MyApp/UserBundle/Entity/User.php namespace MyApp\UserBundle\Entity; use FOS\UserBundle\Model\User as BaseUser; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Validator\Constraints as Assert; /** * @ORM\Entity * @ORM\Table(name="depbook_user") */ class User extends BaseUser { /** * @ORM\Id * @ORM\Column(type="integer") * @ORM\GeneratedValue(strategy="AUTO") */ protected $id; /** * @ORM\Column(type="string", length=255) * * @Assert\NotBlank(message="Please enter your first name.", groups={"Registration", "Profile"}) * @Assert\MaxLength(limit="255", message="The name is too long.", groups={"Registration", "Profile"}) */ protected $firstName; /** * @ORM\Column(type="string", length=255) * * @Assert\NotBlank(message="Please enter your last name.", groups={"Registration", "Profile"}) * @Assert\MaxLength(limit="255", message="The name is too long.", groups={"Registration", "Profile"}) */ protected $lastName; /** * @ORM\Column(type="string", length=255) * * @Assert\NotBlank(message="Please enter your email address.", groups={"Registration", "Profile"}) * @Assert\MaxLength(limit="255", message="The name is too long.", groups={"Registration", "Profile"}) * @Assert\Email(groups={"Registration"}) */ protected $email; /** * @ORM\Column(type="string", length=255, name="email_canonical", unique=true) */ protected $emailCanonical; /** * @ORM\Column(type="boolean") */ protected $enabled; /** * @ORM\Column(type="string") */ protected $salt; /** * @ORM\Column(type="string") */ protected $password; /** * @ORM\Column(type="datetime", nullable=true, name="last_login") */ protected $lastLogin; /** * @ORM\Column(type="boolean") */ protected $locked; /** * @ORM\Column(type="boolean") */ protected $expired; /** * @ORM\Column(type="datetime", nullable=true, name="expires_at") */ protected $expiresAt; /** * @ORM\Column(type="string", nullable=true, name="confirmation_token") */ protected $confirmationToken; /** * @ORM\Column(type="datetime", nullable=true, name="password_requested_at") */ protected $passwordRequestedAt; /** * @ORM\Column(type="array") */ protected $roles; /** * @ORM\Column(type="boolean", name="credentials_expired") */ protected $credentialsExpired; /** * @ORM\Column(type="datetime", nullable=true, name="credentials_expired_at") */ protected $credentialsExpiredAt; public function __construct() { parent::__construct(); // your own logic } /** * @return string */ public function getFirstName() { return $this->firstName; } /** * @return string */ public function getLastName() { return $this->lastName; } /** * Sets the first name. * * @param string $firstname * * @return User */ public function setFirstName($firstname) { $this->firstName = $firstname; return $this; } /** * Sets the last name. * * @param string $lastname * * @return User */ public function setLastName($lastname) { $this->lastName = $lastname; return $this; } } 

I have seen various suggestions about this, but none of the suggestions seem to work for me. FOSUserBundle docs are very scarce as to what should be a very common request.

+7
source share
3 answers

I think the easiest way to do this is to leave the package as it is and rather set up your custom class to have a username equal to the email address.

Do this by overriding the setEmail() method to set the $username property to the $email parameter and setEmailCanonical() to set the $usernameCanonical to $emailCanonical .

 public function setEmail($email){ $this->email = $email; $this->username = $email; } public function setEmailCanonical($emailCanonical){ $this->emailCanonical = $emailCanonical; $this->usernameCanonical = $emailCanonical; } 

All you need to do, except for this, is semantics. Just like your form label reads E-mail instead of the default user label. You can do this by overriding translation files. I will leave it to you (or someone else), as you might not even need it.

With this strategy, you will have redundant data in your database, but it will save you a lot of headache overstrain.

+15
source

If you are using doctrine 2, you can use life cycle events to incorporate your logic into the callback.

http://docs.doctrine-project.org/en/2.0.x/reference/events.html

 /** * @ORM\PreUpdate() * @ORM\PrePersist() */ public function setUsernameToEmail() { $this->username = $this->email; $this->usernameCanonical = $this->emailCanonical; } 
+2
source

When I did not want users to enter emails (thus, adding emails is optional to the FOSUserBundle), I use Symfony 2.7 + FOSUser + SonataUser + SonataAdmin.

At the same time, I needed the entered emails to be unique in the system. Thus, users have 2 options when registering:

  • Leave your email blank
  • Provide a unique email that is not already in the system.

Below, my solution works as expected (I do not claim that it is the cleanest, but I hope it shows you how to perform a similar task)

1) Changes in Entity / User.php

 namespace AppBundle\Entity; use Sonata\UserBundle\Entity\BaseUser as BaseUser; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity * @ORM\Table(name="fos_user") * * * @ORM\AttributeOverrides({ * @ORM\AttributeOverride(name="email", * column=@ORM \Column( * type = "string", * name = "email", * nullable = true, * unique = true * ) * ), * @ORM\AttributeOverride(name="emailCanonical", * column=@ORM \Column( * type = "string", * name = "email_canonical", * nullable = true, * unique = true * ) * ) * }) * \*/ class User extends BaseUser { 

2) Completed doctrine app / console: migrations: diff and migrate, the database tables have been changed, as expected, adding "DEFAULT NULL" to the email and email_canonical fields

3) No matter what I tried, the email was set to NULL, but email_canonical was not, it returned. "I tried to manually set it to NULL in my RegisterFormHandler, var_dump there confirmed that it was really set to NULL when electronic no mail was entered, but I would send an β€œempty string” to the FOSUser database that violated the UNIQUE restriction that I set for emails, so the solution was to override the method in Entity / User.php (as discussed in previous answers to this question)

 // src/AppBundle/Entity/User.php // ... public function setEmailCanonical($emailCanonical) { // when email is empty, force canonical to NULL // for some reason by default "" empty string is inserted $this->emailCanonical = $this->getEmail(); } 

4) Change the validation for FOSUserBundle (or SonataUserBundle) in my case so that it does not require the installation of email. (I just deleted .. from validation.xml as not the ones that were applied to the email anymore)

Copy these 2 files to the config / validation / directory (for SonataUser + FOSUser this is: Application / Sonata / UserBundle / Resources)

  • seller / friendsofsymfony / custom package / FOS / UserBundle / Resources / configuration / storage validation /orm.xml
  • above path, config / validation / orm.xml

Rename the Registration group to these files in your name, for example, myRegistration.

Bind the new validation_group to fos_user in config.yml. If you are using Sonata User, this is:

 sonata_user: profile: register: form: ... validation_groups: - myRegistration - Default 

Enjoy.

+1
source

All Articles