I'm using Yii RBAC to control user access to my app, it consists of three mySql tables;
authitem
(the RBAC role items)
authitemchild
(any RBAC rules that belong to other roles)
authitemassignment
(assigning roles to a user)
For example we may have tables like so:
authitem:
| name (pk) |
areaASuperUser
areaACreateOnly
areaAReadOnly
areaAUpdateOnly
areaADeleteOnly
areaBSuperUser
areaBCreateOnly
areaBReadOnly
areaBUpdateOnly
areaBDeleteOnly
authitemchild
| parent (pk) | child (pk) |
areaASuperUser areaACreateOnly
areaASuperUser areaAReadOnly
areaASuperUser areaAUpdateOnly
areaASuperUser areaADeleteOnly
areaBSuperUser areaBCreateOnly
areaBSuperUser areaBReadOnly
areaBSuperUser areaBUpdateOnly
areaBSuperUser areaBDeleteOnly
auithitemassignment
| itemname (pk) | userid (pk) |
areaASuperUser 1
In the above scenario, user with id of 1 has complete CRUD access in areaA. What I need is a list of all the roles the user does not have access too, and I need to take into account the children of any roles they have access too as well.
I can easily grab all the roles the user doesn't have access to:
SELECT DISTINCT `ai`.`name`
FROM `authitem` `ai`
LEFT JOIN `authassignment` `aa`
ON `aa`.`itemname` = `ai`.`name` AND `aa`.`userid` = 1
WHERE `aa`.`itemname` IS NULL
But this returns:
| name |
areaACreateOnly
areaAReadOnly
areaAUpdateOnly
areaADeleteOnly
areaBSuperUser
areaBCreateOnly
areaBReadOnly
areaBUpdateOnly
areaBDeleteOnly
And because all the areaA* roles are children of areaASuperUser, I don't want them returned.
Any advice or a push in the right direction would be greatly appreciated!
* Edit:
Thanks @SuVeRa, your answer:
SELECT DISTINCT `ai`.`name`
FROM `authitem` `ai`
LEFT JOIN `authassignment` `aa`
ON `aa`.`itemname` = `ai`.`name` AND `aa`.`userid` = 1
WHERE
`aa`.`itemname` IS NULL
AND `ai`.`name` NOT IN (
SELECT
`aic`.`child` itemname
FROM `authitemchild` `aic`
JOIN `authassignment` `aa`
ON `aa`.`itemname` = `aic`.`parent`
WHERE `aa`.`userid` = 1
)
works perfectly for the example above, however I've just extended the app to include more than one level for children, i.e.
authitem:
| name (pk) |
areaABSuperUser
areaASuperUser
areaACreateOnly
areaAReadOnly
areaAUpdateOnly
areaADeleteOnly
areaBSuperUser
areaBCreateOnly
areaBReadOnly
areaBUpdateOnly
areaBDeleteOnly
areaCSuperUser
areaCCreateOnly
areaCReadOnly
areaCUpdateOnly
areaCDeleteOnly
authitemchild
| parent (pk) | child (pk) |
areaABSuperUser areaASuperUser
areaABSuperUser areaBSuperUser
areaASuperUser areaACreateOnly
areaASuperUser areaAReadOnly
areaASuperUser areaAUpdateOnly
areaASuperUser areaADeleteOnly
areaBSuperUser areaBCreateOnly
areaBSuperUser areaBReadOnly
areaBSuperUser areaBUpdateOnly
areaBSuperUser areaBDeleteOnly
areaCSuperUser areaCCreateOnly
areaCSuperUser areaCReadOnly
areaCSuperUser areaCUpdateOnly
areaCSuperUser areaCDeleteOnly
auithitemassignment
| itemname (pk) | userid (pk) |
areaABSuperUser 1
The original answer would return;
| name |
areaACreateOnly
areaAReadOnly
areaAUpdateOnly
areaADeleteOnly
areaBCreateOnly
areaBReadOnly
areaBUpdateOnly
areaBDeleteOnly
areaCSuperUser
areaCCreateOnly
areaCReadOnly
areaCUpdateOnly
areaCDeleteOnly
As it's filtering out the parent and child, but not the children of children. The result I'm after (in this second example) is:
| name |
areaCSuperUser
areaCCreateOnly
areaCReadOnly
areaCUpdateOnly
areaCDeleteOnly
***Edit 2:
Specifically for Yii:
I've done some more reading into Yii, and CAuthManager has a number of helpful methods, including hasItemChild(), isAssigned(), getItemChildren(), ... and others, that could help with grabbing data like I need