FOSUserBundle覆盖映射以删除对用户名的需求

时间:2012-07-23 21:16:42

标签: symfony doctrine fosuserbundle

我想在FOSUserBundle中删除对用户名的需求。我的用户将仅使用电子邮件地址登录,并且我已添加实名字段作为用户实体的一部分。 我意识到我需要重做整个映射,如here.所述 我想我已经正确完成了,但当我尝试提交注册表时,我收到错误:

“只有Doctrine映射的字段名称才能验证其唯一性。”

奇怪的是,我没有尝试对用户实体中的任何内容断言唯一约束。

这是我的完整用户实体文件:

 <?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;


       }
    }

我已经看到了关于此的各种建议,但这些建议似乎都不适合我。关于什么是非常常见的请求,FOSUserBundle文档非常稀疏。

3 个答案:

答案 0 :(得分:15)

我认为最简单的方法是将捆绑包保留原样,而是将用户类设置为具有等于电子邮件地址的用户名。

通过覆盖setEmail()方法同时将$username属性设置为$email参数,setEmailCanonical()也将$usernameCanonical设置为$emailCanonical来执行此操作public function setEmail($email){ $this->email = $email; $this->username = $email; } public function setEmailCanonical($emailCanonical){ $this->emailCanonical = $emailCanonical; $this->usernameCanonical = $emailCanonical; }

{{1}}

除此之外,你所要做的只是与语义有关。就像让表单标签读取电子邮件而不是默认的用户名标签一样。您可以通过覆盖翻译文件来完成此操作。我会把这个留给你(或其他人)因为你甚至可能都不需要。

使用此策略,您将在数据库中拥有冗余数据,但它将为您节省大量重新映射的麻烦。

答案 1 :(得分:2)

如果您使用的是doctrine 2,则可以使用生命周期事件将您的逻辑置于回调中。

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 :(得分:1)

如果我不想要求用户输入电子邮件(从而使电子邮件在FOSUserBundle中可选),我使用Symfony 2.7 + FOSUser + SonataUser + SonataAdmin。

与此同时,我需要输入的电子邮件在系统中是唯一的。因此,用户在注册时有两个选项:

  1. 将电子邮件留空
  2. 提供尚未在系统中的唯一电子邮件
  3. 以下是我的解决方案按预期工作(我不认为它是最干净的,但希望它会告诉你如何完成类似的任务)

    1)对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)已执行的app / console doctrine:migrations:diff&amp;迁移,数据库表按预期更改添加&#34; DEFAULT NULL&#34;发送电子邮件和email_canonical字段

    3)无论我尝试了什么,电子邮件都设置为NULL,但email_canonical不是,它正在返回&#34;&#34;。我尝试在我的RegistrationFormHandler中手动将其设置为NULL,var_dump确认当电子邮件未输入时确实设置为NULL。但是对于数据库,FOSUser会提交&#34;&#34;空字符串,违反了我为电子邮件设置的UNIQUE约束,因此解决方法是覆盖Entity / User.php中的方法(正如此问题的先前答案中所讨论的那样)

    // 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)在我的情况下更改FOSUserBundle(或SonataUserBundle)的验证,因此它不需要设置电子邮件。 (我只是从validation.xml中删除了..而不再是那些应用于电子邮件的那些)

    将这2个文件复制到config / validation /目录中(对于SonataUser + FOSUser,它是:Application / Sonata / UserBundle / Resources)

    1. 供应商/ friendsofsymfony /用户束/ FOS / UserBundle /资源/配置/存储验证/ orm.xml中
    2. 上面的路径,config / validation / orm.xml
    3. 重命名&#34;注册&#34;将这些文件分组为您自己的名称,例如&#34; myRegistration&#34;。

      将新的validation_group绑定到config.yml中的fos_user。如果使用Sonata用户,则为:

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

      玩得开心。