symfony2不会检查uniqueUser

时间:2013-11-07 21:16:47

标签: forms validation symfony doctrine unique

以来

@UniqueEntity(fields =“username”...

下面的

绝对没有(可能是因为用户名是继承的,而且我没有在用户类中明确定义?) 我想我必须做一些简单的事情,比如在控制器或表单验证中手动检查具有该名称的现有用户。所以我选择表单验证。

我不知道怎么做是如何从表单类到达数据库,手动使用表单类中的queryBuilder。

这是我的表单类:

namespace BizTV\UserBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormError;

use Doctrine\ORM\EntityRepository;

class editUserType extends AbstractType
{

    function __construct($company)
    {
        $this->company = $company;
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {

        $company = $this->company;

        $builder
            ->add('locked', 'checkbox', array('label' => 'Kontot är låst, användaren kan inte logga in '))
            ->add('username', 'text', array('label' => 'Användarnamn '))
        ;

        $builder
            ->add('userGroup', 'entity', array(
                'label' => 'Användargrupp',
                'empty_value' => 'Ingen grupptillhörighet',
                'property' => 'name',
                'class'    => 'BizTV\UserBundle\Entity\UserGroup',
                'query_builder' => function(\Doctrine\ORM\EntityRepository $er) use ($company) {
                    $qb = $er->createQueryBuilder('a');
                    $qb->where('a.company = :company');
                    $qb->setParameters( array('company' => $company) );
                    $qb->orderBy('a.name', 'ASC');

                    return $qb;
                }
            ));         


        $builder
            ->add('email', 'email', array('label' => 'Epost '))
            ->add('plainPassword', 'repeated', array('type' => 'password', 'first_name' => 'Nytt_losenord', 'second_name' => 'Upprepa_losenord',));

        $builder
            ->add('roles', 'choice', array(
                'label' => 'Roller',
                'expanded' => true,
                'multiple' => true,
                'choices'  => array(
                    'ROLE_CONTENT' => 'Innehåll (Användaren kan lägga till, redigera och ta bort innehåll där du nedan beviljar åtkomst)',
                    'ROLE_LAYOUT'  => 'Skärmlayout (Användaren kan skapa ny skärmlayout, redigera befintlig eller ta bort gällande skärmlayout där du nedan beviljar åtkomst)',
                    'ROLE_VIDEO'   => 'Videouppladdning (Användaren har rätt att ladda upp videofiler till företagets mediabibliotek)',
                    'ROLE_ADMIN'   => 'Administratör (Användaren är administratör med fulla rättigheter till allt precis som det konto du nu är inloggad på, var mycket restriktiv med att tilldela denna behörighet).',
                ),
            ))
        ;

        $builder
            ->add('access', 'entity', array(
                'label' => 'Behörigheter',
                'multiple' => true,   // Multiple selection allowed
                'expanded' => true,   // Render as checkboxes
                'property' => 'select_label',
                'class'    => 'BizTV\ContainerManagementBundle\Entity\Container',
                'query_builder' => function(\Doctrine\ORM\EntityRepository $er) use ($company) {
                    $qb = $er->createQueryBuilder('a');
                    $qb->innerJoin('a.containerType', 'ct');
                    $qb->where('a.containerType IN (:containers)', 'a.company = :company');
                    $qb->setParameters( array('containers' => array(1,2,3,4), 'company' => $company) );
                    $qb->orderBy('ct.id', 'ASC');

                    return $qb;
                }
            ));



        $validatorEmail = function(FormEvent $event){
            $form = $event->getForm();
            $myExtraField = $form->get('email')->getData();
            if (empty($myExtraField)) {
              $form['email']->addError(new FormError("Du måste ange en epostadress för användaren"));
            }
        };


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

        $validatorUsernameTaken = function(FormEvent $event){
            $form = $event->getForm();
            $myExtraField = $form->get('username')->getData();

    //TODO: CHECK IN DB FOR USER WITH THAT NAME

            if ($taken) {
              $form['username']->addError(new FormError("Du måste ange ett namn för användaren"));
            }            
        };



        // adding the validator to the FormBuilderInterface
        $builder->addEventListener(FormEvents::POST_BIND, $validatorEmail);
        $builder->addEventListener(FormEvents::POST_BIND, $validatorUsername);
        $builder->addEventListener(FormEvents::POST_BIND, $validatorUsernameTaken);

        //TODO check if username exists 

    }

    public function getName()
    {
        return 'biztv_userbundle_newusertype';
    }
}

BTW这是我的实体:

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;

/**
 * @ORM\Entity
 * @ORM\Table(name="fos_user")
 * @UniqueEntity(fields = "username", message = "En användare med det namnet finns redan, försök igen.")
 */
class User extends BaseUser implements AdvancedUserInterface
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;  

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

    /**
     * @ORM\ManyToMany(targetEntity="BizTV\ContainerManagementBundle\Entity\Container", inversedBy="users")
     * @ORM\JoinTable(name="access")
     */
    private $access;

    /**
    * @var object BizTV\ContainerManagementBundle\Entity\Container
    * 
    * This only applies to the BizTV server user accounts or "screen display accounts". Others will have null here. 
    *  
    * @ORM\ManyToOne(targetEntity="BizTV\ContainerManagementBundle\Entity\Container")
    * @ORM\JoinColumn(name="screen", referencedColumnName="id", nullable=true)
    */
    protected $screen;  

    /**
     * @ORM\Column(type="boolean", nullable=true)
     */
    protected $isServer;


    public function __construct()
    {
        parent::__construct();

        $this->access = new \Doctrine\Common\Collections\ArrayCollection();

    }

    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set company
     *
     * @param BizTV\BackendBundle\Entity\company $company
     */
    public function setCompany(\BizTV\BackendBundle\Entity\company $company)
    {
        $this->company = $company;
    }

    /**
     * Get company
     *
     * @return BizTV\BackendBundle\Entity\company 
     */
    public function getCompany()
    {
        return $this->company;
    }

    /**
     * Add access
     *
     * @param BizTV\ContainerManagementBundle\Entity\Container $access
     */
    public function addContainer(\BizTV\ContainerManagementBundle\Entity\Container $access)
    {
        $this->access[] = $access;
    }

    /**
     * Get access
     *
     * @return Doctrine\Common\Collections\Collection 
     */
    public function getAccess()
    {
        return $this->access;
    }   


    /**
     * Set screen
     *
     * @param BizTV\ContainerManagementBundle\Entity\Container $screen
     */
    public function setScreen(\BizTV\ContainerManagementBundle\Entity\Container $screen)
    {
        $this->screen = $screen;
    }

    /**
     * Get screen
     *
     * @return BizTV\ContainerManagementBundle\Entity\Container 
     */
    public function getScreen()
    {
        return $this->screen;
    }

    /**
     * Set isServer
     *
     * @param boolean $isServer
     */
    public function setIsServer($isServer)
    {
        $this->isServer = $isServer;
    }

    /**
     * Get isServer
     *
     * @return boolean 
     */
    public function getIsServer()
    {
        return $this->isServer;
    }

    /**
     * Set userGroup
     *
     * @param BizTV\UserBundle\Entity\UserGroup $userGroup
     */
    public function setUserGroup(\BizTV\UserBundle\Entity\UserGroup $userGroup = null)
    {
        $this->userGroup = $userGroup;
    }

    /**
     * Get userGroup
     *
     * @return BizTV\UserBundle\Entity\UserGroup 
     */
    public function getUserGroup()
    {
        return $this->userGroup;
    }

    //Below should be part of base user class but doesn't work so I implement it manually.

    /**
     * Get lock status
     *
     * @return boolean 
     */
    public function getLocked()
    {
        return $this->locked;
    }    



}

-----更新-----

我的控制器的更新用户方法:

public function createUserAction()
{
    $tempCompany = $this->container->get('security.context')->getToken()->getUser()->getCompany()->getId(); 

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

    if ($form->isValid()) {             

        $em = $this->getDoctrine()->getManager();

        $userManager = $this->container->get('fos_user.user_manager');
        $user = $userManager->createUser();

        $encoder = $this->container->get('security.encoder_factory')->getEncoder($user); //get encoder for hashing pwd later

        //get company
        $currentCompany = $this->container->get('security.context')->getToken()->getUser()->getCompany();

        //Set company
        $entity->setCompany( $currentCompany );

        $tempUsername = $entity->getUsername();
        $entity->setUsername($currentCompany->getCompanyName() . "-" . $tempUsername);

        $entity->setConfirmationToken(null);
        $entity->setEnabled(true);
        $tempPassword = $encoder->encodePassword($entity->getPassword(), $entity->getSalt()); 
        $entity->setPassword($tempPassword);

        $em->persist($entity);
        $em->flush();

        $helper = $this->get('biztv.helper.globalHelper');
        $helper->log('success', 'Användare <strong>'.$entity->getUsername().'</strong> har skapats.');

        return $this->redirect($this->generateUrl('UserManagement'));

    }

    return $this->render('BizTVUserBundle:Default:newUser.html.twig', array(
        'entity' => $entity,
        'form'   => $form->createView()
    ));
}   

我这样做是错的吗?我实际上正如您的建议使用userManager,但仅用于编码密码。我应该持久化使用$ userManager创建的$ user而不是持久保存我自己的$实体,这会让我利用独特的检查等吗?

------------ UPDATE ---------------

@jmickell(在这里发帖回答,因为评论中没有代码格式,感谢您的时间。但我还没有解决方案......)

我根据这个

修改了代码
        $em = $this->getDoctrine()->getManager();

        $userManager = $this->container->get('fos_user.user_manager');
        $user = $userManager->createUser();

        $encoder = $this->container->get('security.encoder_factory')->getEncoder($user); //get encoder for hashing pwd later

        //get company
        $currentCompany = $this->container->get('security.context')->getToken()->getUser()->getCompany();

        //Set company
        $entity->setCompany( $currentCompany );

        $tempUsername = $entity->getUsername();
        $entity->setUsername($currentCompany->getCompanyName() . "-" . $tempUsername);

        $entity->setConfirmationToken(null);
        $entity->setEnabled(true);

        $tempPassword = $encoder->encodePassword($entity->getPassword(), $entity->getSalt()); 
        $entity->setPassword($tempPassword);

        $userManager->updateUser($entity);

它可以保存用户,就像你说没有刷新一样,但是没有对用户名/密码进行验证。我猜这是必须发生的事情,形式是isValid?或者在表单类本身内部?

如果您查看我的表单类(问题的最重要部分),我是否遗漏了对于usernameCanonical和emailCanonical的验证器必须执行的功能?

此外,如果我替换此

        $tempPassword = $encoder->encodePassword($entity->getPassword(), $entity->getSalt()); 
        $entity->setPassword($tempPassword);

这个(据我所知你建议)

$entity->setPlainPassword( $entity->getPassword() );

我最终得到一个SQL错误,告诉我密码字段不能为空......

我也尝试将验证组添加到这样的表单中,但行为没有任何改变

所以我看了这里(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'),
));
}

