symfony2:如何向用户名添加验证规则?

symfony2:如何向用户名添加验证规则?,symfony,validation,fosuserbundle,Symfony,Validation,Fosuserbundle,由于我正在扩展BaseUser,因此在我的用户实体中没有属性$name。如何向其添加验证?我是否可以将属性$username添加到此实体?这会干扰或覆盖某些功能或验证,或是本机提供给用户类的功能或验证吗 我问了这个问题:。 但是由于我使用了大量的注释验证,这对我来说是行不通的 后续问题-我在fosUSerBundleXML文件中看到了这一点,用于验证用户本机是否有一个用于使用已获取用户名的检查器。我没有这个功能,如果我尝试添加一个与现有用户同名的用户,我的会直接显示一条SQL错误消息。这是不是因

由于我正在扩展
BaseUser
,因此在我的用户实体中没有属性
$name
。如何向其添加验证?我是否可以将属性
$username
添加到此实体?这会干扰或覆盖某些功能或验证,或是本机提供给用户类的功能或验证吗

我问了这个问题:。
但是由于我使用了大量的注释验证,这对我来说是行不通的

后续问题-我在
fosUSerBundle
XML文件中看到了这一点,用于验证用户本机是否有一个用于使用已获取用户名的检查器。我没有这个功能,如果我尝试添加一个与现有用户同名的用户,我的会直接显示一条SQL错误消息。这是不是因为我使用的注释一起覆盖了XML验证文件

<?php
namespace BizTV\UserBundle\Entity;

use BizTV\UserBundle\Validator\Constraints as BizTVAssert;
use Symfony\Component\Security\Core\User\AdvancedUserInterface;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;


use FOS\UserBundle\Model\User as BaseUser;

use Doctrine\ORM\Mapping as ORM;

use BizTV\BackendBundle\Entity\company as company;


class User extends BaseUser implements AdvancedUserInterface
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;  

//TODO: Add regex on $name for a-z, A-Z, 0-9 and _ (underscore) 
//TODO: Add constraint on $name    * @BizTVAssert\NameExists    (and finish coding this constraint)

    /**
    * @var object BizTV\BackendBundle\Entity\company
    *  
    * @ORM\ManyToOne(targetEntity="BizTV\BackendBundle\Entity\company")
    * @ORM\JoinColumn(name="company", referencedColumnName="id", nullable=false)
    */
    protected $company; 

    /**
    * @var object BizTV\UserBundle\Entity\UserGroup
    * @ORM\ManyToOne(targetEntity="BizTV\UserBundle\Entity\UserGroup")
    * @ORM\JoinColumn(name="userGroup", referencedColumnName="id", nullable=true)
    */
    protected $userGroup;   
我还尝试通过以下方式将此验证组设置为“注册组”(即“免费”为您提供唯一的用户和电子邮件验证):

use Symfony\Component\OptionsResolver\OptionsResolverInterface;

public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
    'validation_groups' => array('registration'),
));
}

还是什么都没发生。保存时直接返回SQL错误。

这不是问题的答案,但到目前为止对我来说是一个解决方案。我将验证器添加到我的表单(UserType)


我提前道歉。我不完全确定您是想验证
$name
属性还是
$username
属性,但我希望这能为您指明正确的方向

要添加带有正则表达式验证的
$name
属性,它应该如下所示。未经测试,但我将从这里开始:

<?php

use Doctrine\ORM\Mapping as ORM;
use FOS\UserBundle\Model\User as BaseUser;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @ORM\Entity
 * @ORM\Table(name="users")
 */
class User extends BaseUser
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @ORM\Column(type="string")
     * @Assert\NotBlank(groups={"Registration","Profile"})
     * @Assert\Regex(pattern="/^[a-zA-Z0-9_]+$/", groups={"Registration","Profile"})
     */
    protected $name;

    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

    public function getName()
    {
        return $this->name;
    }
}
如果您使用的是表单生成器或捆绑包未提供的表单类型,则其外观可能如下所示:

// setting values from a form
$userManager = $this->container->get('fos_user.user_manager');
$user = $userManager->createUser();

