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

时间:2013-10-31 12:19:37

标签: validation symfony fosuserbundle username

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

我提出这个问题FOSUserBundle - Validation for username, password or email fields,但因为我使用了一堆对我不起作用的注释验证。

后续问题 - 我在fosUSerBundle XML文件中看到用于验证用户本身是一个使用截取用户名的检查器,我没有得到该功能,如果我有直接的SQL错误消息尝试添加与现有用户同名的用户。这是因为我使用注释会一起覆盖XML验证文件吗?

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;   

所以我看了这里(symfony2 using validation groups in form)并在构建表单时将其添加到控制器中尝试了该解决方案,没有任何反应(仍然直接跳转到INSERT INTO SQL错误)

    $entity  = new User();
    $request = $this->getRequest();
    $form    = $this->createForm(new newUserType($tempCompany), $entity, array('validation_groups'=>'registration'));
    $form->bind($request);

我还试图在表单类中设置此validatino组“注册组”(这应该为您提供免费的“唯一用户和电子邮件验证”):

use Symfony\Component\OptionsResolver\OptionsResolverInterface;

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

仍然没有任何反应。保存时直接导致SQL错误...

5 个答案:

答案 0 :(得分:3)

我提前道歉。我不完全确定您是要验证$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;
    }
}

继承了唯一的usernameCanonical和emailCanonical验证,但它们位于验证组中。有关验证组herehere的更多信息。

到目前为止,我觉得FOSUserBundle使用的用户管理器就像是一个存储库,所以你会希望尽可能地使用它来与存储层进行交互。以下是控制器中的内容(同样,未经测试):

// 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()
));

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

答案 1 :(得分:3)

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

<?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()
    ));
  }

  /* ... */
}

答案 2 :(得分:1)

这不是问题的答案,而是迄今为止的解决方案。我将验证器添加到我的表单(UserType)。

    $validatorUsername = function(FormEvent $event){
        $form = $event->getForm();
        $myExtraField = $form->get('username')->getData();
        if ( preg_match('/^[a-zA-Z0-9_]+$/',$myExtraField) == false ) {
          $form['username']->addError(new FormError("Du får inte använda andra specialtecken än understreck (_)"));
        }

    };

答案 3 :(得分:1)

实现Symfony cookbook中记录的回调验证约束:http://symfony.com/doc/current/reference/constraints/Callback.html

示例:

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

答案 4 :(得分:0)

要更改$username上的验证,我建议您采取FOSUserBundle - Change username validation中描述的步骤,这是最简单的方法。在单个项目中同时使用XML和Annotations没有任何问题。实际上建议使用Annotations,因为它将映射元数据保留在实体/类之外,这是(DataMapper pattern的全部要点。

另一种方法是扩展FOS\UserBundle\Model\User,但实施FOS\UserBundle\Model\UserInterface。您必须对UserProviderUserManager进行一项小调整才能完成这项工作,它的描述为here。 接下来,您必须自己完成所有映射,您可以自由使用所需的任何注释。

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

  1. 您没有检查属性是否唯一,但是实体是否是唯一的(基于属性)。因此验证器不会放在属性上,而是放在实体上。
  2. FOSUserBundle将$username翻译为$usernameCanonical,并根据User验证$usernameCanonical实体是否唯一。这实际上是非常好的系统,因为您可以影响唯一性检查中使用的值。您甚至可以超越strtolower(默认值),例如删除非单词字符,将é更改为e等等。因此,在检查$username本身的唯一性时,实际上看不到任何值。< / LI>
相关问题