diff options
-rw-r--r-- | includes/database/select.inc | 6 | ||||
-rw-r--r-- | modules/node/node.module | 12 | ||||
-rw-r--r-- | modules/simpletest/tests/database_test.module | 14 | ||||
-rw-r--r-- | modules/simpletest/tests/database_test.test | 2 | ||||
-rw-r--r-- | modules/system/system.api.php | 62 |
5 files changed, 87 insertions, 9 deletions
diff --git a/includes/database/select.inc b/includes/database/select.inc index a8e763146..532b2e5a1 100644 --- a/includes/database/select.inc +++ b/includes/database/select.inc @@ -291,7 +291,13 @@ class SelectQuery extends Query implements QueryConditionInterface, QueryAlterab } public function execute() { + // Modules may alter all queries or only those having a particular tag. drupal_alter('query', $this); + if (isset($this->alterTags)) { + foreach ($this->alterTags as $tag => $value) { + drupal_alter("query_$tag", $this); + } + } $args = $this->getArguments(); diff --git a/modules/node/node.module b/modules/node/node.module index f2e616f6a..deca20ea3 100644 --- a/modules/node/node.module +++ b/modules/node/node.module @@ -2324,17 +2324,23 @@ function node_db_rewrite_sql($query, $primary_table, $primary_field) { } /** - * Implementation of hook_query_alter(). + * Implementation of hook_query_TAG_alter(). */ -function node_query_alter(QueryAlterableInterface $query) { - if ($query->hasTag('node_access') && !node_access_view_all_nodes()) { +function node_query_node_access_alter(QueryAlterableInterface $query) { + // Skip the extra expensive alterations if site has no node access control modules. + if (!node_access_view_all_nodes()) { + // Prevent duplicate records. $query->distinct(); + // The recognized operations are 'view', 'update', 'delete'. if (!$op = $query->getMetaData('op')) { $op = 'view'; } + // Skip the extra joins and conditions for node admins. if (!user_access('bypass node access')) { + // The node_access table has the access grants for any given node. $access_alias = $query->join('node_access', 'na', 'na.nid = n.nid'); $or = db_or(); + // If any grant exists for the specified user, then user has access to the node for the specified operation. foreach (node_access_grants($op, $query->getMetaData('account')) as $realm => $gids) { foreach ($gids as $gid) { $or->condition(db_and() diff --git a/modules/simpletest/tests/database_test.module b/modules/simpletest/tests/database_test.module index 555f976b3..25631e0c7 100644 --- a/modules/simpletest/tests/database_test.module +++ b/modules/simpletest/tests/database_test.module @@ -4,16 +4,12 @@ /** * Implementation of hook_query_alter(). */ -function database_test_query_alter(SelectQuery $query) { +function database_test_query_alter(QueryAlterableInterface $query) { if ($query->hasTag('database_test_alter_add_range')) { $query->range(0, 2); } - if ($query->hasTag('database_test_alter_remove_range')) { - $query->range(); - } - if ($query->hasTag('database_test_alter_add_join')) { $people_alias = $query->join('test', 'people', "test_task.pid=people.id"); $name_field = $query->addField('people', 'name', 'name'); @@ -36,6 +32,14 @@ function database_test_query_alter(SelectQuery $query) { } } + +/** + * Implementation of hook_query_TAG_alter(). Called by DatabaseTestCase::testAlterRemoveRange. + */ +function database_test_query_database_test_alter_remove_range_alter(QueryAlterableInterface $query) { + $query->range(); +} + /** * Implementation of hook_menu(). */ diff --git a/modules/simpletest/tests/database_test.test b/modules/simpletest/tests/database_test.test index 37c6fac5f..9cbec229a 100644 --- a/modules/simpletest/tests/database_test.test +++ b/modules/simpletest/tests/database_test.test @@ -1695,7 +1695,7 @@ class DatabaseAlter2TestCase extends DatabaseTestCase { } /** - * Test that we can remove a range() value from a query. + * Test that we can remove a range() value from a query. This also tests hook_query_TAG_alter(). */ function testAlterRemoveRange() { $query = db_select('test'); diff --git a/modules/system/system.api.php b/modules/system/system.api.php index 3ac517fd4..e6d3b3038 100644 --- a/modules/system/system.api.php +++ b/modules/system/system.api.php @@ -1375,6 +1375,68 @@ function hook_schema_alter(&$schema) { } /** + * Perform alterations to a structured query. + * + * Structured (aka dynamic) queries that have tags associated may be altered by any module + * before the query is executed. + * + * @see hook_query_TAG_alter() + * @see node_query_node_access_alter() + * + * @param $query + * A Query object describing the composite parts of a SQL query. + * @return + * None. + */ +function hook_query_alter(QueryAlterableInterface $query) { + +} + +/** + * Perform alterations to a structured query for a given tag. + * + * @see hook_query_alter() + * @see node_query_node_access_alter() + * + * @param $query + * An Query object describing the composite parts of a SQL query. + * @return + * None. + */ +function hook_query_TAG_alter(QueryAlterableInterface $query) { + // Skip the extra expensive alterations if site has no node access control modules. + if (!node_access_view_all_nodes()) { + // Prevent duplicates records. + $query->distinct(); + // The recognized operations are 'view', 'update', 'delete'. + if (!$op = $query->getMetaData('op')) { + $op = 'view'; + } + // Skip the extra joins and conditions for node admins. + if (!user_access('bypass node access')) { + // The node_access table has the access grants for any given node. + $access_alias = $query->join('node_access', 'na', 'na.nid = n.nid'); + $or = db_or(); + // If any grant exists for the specified user, then user has access to the node for the specified operation. + foreach (node_access_grants($op, $query->getMetaData('account')) as $realm => $gids) { + foreach ($gids as $gid) { + $or->condition(db_and() + ->condition("{$access_alias}.gid", $gid) + ->condition("{$access_alias}.realm", $realm) + ); + } + } + + if (count($or->conditions())) { + $query->condition($or); + } + + $query->condition("{$access_alias}.grant_$op", 1, '>='); + } + } +} + +/** * Install the current version of the database schema, and any other setup tasks. * * The hook will be called the first time a module is installed, and the |