7

我想消除 FOSUserBundle 中对用户名的需求。我的用户将仅使用电子邮件地址登录,并且我已将真实姓名字段添加为用户实体的一部分。我意识到我需要重做这里描述的整个映射。 我想我做得对,但是当我尝试提交注册表时,我得到了错误:

“只有 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 文档对于什么必须是非常常见的请求非常少见。

4

3 回答 3

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

除此之外,您需要做的就是与语义相关的事情。就像让您的表单标签读取电子邮件而不是默认的用户名标签一样。您可以通过覆盖翻译文件来做到这一点。我将把它留给你(或其他人),因为它甚至可能对你来说没有必要。

使用这种策略,您的数据库中将有冗余数据,但它会为您省去很多重新映射的麻烦。

于 2012-09-15T15:29:39.840 回答
2

如果您使用的是原则 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;
}
于 2014-07-16T08:41:51.687 回答
1

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

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

  1. 将电子邮件留空
  2. 提供一个独特的电子邮件,该电子邮件尚未在系统中

以下是我按预期工作的解决方案(我并不声称它是最干净的解决方案,但希望它会向您展示如何完成类似任务的方法)

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)执行应用程序/控制台原则:迁移:差异和迁移,数据库表已按预期更改,将“DEFAULT NULL”添加到电子邮件和 email_canonical 字段

3)无论我尝试什么,email 都被设置为 NULL,但 email_canonical 不是,它正在返回“”。我尝试在我的 RegistrationFormHandler 中手动将其设置为 NULL,var_dump 确认在未输入电子邮件时它确实设置为 NULL。但是 FOSUser 会向数据库提交“”空字符串,这违反了我为电子邮件设置的 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/user-bundle/FOS/UserBundle/Resources/config/storage-validation/orm.xml
  2. 以上路径,config/validation/orm.xml

将这些文件中的“注册”组重命名为您自己的名称,例如“myRegistration”。

将新的validation_group 绑定到config.yml 中的fos_user。如果使用奏鸣曲用户,它是:

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

玩得开心。

于 2016-02-28T09:30:07.453 回答