Symfony2在表单字段上执行高级操作以设置用户角色

时间:2013-10-11 11:15:50

标签: php forms symfony drop-down-menu doctrine

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

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

这是我对\ Entity \ User.php

的ORM定义
<?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);
    }
}

在DB中报告如下:

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

这是我对\ Entity \ Role.php

的ORM定义
<?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;
    }
}

在DB中报告如下:

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

此外,ORM命令自动生成(无需在我的Entity文件夹中编写自定义类),表user_roles为我管理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)我的表单映射到User.php实体上,我不知道如何添加一个引用另一个实体(Role.php)的表单字段,与默认的'data_class'不同。

2)另一个问题是我需要提取一个字符串orray(角色的人类可重复名称)来显示我的Dropdown上的选项,但是我需要在DB中插入相关的id而不是串即可。我该怎么做?我是否应该这样做:http://symfony.com/doc/current/cookbook/form/data_transformers.html

3)我认为表单字段实例(下拉列表)不允许我在我的数据库(关联ID_USER和ID_ROLE)中自动插入一个包含2个字段的新记录。使这成为可能的最佳方法是什么?我想我需要从我的下拉字段中提取值并在控制器中构建一个查询,但是我该怎么做呢?

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

1 个答案:

答案 0 :(得分:1)

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;