自
以来@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'),
));
}
答案 0 :(得分:1)
如果您使用FOSUserBundle UserManager更新用户实体,则无需担心用户名字段中的唯一性。基本用户具有usernameCanonical和emailCanonical字段,这些字段经过验证,具有唯一性。
在持久化用户之前(在使用Doctrine实现时),幕后使用事件侦听器来更新规范字段。
“要保存用户对象,可以使用用户管理器的updateUser方法。此方法将更新编码密码和规范字段,然后保留更改。”
您可以免费获得唯一的用户名和电子邮件字段!
答案 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;
}
}