0

由于

@UniqueEntity(fields = "用户名"...

下面绝对什么都不做(可能是因为用户名是继承的,而不是我在用户类中明确定义的?)我想我将不得不做一些简单的事情,比如在控制器或表单验证中手动检查具有该名称的现有用户。所以我使用表单验证。

我不知道如何从表单类访问数据库,手动从表单类内部使用 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';
    }
}

顺便说一句,这是我的实体:

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 而不是保留我自己的 $entity,这会让我利用唯一检查等吗?

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

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

我根据this更改了代码

        $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 在表单中使用验证组)并通过在构建表单时将其添加到控制器来尝试该解决方案,但没有任何反应(仍然直接跳转到 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'),
));
}
4

3 回答 3

1

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

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

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

更新用户对象

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

于 2013-11-09T05:18:43.380 回答
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.")
于 2013-11-08T17:04:48.383 回答
0

我想我的问题隐藏在其他地方的代码中,因为没有任何建议有效……我猜它太本地化了。

无论如何,我最终不得不以这种方式“手动”解决它,而不使用内置函数进行验证。很烦人,但它有效。在 ->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;
            }


    }
于 2013-11-25T10:10:29.900 回答