8

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

我提出了这个问题:FOSUserBundle - 验证用户名、密码或电子邮件字段
但是由于我使用了一堆注释验证,这对我不起作用。

后续问题 - 我在fosUSerBundleXML 文件中看到,用于验证用户它本身有一个检查器以使用已获取的用户名。我没有获得该功能,如果我尝试添加与现有用户同名的用户,我的会直接出现 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;   

因此,我查看了此处(symfony2 在表单中使用验证组)并通过在构建表单时将其添加到控制器来尝试该解决方案。什么都没有发生(仍然直接跳转到 INSERT INTO SQL 错误)

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

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

use Symfony\Component\OptionsResolver\OptionsResolverInterface;

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

仍然没有任何反应。保存时直接出现 SQL 错误。

4

5 回答 5

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 验证,但它们位于验证组中。有关验证组的更多信息,请点击此处此处

到目前为止,在我看来,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()
));

我希望这有帮助。让我知道我是否可以提供更多详细信息。我会在这里发布我的一些代码,但我的实现有点不同。

于 2013-11-13T06:13:40.520 回答
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()
    ));
  }

  /* ... */
}
于 2013-11-14T21:12:27.643 回答
2

这不完全是问题的答案,但到目前为止对我来说是一个解决方案。我将验证器添加到我的表单(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 (_)"));
        }

    };
于 2013-10-31T19:54:37.993 回答
1

实现 Symfony 食谱中记录的回调验证约束: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
        );
}
于 2013-11-13T13:04:38.403 回答
0

对于更改验证$username,我鼓励您执行FOSUserBundle - 更改用户名验证中描述的步骤,这是最简单的方法。在一个项目中同时使用 XML 和 Annotations 没有任何问题。实际上建议不要使用注释,因为它将映射元数据保留在实体/类之外,这是 ( Data ) Mapper 模式的重点。

另一种方法是扩展FOS\UserBundle\Model\User,而是实施FOS\UserBundle\Model\UserInterface。您必须进行一些小调整才能使这项工作正常进行,UserProvider此处进行了描述。接下来你必须自己完成所有的映射,你可以自由地使用任何你想要的注解。UserManager

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

  1. 您不是在检查属性是否唯一,而是检查实体是否唯一(基于属性)。所以验证器不是放在一个属性上,而是放在一个实体上。
  2. FOSUserBundle 将 转换$username$usernameCanonical,并根据 验证User实体是否唯一$usernameCanonical。这实际上是一个非常好的系统,因为您可以影响唯一性检查中使用的值。您甚至可以比strtolower(默认值)更进一步,例如删除非单词字符,将 é 更改为 e 等。因此,在检查$username自身的唯一性方面并没有真正看到任何价值。
于 2013-11-13T19:02:12.217 回答