I'm contemplating the best way to implement the conditional permissions i.e. Users and Teams are m-to-m. But each Team also has a 1-to-m "Leader" relationship with the User table as well.
For simplicity sake, let's say we have two permission levels, "User" and "Admin". Then lets say, only certain Team administration task i.e. group emails, can only be sent by that team's leader.
At the moment, every action that is specific to team leaders queries the database to check it the current user is the team leader (keeping in mind a user may lead many Teams). I personally don't like seeing "if($user->isLeader($team))" all over the place.
I have considered setting a list of teams lead by a user in the user session on login (ala phpBB) or using a symfony filter to do the same.
However, in the first approach, the data can become stale in the case where another user may change a team's leader. The second approach requires an extra database query on every page load.
Any better ideas? note: there are multiple app in the one project that need to share the same permission model (i.e. backend and api)
I have achieved something similar by over-riding the hasCredential method in myUser to execute custom checks when a certain credential is required.
eg:
You can then add the "team_leader" credential to security.yml like you would any other.
Obviously this depends on you using sfObjectRoutes, so may not be that suitable if you can't do this and can't adapt what you are using, but I think its a nice solution when you can use it!
If you are worried about extra queries, you could look at wrapping some caching around the isLeader calls.
I see 2 options:
Override
sfDoctrineGuardUser::getGuardUser()
Override the getGuardUser method of
sfDoctrineGuardUser
to fetch the Teams when it get's the user. This requires an additional left join, but it saves you later queries.You can then add the user's credentials based on his teams via a filter or by overriding
hasCredential
.Invalidate cached team statuses
If you don't want any additional queries, the only additional option I see is to use a global cache. This would involve the following:
apc_add(team_invalid_[team_id], true, [length_of_session])