Let me start by giving you a diagram of the relationships between the tables used in my mysql query:
(source: r717.net )
I have a query that looks like this:
SELECT *
FROM `permissions`
WHERE `id` IN (
SELECT pr.perm_id
FROM `user_roles` as ur
LEFT JOIN `permissions_role` as pr
ON ur.role_id = pr.role_id
WHERE ur.user_id = '$userid'
)
OR `id` IN (
SELECT `perm_id`
FROM `permissions_user`
WHERE `user_id` = '$userid'
)
$userid
is the id from the user table for the current user. I store the permission name from the result into an array which represents all permissions assigned to the user based on his/her role and his/her id:
<?php
$user_perms = array();
if(mysql_num_rows($query) > 0):
while($result = mysql_fetch_array($query):
$user_perms[] = $result('name');
endwhile;
endif;
?>
print_r($user_perms);
produces an output that looks like:
Array (
[0] => ACCESS_TELEPHONELIST_PAGE
[1] => ACCESS_VACATIONSCHED_PAGE
[2] => ACCESS_TOURSCHED_PAGE
[3] => ACCESS_WORKSCHED_PAGE
[4] => ACCESS_RESOURCES_LINKS
[5] => ACCESS_PMTOOL_PAGE
[6] => ACCESS_TOOLSTOOL_PAGE
[7] => ACCESS_SHOPTOOLLIST_PAGE
[8] => ACCESS_TOOLINVENTORY_PAGE
[9] => ACCESS_MANAGETOOLLIST_PAGE
[10] => ACCESS_TOOLREPORTS_PAGE
[11] => ACCESS_JOBSLIST_LINKS
[12] => MAIN_TAB_TOOLSTOOL
[13] => ADMIN_TAB_PODMANAGEMENT
[14] => TOOL_TAB_SHOPTOOLLIST
)
What I want to do is to also store all of the user's roles into another array without making a second query. I thought I needed to use aliases for the sub queries, so I tried this query:
SELECT permissions.*, usersroles.role_id
FROM `permissions`
INNER JOIN (
SELECT ur.user_id, pr.perm_id, ur.role_id
FROM `user_roles` as ur
LEFT JOIN `permissions_role` as pr
ON ur.role_id = pr.role_id
WHERE ur.user_id = '$userid'
) AS usersroles ON usersroles.perm_id = permissions.id
INNER JOIN (
SELECT `perm_id`, `user_id`
FROM `permissions_user`
WHERE `user_id` = '$userid'
) AS userperms ON userperms.user_id = usersroles.user_id
AND userperms.perm_id = permissions.id
and, using code similar to the code above...
<?php
$user_perms = array();
$user_roles = array();
if(mysql_num_rows($query) > 0):
while($result = mysql_fetch_array($query):
$user_perms = $result('name');
$user_roles = $result('role_id');
endwhile;
endif;
?>
... I get this warning:
Warning: mysql_num_rows() expects parameter 1 to be resource, boolean given
But, I would like to print_r($user_roles);
and produce an output that looks like this:
Array (
[0] => administrator
[1] => humanresources
[2] => podmanager
)
Can anyone tell me what I am doing wrong, or suggest a better way to get the data I need from one query into 2 arrays?
EDIT : After careful consideration, I changed my code to use 2 queries as ImreL suggested. The resulting code works nicely and executes quickly. I have edited my answer to show the final code I used and added supporting code to demonstrate how I am using the 2 queries. Big thanks to ImreL!
The query will be required to run on every page the user loads and we have over 30,000 permissions, and 3,000 roles. I am just trying very hard to keep my number of queries to a minimum. We also host our 7 sites on a server in our office, and the server doesn't seem to be capable of handling the amount of traffic we generate (unfortunately I have no control over this)
I see that your intentions are good, but let me tell you this:
The "number of queries" is not the right way to measure your site's performance.
Many times 2 simple queries use less resources than 1 complex.
Also there are other ways to speed up your sites:
So finally, I tried to come up with query to satisfy what was asked:
select * from (
select ur.role_id, p.*
from user_roles ur
left join permissions_role pr on ur.role_id = pr.role_id
left join permissions p on p.id = pr.perm_id
where ur.user_id = '$userid'
union all
select null as role_id, p.*
from permissions_user pu
join permissions p on p.id = pu.perm_id
where pu.user_id = '$userid'
) sub
group by ifnull(name,role_id) -- group by to eliminate duplicates
But this is not good on performance. You are much better off with 2 queries: 1st to get all permissions for user
select p.* from permissions p
join permissions_role pr on pr.perm_id = p.id
join user_roles ur on ur.role_id = pr.role_id and ur.user_id = '$userid'
union
select p.* from permissions p
join permissions_user pu on pu.perm_id = p.id and pu.user_id = '$userid';
and 2nd to get all roles.
EDIT : Here are the final working queries. Also, I thought it might be useful for others to see how the queries are used, so a full explanation is included.
//build the array(s)
$userperms = array();
$userroles = array();
if(isset($_SESSION['userid'])):
//get the userid
$thisuserid = $_SESSION['userid'];
//get the permissions for each of the user's roles
$Cpermissions_role = mysql_query("
SELECT r.type, ur.user_id, pr.perm_id, ur.role_id, p.name
FROM user_roles ur
LEFT JOIN permissions_role pr ON ur.role_id = pr.role_id
LEFT JOIN roles r ON ur.role_id = r.id
LEFT JOIN permissions p ON p.id = pr.perm_id
WHERE ur.user_id = '$userid'") or die(mysql_error());
//get the extra permissions for the user
$Cpermissions_user = mysql_query("
SELECT pu.user_id, pu.perm_id, p.name
FROM permissions_user pu
LEFT JOIN permissions p ON p.id = pu.perm_id
WHERE pu.user_id = '$userid'") or die(mysql_error());
//build an array of the user's roles & an array of the user's permissions
if(mysql_num_rows($Cpermissions_role) > 0):
while($Rpermissions_role = mysql_fetch_array($Cpermissions_role)):
if(empty($userperms)):
$userperms[] = $Rpermissions_role['name'];
elseif(!in_array($Rpermissions_role['name'],$userperms)):
$userperms[] = $Rpermissions_role['name'];
endif;
if(empty($userroles)):
$userroles[] = $Rpermissions_role['type'];
elseif(!in_array($Rpermissions_role['type'],$userroles)):
$userroles[] = $Rpermissions_role['type'];
endif;
endwhile;
endif;
if(mysql_num_rows($Cpermissions_user) > 0):
while($Rpermissions_user = mysql_fetch_array($Cpermissions_user)):
if(empty($userperms)):
$userperms[] = $Rpermissions_user['name'];
elseif(!in_array($Rpermissions_user['name'],$userperms)):
$userperms[] = $Rpermissions_user['name'];
endif;
endwhile;
endif;
endif;
/**
* Determines if the user has permission for the page or parts of page
* @param string $perm the permission constant
* @return boolean true if user has access, false if not
*/
function hasPermission($perm){
global $userperms;
if(empty($userperms)):
return false;
else:
if(is_array($userperms)):
if(in_array($perm,$userperms)):
return true;
else:
return false;
endif;
else:
if($perm == $userperms):
return true;
else:
return false;
endif;
endif;
endif;
}
Then, I use the following decision statement:
if(hasPermission("ACCESS_HOME_PAGE")):
//perform circus tricks here
endif;
So, now print_r($userperms);
outputs this:
Array (
[0] => ACCESS_TELEPHONELIST_PAGE
[1] => ACCESS_VACATIONSCHED_PAGE
[2] => ACCESS_TOURSCHED_PAGE
[3] => ACCESS_WORKSCHED_PAGE
[4] => ACCESS_RESOURCES_LINKS
[5] => ACCESS_PMTOOL_PAGE
[6] => ACCESS_TOOLSTOOL_PAGE
[7] => ACCESS_SHOPTOOLLIST_PAGE
[8] => ACCESS_TOOLINVENTORY_PAGE
[9] => ACCESS_MANAGETOOLLIST_PAGE
[10] => ACCESS_TOOLREPORTS_PAGE
[11] => ACCESS_JOBSLIST_LINKS
[12] => MAIN_TAB_TOOLSTOOL
[13] => ADMIN_TAB_PODMANAGEMENT
[14] => TOOL_TAB_SHOPTOOLLIST
[15] => ACCESS_HOME_PAGE
)
And, print_r($userroles);
outputs this:
Array (
[0] => administrator
[1] => humanresourcees
[2] => podmanager
)
And, just to be thorough, here is the JavaScript I use to access the php array:
var js_userperms = new Array();
js_userperms = ["<?php echo join("\", \"", $userperms); ?>"];
And, the jQuery decision statement:
if(jQuery.inArray("ACCESS_HOME_PAGE", js_userperms) != -1){
//perform circus tricks here
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.