One option I found was to use the hook_node_access
this function has three inputs
$node
The Node object on which the operation is done
$op
The Operation being done on the Node could have three values view, update or delete
$account
the user object.
The taxonomy access control stores the access information in taxonomy_access_term
which has the following fields tid - taxonomy term ID, rid - the role ID, grant_view, grant_update, grant_delete, grant_delete, grant_create, grant_list
All the grant columns can have the following values
- 0=>Ignore
- 1=>Allow
- 2=>Deny.
Used the following function to override the hook_node_access
function custom_node_access($node, $op, $account) {
if ($op == 'view')
{
// Get all the tids into the $tids array
$tids = array();
$tids[] = $node->field_class[$node->language][0]['tid'];
$tids[] = $node->field_subject[$node->language][0]['tid'];
// Get all the role ids into the $roles variable
$roles = array_keys($account->roles);
// Create the query to get the `grant_view` with a value 1 if all the
// roles have grant permission then the result would have 2 records.
$query = db_select('taxonomy_access_term' , 't');
$query->condition('t.tid', $tids, 'IN');
$query->condition('t.rid', $roles, 'IN');
$query->condition('t.grant_view', 1);
$query->fields('t', array('grant_view'));
$result = $query->execute();
// if the result is less than two then we deny access other wise we
// ignore it so that let the node_access control take over.
if ($result->rowCount() < 2)
{
return NODE_ACCESS_DENY;
}
}
return NODE_ACCESS_IGNORE;
}
This works well node displays. But the problem would be that since the hook_node_access is bypassed by the list queries this will not work, Might have to add the node_access tag to all the queries which would become a performance issue.
The second method was to use the hook_node_access_records_alter
and hook_node_grants_alter
the hook_node_access_records_alter
edits the grant realms before writing it to the node_access
table when creating or editing a node.
function custom_node_access_records_alter(&$grants, $node) {
// Store the grants to a temp variable
// create a new varible to store the new gid
$gid = "";
// Loop through the grants
foreach ($temp as $key => $grant)
{
if ($grant['grant_view'])
{
// if the grant_view is set to 1 then append the gid
// after adding a padding 0 to the left so that we get
// a 2 digit number
$gid .= str_pad($grant['gid'], 2, "0", STR_PAD_LEFT);
}
}
// After completing this loop the new gid would look something like 040506
// which means the role id 4, 5, and 6 has access to the page. and since we have
// added it together we can make sure that it is individualy not valid
// has to work together.
// Rewrite the grant values with the new gid.
if($gid_view != "")
{
$grants = array();
$grants[0] = array();
$grants[0]['realm'] = 'taxonomy_access_role';
$grants[0]['gid'] = (int)$gid;
$grants[0]['grant_view'] = 1;
$grants[0]['grant_update'] = 0;
$grants[0]['grant_delete'] = 0;
$grants[0]['priority'] = 1;
}
}
The next step would be to override the hook_node_grants_alter
function.
function custom_node_grants_alter(&$grants, $account, $op) {
// we only want it to work with the view.
if($op == 'view')
{
$gid = '';
// loop through the roles of the user
foreach($account->roles as $rid => $role)
{
// we do not want the role id 2 as it is the id of the authenticated user.
if ($rid >2)
{
// generate the gid we created in the hook_node_access_records_alter
// so if the user has all the roles we set to the node then we would
// get the same gid other wise the gid would be different and access
// would be denied
$gid .= str_pad($rid, 2, "0", STR_PAD_LEFT);
}
}
// Over write the grants array.
$grants = array();
$grants['taxonomy_access_role'][0] = (int)$gid;
}
}
Note : There are few assumptions made here
- We only have the taxonomy access control module as access control module other than the core access control system. If there are more then we have to check and make changes to the function accordingly.
- We are only checking for the view grants and not bothered about the rest of the grants.
- Maximum number of roles that a user would have is 5. The gid is of the type int so it can accommodate a maximum value of 10 digit.
- Each role would have only one allow per taxonomy term and rest of it would be deny.