Symfony2 对表单字段的高级操作,用于设置用户角色


Symfony2 Advanced operations on Form Field to set user roles

我实际上正在用Symfony2开发一个应用程序。我已经构建了一个具有不同角色的身份验证工作系统,根据官方文档的建议设置了表的结构:http://symfony.com/doc/current/cookbook/security/entity_provider.html

有两个页面,使用表单允许我创建新用户并编辑现有用户,现在我需要实现一个表单字段(选择)来选择与用户关联的角色。无论如何,由于这个检查,我发现了一些困难:

这是我对''实体''用户的ORM定义.php

<?php
namespace Acme'MyBundle'Entity;
use Symfony'Component'Security'Core'User'UserInterface;
use Doctrine'ORM'Mapping as ORM;
use Symfony'Component'Security'Core'User'AdvancedUserInterface;
use Doctrine'Common'Collections'ArrayCollection;
/**
 * @ORM'Entity
 * @ORM'Table(name="Users")
 */
class User implements UserInterface, AdvancedUserInterface, 'Serializable
{
    // Definizione campi
    /**
     * @ORM'Id
     * @ORM'Column(type="integer")
     * @ORM'GeneratedValue(strategy="AUTO")
     */
    protected $id;
    /**
     * @ORM'Column(type="string", unique=true)
     */
    protected $username;
    /**
     * @ORM'Column(type="string")
     */
    protected $password;
    /**
     * @ORM'Column(type="string")
     */
    protected $salt;
    /**
     * @ORM'ManyToMany(targetEntity="Role", inversedBy="users")
     *
     */
    private $roles;
    /**
    * @ORM'Column(type="integer", nullable=true)
    */
    protected $idAnagrafica;
    /**
    * @ORM'Column(type="integer", nullable=true)
    */
    protected $idTipoVisita;
    /**
    * @ORM'Column(type="boolean", nullable=true)
    */
    protected $attivo;

    // Definizioni delle funzioni Get
    /**
    * @return integer
    */
    public function getId()
    {
        return $this->id;
    }
    /**
    * @return string
    */
    public function getUsername()
    {
        return $this->username;
    }
    /**
    * @return string
    */
    public function getPassword()
    {
        return $this->password;
    }
    /**
    * @return string
    */
    public function getSalt()
    {
        if (null === $this->salt)
        {
            $this->salt = sha512(sprintf('%s_%d_%f',uniqid(),rand(0, 99999),microtime(true)));
        }
        return $this->salt;
    }
     /**
     * @return array
     */
     public function getRoles()
     {
         return $this->roles->toArray();
     }
    /**
    * @return integer
    */
    public function getIdRole()
    {
        return $this->idRole;
    }
    /**
    * @return integer
    */
    public function getIdAnagrafica()
    {
        return $this->idAnagrafica;
    }
    /**
    * @return integer
    */
    public function getIdTipoVisita()
    {
        return $this->idTipoVisita;
    }
    /**
    * @return boolean
    */
    public function getAttivo()
    {
        return $this->attivo;
    }
    // Funzioni di servizio
    public function __construct()
    {
        $this->roles = new ArrayCollection();
    }
    /**
    * @see 'Serializable::serialize()
    */
    public function serialize()
    {
        return serialize(array($this->id,));
    }
    /**
    * @see 'Serializable::unserialize()
    */
    public function unserialize($serialized)
    {
        list ($this->id,) = unserialize($serialized);
    }
    // Definizione delle funzioni Set
    /**
    * @return void
    */
    public function eraseCredentials()
    {
        $this->roles = null;
    }
    /**
     * Set username
     *
     * @param string $username
     * @return User
     */
    public function setUsername($username)
    {
        $this->username = $username;
        return $this;
    }
    /**
     * Set password
     *
     * @param string $password
     * @return User
     */
    public function setPassword($password)
    {
        $this->password = $password;
        return $this;
    }
    /**
     * Set salt
     *
     * @param string $salt
     * @return User
     */
    public function setSalt($salt)
    {
        $this->salt = $salt;
        return $this;
    }
    /**
     * Set idAnagrafica
     *
     * @param integer $idAnagrafica
     * @return User
     */
    public function setIdAnagrafica($idAnagrafica)
    {
        $this->idAnagrafica = $idAnagrafica;
        return $this;
    }
    /**
     * Set riferimento idTipoVisita
     *
     * @param integer $idTipoVisita
     * @return User
     */
    public function setIdTipoVisita($idTipoVisita)
    {
        $this->idTipoVisita = $idTipoVisita;
        return $this;
    }
    /**
     * Set attivo
     *
     * @param boolean $attivo
     * @return User
     */
    public function setAttivo($attivo)
    {
        $this->attivo = $attivo;
        return $this;
    }
    // Funzioni advance user interface
    public function isAccountNonExpired()
    {
        return true;
    }
    public function isAccountNonLocked()
    {
        return true;
    }
    public function isCredentialsNonExpired()
    {
        return true;
    }
    public function isEnabled()
    {
        return $this->attivo;
    }