3 个答案:

答案 0 :(得分:1)

如果您使用FOSUserBundle UserManager更新用户实体,则无需担心用户名字段中的唯一性。基本用户具有usernameCanonical和emailCanonical字段,这些字段经过验证,具有唯一性。

在持久化用户之前(在使用Doctrine实现时),幕后使用事件侦听器来更新规范字段。

“要保存用户对象,可以使用用户管理器的updateUser方法。此方法将更新编码密码和规范字段,然后保留更改。”

Updating a User object

您可以免费获得唯一的用户名和电子邮件字段!

答案 1 :(得分:0)

首先在您的实体中添加:

use Symfony\Bridge\Doctrine\Validator\Constraints as DoctrineAssert;

然后将代码更改为

@DoctrineAssert\UniqueEntity(fields = "username", message = "En användare med det namnet finns redan, försök igen.")

而不是

@UniqueEntity(fields = "username", message = "En användare med det namnet finns redan, försök igen.")

答案 2 :(得分:0)

我想我的问题隐藏在我的代码中,因为没有任何建议可行...猜它太本地化了。

无论如何,我最终必须以这种方式解决它,“手动”而不使用内置函数进行验证。很烦人,但它的工作原理。在 - &gt; isValid()调用之前,我添加了这些......

           //check for users with same name or email
            $nameOccupied = $this->checkNameOccupied($entity);
            if ($nameOccupied==1) {                        
                    $error = new FormError("Det finns redan en användare med det namnet.");
                    $form->get('username')->addError($error);        
            }

            $emailOccupied = $this->checkEmailOccupied($entity);
            if ($emailOccupied==1) {                        
                    $error = new FormError("Det finns redan en användare med den epostadressen.");
                    $form->get('email')->addError($error);        
            }

    if ($form->isValid()) {     

这是实际的检查员..

   /* check whether name of user already is in use */
    private function checkNameOccupied($entity) {

            $name = $entity->getUsername();

            //get company
            $currentCompany = $this->container->get('security.context')->getToken()->getUser()->getCompany();

            $tempUsername = $entity->getUsername();
            $needle = $currentCompany->getCompanyName() . "-" . $tempUsername;

            //look for entity with same name inside container
            $repository = $this->getDoctrine()->getRepository('BizTVUserBundle:User');

            $query = $repository->createQueryBuilder('c')
                    ->where('c.username = :name')
                    ->setParameters(array('name' => $needle))
                    ->getQuery();


            $match = $query->getResult();

            if(isset($match[0])) {
                    //make sure we aren't validating against itself
                    if ( $entity->getId() && $entity->getId() == $match[0]->getId() ) {
                            return false;
                    }
                    else {
                            return true;
                    }                        
            }
            else {
                    return false;
            }


    }