$form = $this->container->get('form.factory')
    ->createBuilder('form', $user, array('validation_groups' => 'Registration'))
    ->add('username', 'text')
    ->add('email', 'email')
    ->add('name', 'text')
    ->add('plainPassword', 'repeated', array(
        'type' => 'password'
    ))
    ->getForm();

if ($request->isMethod('POST')) {
    $form->handleRequest($request);
    if ($form->isValid()) {
        $userManager->updateUser($user);

        // redirect response
    }
}

return $this->container->get('templating')->renderResponse($templateName, array(
    'form' => $form->createView()
));

我希望这有帮助。如果我能提供更多细节,请告诉我。我想在这里发布一些代码,但我的实现有点不同。

实现回调验证约束,该约束在Symfony cookbook中有记录:

例如:

use Symfony\Component\Security\Core\User\AdvancedUserInterface;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
use BizTV\BackendBundle\Entity\company;

/**
 * @Assert\Callback(methods={"validateName"})
 */
class User extends BaseUser implements AdvancedUserInterface
{
/**
 * @ORM\Id
 * @ORM\Column(type="integer")
 * @ORM\GeneratedValue(strategy="AUTO")
 */
protected $id;  

/**
* @var object BizTV\BackendBundle\Entity\company
*  
* @ORM\ManyToOne(targetEntity="BizTV\BackendBundle\Entity\company")
* @ORM\JoinColumn(name="company", referencedColumnName="id", nullable=false)
*/
protected $company; 

/**
* @var object BizTV\UserBundle\Entity\UserGroup
* @ORM\ManyToOne(targetEntity="BizTV\UserBundle\Entity\UserGroup")
* @ORM\JoinColumn(name="userGroup", referencedColumnName="id", nullable=true)
*/
protected $userGroup;   

/**
 * @param ExecutionContextInterface $context
 */
public function validateName(ExecutionContextInterface $context)
{
    // do some validation

    // or add violation
        $context->addViolationAt(
            'name',
            'Name "%name% is not valid',
            array('%name%' => $this->getName()),
            null
        );
}

要更改对
$username
的验证,我建议您执行中描述的步骤,这是最简单的方法。在单个项目中同时使用XML和注释没有什么错。实际上建议不要使用注释,因为它将映射元数据保留在实体/类之外,这是()的要点

另一种方法是不扩展
FOS\UserBundle\Model\User
,而是实现
FOS\UserBundle\Model\UserInterface
。下面介绍了您必须对
UserProvider
UserManager
进行一个小的调整,以使其正常工作。 接下来,您必须自己完成所有映射,您可以自由使用任何您想要的注释

至于验证
$username
的唯一性,您应该注意两件事:

  • 您没有检查属性是否唯一,而是检查实体是否唯一(基于属性)。因此,验证器不是放在属性上,而是放在实体上
  • FOSUserBundle将
    $username
    转换为
    $usernamecononical
    ,并基于
    $usernamecononical
    验证
    用户
    实体是否唯一。这实际上是一个非常好的系统,因为您可以影响唯一性检查中使用的值。您甚至可以比strtolower更进一步(默认设置),例如删除非单词字符、将é更改为e等。因此,在检查
    $username
    本身的唯一性时,实际上看不到任何值

  • 您应该能够组合在注释和PHP中定义的约束(但可能不能同时组合在注释和XML中定义的约束)


