Let's say we have 3 main roles that are directly bound to the database table user: ROLE_USER, ROLE_MODERATOR and ROLE_ADMIN.
BUT, we also got some other roles, which are used for the Crews component (see UML below). I use the following roles for actions peformed in a Crew: ROLE_CREW_BOSS, ROLE_CREW_LEFTHAND, ROLE_CREW_RIGHTHAND, ROLE_CREW_MEMBER.
+----------------+ +------------------+
| users | | crews |
|----------------| |------------------|
| id | | id |
| username <---+ | name |
| password | | +---> cash |
| roles | | +-------------------+ | | ... |
| ... | | | crew_members | | | |
| | | |-------------------| | | |
+----------------+ | | crew_id +--------------+ | |
+----+ user_id | +--------^---------+
| roles | |
| ... | +------------+
| | |
| | | +------------------+
| | | | forum_topics |
| | | |------------------|
| | | | id |
+-------------------+ +---+ crew_id |
| title |
| description |
| ... |
| |
| |
| |
+------------------+
That is the base structure, I hope that part is clear. Now comes the problem...
The problem
Every user with the role ROLE_MODERATOR can create ForumTopic objects, but not the one where crew_id is set, because that one is private for a specific crew. Also, only crew members (which are also users) that have the role ROLE_CREW_BOSS, ROLE_CREW_LEFTHAND or ROLE_CREW_RIGHTHAND can edit the forum topics of their crew. How do I check those kind of complexity? With a Voter maybe?
UPDATE 1
I have solved the problem for 50%, but it's not solid. I've created a voter specific for the object Entity\\ForumTopic.
public function vote(TokenInterface $token, $object, array $attributes)
{
if ($object instanceof ObjectIdentityInterface) {
if ($object->getType() == 'Entity\\ForumTopic') {
/**
* @var Member $member
*/
$member = $token->getUser();
$userTable = new UserTable();
$user = $userTable->getByMember($member);
$userInCrewTable = new UserInCrewTable();
$crewMember = $userInCrewTable->getByUser($user);
if ($crewMember && in_array($crewMember->getRole(), array('boss', 'lefthand', 'righthand'))) {
return self::ACCESS_GRANTED;
}
}
}
return self::ACCESS_ABSTAIN;
}
The only problem here is that I don't use the respective roles, so I can't use the role hierarchy functionality for example. Anyone got a better solution or a improvement on my current solution?
Thanks!
Steffen