    /**
     * Add roles
     *
     * @param 'Acme'MyBundle'Entity'Role $roles
     * @return User
     */
    public function addRole('Acme'MyBundle'Entity'Role $roles)
    {
        $this->roles[] = $roles;
        return $this;
    }
    /**
     * Remove roles
     *
     * @param 'Acmee'MyBundle'Entity'Role $roles
     */
    public function removeRole('Acme'MyBundle'Entity'Role $roles)
    {
        $this->roles->removeElement($roles);
    }
}

在数据库中报告如下:

ID | USERNAME | PASSWORD | ATTIVO | SALT | IDANAGRAFICA | IDTIPOVISITA
----------------------------------------------------------------------
...| ...      | ...      | ...    | ...  | ...          | ...

这是我对''实体''角色的ORM定义.php

<?php
namespace Acme'MyBundle'Entity;
use Symfony'Component'Security'Core'Role'RoleInterface;
use Doctrine'ORM'Mapping as ORM;
use Doctrine'Common'Collections'ArrayCollection;
/**
 * @ORM'Entity
 * @ORM'Table(name="roles")
 */
class Role implements RoleInterface
{
    // Definizione campi
    /**
     * @ORM'Column(name="id", type="integer")
     * @ORM'Id()
     * @ORM'GeneratedValue(strategy="AUTO")
     */
    private $id;
    /**
     * @ORM'Column(name="name", type="string")
     */
    private $name;
    /**
     * @ORM'Column(name="role", type="string", unique=true)
     */
    private $role;
    /**
     * @ORM'ManyToMany(targetEntity="User", mappedBy="roles")
     */
    private $users;
    // Funzioni di servizio
    public function __construct()
    {
        $this->users = new ArrayCollection();
    }
    // Funzioni di tipo Get
    /**
     * Get id
     *
     * @return integer
     */
    public function getId()
    {
        return $this->id;
    }
    /**
     * Get name
     *
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }
    /**
     * @see RoleInterface
     */
    public function getRole()
    {
        return $this->role;
    }
    /**
     * Set role
     *
     * @param string $role
     * @return Role
     */
    public function setRole($role)
    {
        $this->role = $role;
        return $this;
    }
    /**
     * Set name
     *
     * @param string $name
     * @return Role
     */
    public function setName($name)
    {
        $this->name = $name;
        return $this;
    }
}

在数据库中报告如下:

ID | NAME | ROLE
----------------
...| ...  | ...

此外,ORM 命令为我自动生成(无需在我的实体文件夹中编写自定义类)为我管理用户和角色之间关系的表user_roles。

ID_USER | ID_ROLE
-----------------
...     | ...

这是我的表格:

<?php
// src/Acme/MyBundle/Form/Type/UserType.php
namespace Acme'MyBundle'Form'Type;
use  Acme'MyBundle'Entity'User;
use  Acme'MyBundle'Entity'Role;
use Symfony'Component'Form'AbstractType;
use Symfony'Component'Form'FormBuilderInterface;
use Symfony'Component'OptionsResolver'OptionsResolverInterface;
use Doctrine'ORM'EntityRepository;
class UserType extends AbstractType
{
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array('data_class' => 'Acme'MyBundle'Entity'User', 'Acme'MyBundle'Entity'Role'));
    }
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        // Crezione del form
        $builder->add('username', 'text', array('label' => 'Username: ', 'required' => false));
        $builder->add('password', 'repeated', array('first_name' => 'password', 'second_name' => 'confirm', 'type' => 'password'));
        $builder->add('attivo', 'checkbox', array('label' => 'Attivo', 'required'  => false));
        $builder->add('idTipoVisita', 'choice', array('choices' => array('1' => 'Fisiatra', '2' => 'Genetista'), 'required'  => false));
// $builder->add( ***I NEED TO INSERT HERE THE DROPODOWN FIELD TO SELECT THE ROLE*** );
            $builder->add('save', 'submit');
            $builder->add('annulla', 'submit');
        }
        public function getName()
        {
            return 'user';
        }
    }

这是我的控制器:

