I’m new to Yii, and I’m working on a fairly simple project that manages lessons. I want to use DB-based RBAC to display different views to different groups of users. The problem I’m having is figuring out how to condense my user groups into a single User table. Here are the relevant entities with a few example fields.
I want to store different data for the different groups, and the attributes are likely to expand in the future, so I don’t like the idea of putting the Instructors and Adivsors in the same table. I may want to allow Students to use the system at some point too.
I imagine most systems have users who are similarly split, but what’s the accepted way of dealing with this situation? What designs are people here using for their projects? Any advice would be appreciated.
It seems one solution may be to store the [font=“Courier New”]user_id[/font] in the group tables as an FK that may also be the PK, e.g. [font=“Courier New”]Instructor (user_id, name, certification)[/font]. It should then be easy to load the relevant model using [font=“Courier New”]user->id[/font]. I’m not sure how Boyce-Codd would approve of this design, but it does seem to be used to implement inheritance in RDMS. I might give it a go for now, since I’m really just experimenting at the moment.
It would be nice to see/hear about some real examples though, since I can think of many situations with different categories of users that require different attributes to be stored on disk (employee, customer; job-seeker, recruiter; student, professor etc).
One way of doing it is through composition instead of inheritance.
A user is just an id with basic name, password and whathaveyou, and then you’ll have the Instructor, Advisor etc tables linked to the user table through a user_id field. To access the advisor fields, set up an advisor relation in the User object to the other table, and you’d just do
$user->advisor->specialty;
You will have all users in one table, just not all fields. The RBAC thing is a bit different, but if you want you could just let it depend on the existence of a composition table:
public function isAdvisor(){
return (bool)$this->advisor; // this will return true if an advisor relation exists, false if it doesn't
}
Be sure to eagerly load the relations if you’re going to access a lot of them in one pageview.
Thanks for your suggestions. I’ve done something similar, but it probably needs a bit of polishing.
I was wondering how you’d implement things to get [font=“Courier New”]$user->advisor->specialty[/font]. I’m currently using an instance of [font=“Courier New”]UserIdentity[/font], and adding the [font=“Courier New”]Instructor/Advisor[/font] model using [font=“Courier New”]setState()[/font], which gives me [font=“Courier New”]Yii::app()->user->instructor->specialty[/font].
Also what options should I be looking at for eager loading? At the moment the model for [font="Courier New"]setState()[/font] is coming from a relation in the User model.
public function relations()
{
return array(
'instructor' => array(self::HAS_ONE, 'Instructor', 'username'),
...
);
}