function domain_alter_node_query in Domain Access 7.2
Same name and namespace in other branches
- 7.3 domain.module \domain_alter_node_query()
Abstraction to allow query alters outside of node access.
This entire function is stolen from node.module. We should fix this in core.
@link http://drupal.org/node/1363062
Parameters
$query: A dynamic node query.
$type: Either 'node' or 'entity' depending on what sort of query it is. See node_query_node_access_alter() and node_query_entity_field_access_alter() for more. Currently, we only support 'node'.
1 call to domain_alter_node_query()
- domain_query_node_access_alter in ./
domain.module - Implements hook_query_TAG_alter().
File
- ./
domain.module, line 2952 - Core module functions for the Domain Access suite.
Code
function domain_alter_node_query(QueryAlterableInterface $query, $type) {
global $user;
// Read meta-data from query, if provided.
if (!($account = $query
->getMetaData('account'))) {
$account = $user;
}
if (!($op = $query
->getMetaData('op'))) {
$op = 'view';
}
// Only act on view.
if ($op != 'view') {
return;
}
$tables = $query
->getTables();
$base_table = $query
->getMetaData('base_table');
// If no base table is specified explicitly, search for one.
if (!$base_table) {
$fallback = '';
foreach ($tables as $alias => $table_info) {
if (!$table_info instanceof SelectQueryInterface) {
$table = $table_info['table'];
// If the node table is in the query, it wins immediately.
if ($table == 'node') {
$base_table = $table;
break;
}
// Check whether the table has a foreign key to node.nid. If it does,
// do not run this check again as we found a base table and only node
// can triumph that.
if (!$base_table) {
// The schema is cached.
$schema = drupal_get_schema($table);
if (isset($schema['fields']['nid'])) {
if (isset($schema['foreign keys'])) {
foreach ($schema['foreign keys'] as $relation) {
if ($relation['table'] === 'node' && $relation['columns'] === array(
'nid' => 'nid',
)) {
$base_table = $table;
}
}
}
else {
// At least it's a nid. A table with a field called nid is very
// very likely to be a node.nid in a node access query.
$fallback = $table;
}
}
}
}
}
// If there is nothing else, use the fallback.
if (!$base_table) {
if ($fallback) {
watchdog('security', 'Your node listing query is using @fallback as a base table in a query tagged for node access. This might not be secure and might not even work. Specify foreign keys in your schema to node.nid ', array(
'@fallback' => $fallback,
), WATCHDOG_WARNING);
$base_table = $fallback;
}
else {
throw new Exception(t('Query tagged for node access but there is no nid. Add foreign keys to node.nid in schema to fix.'));
}
}
}
// Prevent duplicate records.
$query
->distinct();
// Find all instances of the base table being joined -- could appear
// more than once in the query, and could be aliased. Join each one to
// the node_access table.
$grants = node_access_grants($op, $account);
if ($type == 'entity') {
// The original query looked something like:
// @code
// SELECT nid FROM sometable s
// INNER JOIN node_access na ON na.nid = s.nid
// WHERE ($node_access_conditions)
// @endcode
//
// Our query will look like:
// @code
// SELECT entity_type, entity_id
// FROM field_data_something s
// LEFT JOIN node_access na ON s.entity_id = na.nid
// WHERE (entity_type = 'node' AND $node_access_conditions) OR (entity_type <> 'node')
// @endcode
//
// So instead of directly adding to the query object, we need to collect
// in a separate db_and() object and then at the end add it to the query.
$entity_conditions = db_and();
}
foreach ($tables as $nalias => $tableinfo) {
$table = $tableinfo['table'];
if (!$table instanceof SelectQueryInterface && $table == $base_table) {
// The node_access table has the access grants for any given node so JOIN
// it to the table containing the nid which can be either the node
// table or a field value table.
if ($type == 'node') {
$access_alias = $query
->join('node_access', 'na', '%alias.nid = ' . $nalias . '.nid');
}
else {
$access_alias = $query
->leftJoin('node_access', 'na', '%alias.nid = ' . $nalias . '.entity_id');
$base_alias = $nalias;
}
$grant_conditions = db_or();
// If any grant exists for the specified user, then user has access
// to the node for the specified operation.
foreach ($grants as $realm => $gids) {
foreach ($gids as $gid) {
$grant_conditions
->condition(db_and()
->condition($access_alias . '.gid', $gid)
->condition($access_alias . '.realm', $realm));
}
}
$count = count($grant_conditions
->conditions());
if ($type == 'node') {
if ($count) {
$query
->condition($grant_conditions);
}
$query
->condition($access_alias . '.grant_' . $op, 1, '>=');
}
else {
if ($count) {
$entity_conditions
->condition($grant_conditions);
}
$entity_conditions
->condition($access_alias . '.grant_' . $op, 1, '>=');
}
}
}
if ($type == 'entity' && count($entity_conditions
->conditions())) {
// All the node access conditions are only for field values belonging to
// nodes.
$entity_conditions
->condition("{$base_alias}.entity_type", 'node');
$or = db_or();
$or
->condition($entity_conditions);
// If the field value belongs to a non-node entity type then this function
// does not do anything with it.
$or
->condition("{$base_alias}.entity_type", 'node', '<>');
// Add the compiled set of rules to the query.
$query
->condition($or);
}
}