Reputation: 2639
I have two roles in my application, for example ROLE_USER
and ROLE_SUPERUSER
. Users are stored in the database using Doctrine. Users with the ROLE_USER
role are based on a simple User
class. (Getters and setters have been removed for readability.)
namespace Acme\MyBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* @ORM\Entity
* @ORM\Entity(repositoryClass="Acme\MyBundle\Entity\UserRepository")
* @ORM\Table("users")
* @UniqueEntity(
* fields={"email"},
* message="email already used"
* )
*/
class User implements UserInterface, \Serializable
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @ORM\Column(type="string", length=255, unique=true)
* @Assert\NotBlank()
* @Assert\Email()
*/
protected $email;
/**
* @ORM\Column(type="string", length=32)
*/
private $salt;
/**
* @ORM\Column(type="string", length=4096)
*/
private $password;
/**
* @ORM\Column(name="is_active", type="boolean")
*/
private $isActive;
public function __construct()
{
$this->isActive = true;
$this->salt = md5(uniqid(null, true));
}
/**
* @inheritDoc
*/
public function getRoles()
{
return array('ROLE_USER','ROLE_SUPERUSER');
}
}
I have a SuperUser
class that extends User
to provides more fields that only users with ROLE_SUPERUSER
would need.
Acme\MyBundle\Entity\SuperUser.php
namespace Acme\MyBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* @ORM\Entity
* @ORM\Table(name="super_users")
*/
class SuperUser extends User
{
/**
* @var integer
*/
protected $id;
/**
* @var string
*/
protected $email;
/**
* @ORM\Column(type="string", length=32)
*/
proteced $avatar;
/**
* @ORM\Column(type="string", length=50, unique=true)
*/
proteced $username;
}
In my controllers I'm using $user = $this -> getUser();
to get the current user, but this returns an instance of the User
class and I cannot access the SuperUser
properties or methods, even if the user has the role ROLE_SUPERUSER
.
For example, I would like to be able to use the following code.
if ($this->get('security.context')->isGranted('ROLE_SUPERUSER')) {
$avatar = $this->getUser()-> avatar;
}
Is there anyway to be able to do that? I would say there's something to do with Doctrine relationships, but I don't really know what to change.
By the way, as you can see I don't have an username
field in my standard User
class, it's only present in SuperUser
. Does this may cause any problems since the authentication is based on username
?
I think my problem hasn't been clearly exposed, but this might be due to my current code, which is wrong.
I don't have two user tables. I want only one User
class (with one users table). The authentication is operated only on this class with email and password.
I have another class SuperUser```that provides extra fields to users that have the
ROLE_SUPERUSER`` role, but the superusers are users and have an entry in the users table. I just want to create a left join on the concerned rows, that's why I used inheritance. (Maybe there's a better way to do it.)
If I want to get all the emails, I can query the users table. If I want to get all the usernames, since only superusers have one, I can query the superusers table.
Upvotes: 1
Views: 1412
Reputation: 3697
I would go for two entities with a OneToOne relationship (No extends)
/** @Entity **/
class SuperUser
{
// ...
/**
* @ORM\OneToOne(targetEntity="User", mappedBy="superUser")
**/
private $user;
// ...
}
/** @Entity **/
class User
{
// ...
/**
* @ORM\OneToOne(targetEntity="SuperUser", inversedBy="user")
* @ORM\JoinColumn(name="user_id", referencedColumnName="id")
**/
private $superUser;
// ...
}
Otherwise take a look at Inheritance Mapping
Upvotes: 2
Reputation: 5542
You should have two user providers then, and use one master provider:
security:
providers:
master_provider:
chain:
providers: [user, super_user]
user:
entity: { class: Acme\MyBundle\Entity\User, property: username }
super_user:
entity: { class: Acme\MyBundle\Entity\SuperUser, property: username }
firewalls:
main:
provider: master_provider
http://symfony.com/doc/current/cookbook/security/multiple_user_providers.html
Upvotes: 0