我实际上正在用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;