    Nut检查其他同名用户需要数据库连接,我的印象是这样的查询不能(或至少不应该)从实体类内部运行?在Symfony 2.4中,您可以在外部类中设置这些回调验证。看医生:啊,误解你了。也许这就是你要找的?我不知道更好的解决方案现在我正在考虑验证用户名(虽然其他东西的regexp也很有趣。我自己对这个问题的答案(不是真正的答案)表明,我做了一些变通。但我不能继承这个所谓的“免费”的东西唯一用户名和emai…的功能是ORM用户验证。您将看到为验证组“注册”和“配置文件”设置了
    Symfony\Bridge\doctor\Validator\Constraints\uniquentity
    ,因此“注册”将不起作用。请尝试
    $userManager->updateUser($entity,false);var\u dump($entity);exit();
    查看您的实体值。我不确定还可以尝试什么,因为您有很多不同的代码尝试执行相同的操作(例如表单中的验证程序事件侦听器)。我通常通过查看对象中的数据来解决这类问题,以确保所有内容都已正确设置。具体而言,UsernameCononical、emailCanonical、plainPassword、password等。我怀疑UsernameCononical字段未设置。请尝试调用
    $userManager->updateCanonicalFields($entity);
    在验证之前。我想知道是否设置了UsernameCononical字段(否则验证将不起作用)。如果手动调用updateCanonicalFields,然后进行验证,我打赌它可以解决您的问题。
    // setting values manually
    $userManager = $this->container->get('fos_user.user_manager');
    $user = $userManager->createUser();
    $user->setName('Joe');
    $user->setUsername('joeuser');
    $user->setEmail('joe@gmail.com');
    $user->setPlainPassword('secret');
    $user->addRole('ROLE_EDITOR');
    
    // persist to database
    $userManager->updateUser($user);
    
    // inherited validations that check for username and email uniqueness
    // using validation group names 'Registration' and 'Profile'
    $uniqueEmail = $user->getEmailCanonical();
    $uniqueUsername = $user->getUsernameCanonical();
    
    // setting values from a form
    $userManager = $this->container->get('fos_user.user_manager');
    $user = $userManager->createUser();
    
    $form = $this->container->get('form.factory')
        ->createBuilder('form', $user, array('validation_groups' => 'Registration'))
        ->add('username', 'text')
        ->add('email', 'email')
        ->add('name', 'text')
        ->add('plainPassword', 'repeated', array(
            'type' => 'password'
        ))
        ->getForm();
    
    if ($request->isMethod('POST')) {
        $form->handleRequest($request);
        if ($form->isValid()) {
            $userManager->updateUser($user);
    
            // redirect response
        }
    }
    
    return $this->container->get('templating')->renderResponse($templateName, array(
        'form' => $form->createView()
    ));
    
    use Symfony\Component\Security\Core\User\AdvancedUserInterface;
    use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
    use FOS\UserBundle\Model\User as BaseUser;
    use Doctrine\ORM\Mapping as ORM;
    use BizTV\BackendBundle\Entity\company;
    
    /**
     * @Assert\Callback(methods={"validateName"})
     */
    class User extends BaseUser implements AdvancedUserInterface
    {
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;  
    
    /**
    * @var object BizTV\BackendBundle\Entity\company
    *  
    * @ORM\ManyToOne(targetEntity="BizTV\BackendBundle\Entity\company")
    * @ORM\JoinColumn(name="company", referencedColumnName="id", nullable=false)
    */
    protected $company; 
    
    /**
    * @var object BizTV\UserBundle\Entity\UserGroup
    * @ORM\ManyToOne(targetEntity="BizTV\UserBundle\Entity\UserGroup")
    * @ORM\JoinColumn(name="userGroup", referencedColumnName="id", nullable=true)
    */
    protected $userGroup;   
    
    /**
     * @param ExecutionContextInterface $context
     */
    public function validateName(ExecutionContextInterface $context)
    {
        // do some validation
    
        // or add violation
            $context->addViolationAt(
                'name',
                'Name "%name% is not valid',
                array('%name%' => $this->getName()),
                null
            );
    }
    
    <?php
    
    /* ... */
    
    use Symfony\Component\Validator\Mapping\ClassMetadata;
    
    class User extends BaseUser implements AdvancedUserInterface
    {
      /* ... */
    
      public static function loadValidatorMetadata(ClassMetadata $metadata)
      {
        $metadata->addPropertyConstraint(
            'username'
          , new Assert\Regex(array(
                'pattern' => '/^[a-zA-Z0-9_]$/'
            )
        ));
        $metadata->addPropertyConstraint(
            'username'
          , new BizTVAssert\NameExists()
        ));
      }
    
      /* ... */
    }