<?php
// src/Acme/MyBundle/Controller/UserController.php
namespace Acme'MyBundle'Controller;
use Symfony'Bundle'FrameworkBundle'Controller'Controller;
use Symfony'Component'HttpFoundation'Request;
use Acme'MyBundle'Form'Type'UserType;
use Acme'MyBundle'Entity'User;
class UserController extends Controller
{
    // Funzione per la modifica dei dati dell utente
    public function editAction($id, Request $request)
    {
        $em = $this->getDoctrine()->getManager();
        $user = $em->getRepository('AcmeMyBundle:User')->find($id);
        $form = $this->createForm(new UserType(), $user );
        if (!$user) { throw $this->createNotFoundException('Non esiste nessun utente associato a questo id.'); }
        if ($request->isMethod('POST'))
        {
            $form->bind($request);
            // Gestione bottone Annulla
            if ($form->get('annulla')->isClicked())
            {
                return $this->redirect($this->generateUrl('AcmeMyBundle_showAnag', array('id' => $anagrafica->getId())));
            }
            if ($form->isValid())
            {
                $user = $form->getData();
                $user->setSalt(md5(uniqid()));
                $encoder = $this->container
                ->get('security.encoder_factory')
                ->getEncoder($user);
                $user->setPassword($encoder->encodePassword($user->getPassword(), $user->getSalt()));
                $em->persist($user);
                $em->flush();
                return $this->redirect($this->generateUrl('AcmeMyBundle_showAnag', array('id' => $user->getIdAnagrafica($id))));
            }
        }
        return $this->render('AcmeMyBundle:User:edit.html.twig', array('form' => $form->createView(),'user' => $user));
    }
    // Funzione per la creazione di un nuovo utente
    public function newAction($id, Request $request)
    {
        $em = $this->getDoctrine()->getManager();
        $anagrafica = $em->getRepository('AcmeMyBundle:Anagrafiche')->find($id);
        if (!$anagrafica) { throw $this->createNotFoundException('Non esiste nessuna anagrafica associata a questo id.'); }
        $query = $em->getRepository('AcmeMyBundle:User')->createQueryBuilder('p')
            ->where('p.idAnagrafica = :id')
            ->setParameter('id', $id)
            ->getQuery();
        $user = $query->getOneOrNullResult();
        if ($user)
        {
            throw $this->createNotFoundException('Non puoi accedere a questa pagina perchè esiste già un utente associato a questo id anagrafica.');
        }
        $form = $this->createForm(new UserType(), new User() );
        if ($request->isMethod('POST'))
        {
            $form->bind($request);
            // Gestione bottone Annulla
            if ($form->get('annulla')->isClicked())
            {
                return $this->redirect($this->generateUrl('AcmeMyBundle_showAnag', array('id' => $anagrafica->getId())));
            }
            if ($form->isValid())
            {
                $user = $form->getData();
                $user->setSalt(md5(uniqid()));
                $encoder = $this->container
                ->get('security.encoder_factory')
                ->getEncoder($user);
                $user->setPassword($encoder->encodePassword($user->getPassword(), $user->getSalt()));
                $user->setIdAnagrafica($id);
                $em->persist($user);
                $em->flush();
                return $this->redirect($this->generateUrl('AcmeMyBundle_showAnag', array('id' => $user->getIdAnagrafica($id))));
            }
        }
        return $this->render('AcmeMyBundle:User:new.html.twig', array('form' => $form->createView(),'anagrafica' => $anagrafica));
    }
    // Funzione per la selezione della modifica o della creazione di un nuovo record
        public function selectAction($id, Request $request)
        {
            $em = $this->getDoctrine()->getManager();
            $anagrafica = $em->getRepository('AcmeMyBundle:Anagrafiche')->find($id);
            if (!$anagrafica) { throw $this->createNotFoundException('Non esiste nessuna anagrafica associata a questo id.'); }
            $query = $em->getRepository('AcmeMyBundle:User')->createQueryBuilder('p')
                ->where('p.idAnagrafica = :id')
                ->setParameter('id', $id)
                ->getQuery();
            $user = $query->getOneOrNullResult();
            if ($user)
            {
                return $this->redirect($this->generateUrl('AcmeMyBundle_editUser', array('id' => $user->getId())));
            }
            else
            {
                return $this->redirect($this->generateUrl('AcmeMyBundle_newUser', array('id' => $id)));
            }
            return NULL;
    }
}

1)我的表单映射到用户.php实体上,我不知道如何添加引用到另一个实体(角色.php)的表单字段,该字段与默认的"data_class"不同

2)另一个问题是我需要提取字符串(角色的人类可读名称)以在我的下拉列表中显示选项,但我需要在数据库中插入相关 id 而不是字符串。我该怎么做?我有没有做这样的事情:http://symfony.com/doc/current/cookbook/form/data_transformers.html?

3)我想表单字段实例(下拉列表)不允许我在数据库中自动插入带有 2 个字段的新记录(关联ID_USER和ID_ROLE)。实现这一目标的最佳方法是什么?我想我需要从下拉字段中减去值并在控制器中构建一个查询,但是我该怎么做呢?

非常感谢您的建议,问候。

在你的UserType中:

// ...
$builder
   ->add('userroles', 'entity', array(
      'class' => 'AcmeMyBundle:Role',
      'property' => 'name'
      'multiple'  => true));
// ...

User实体中:

// ...
public function setUserroles($roles)
{
   $this->roles = $roles;
   return $this;
}
public function getUserroles()
{
   return $this->roles;
}
// ...

在您的 php 模板中:

<?php if ($view['form']->errors($form['userroles'])): ?>
   <div class="error">
       <?php echo $view['form']->errors($form['userroles']) ?>
   </div>
<?php endif; ?>
<?php echo $view['form']->widget($form['userroles']) ?>

更新:在您的User.php

/**
 * @var 'Doctrine'Common'Collections'Collection
 *
 * @ORM'ManyToMany(targetEntity="Role", inversedBy="users")
 * @ORM'JoinTable(name="User_Role",
 *   joinColumns={
 *     @ORM'JoinColumn(name="user_id", referencedColumnName="id")
 *   },
 *   inverseJoinColumns={
 *     @ORM'JoinColumn(name="role_id", referencedColumnName="id")
 *   }
 * )
 */
private $roles;