summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDries Buytaert <dries@buytaert.net>2009-01-04 19:56:51 +0000
committerDries Buytaert <dries@buytaert.net>2009-01-04 19:56:51 +0000
commit634379299f7ab35bf64504718a77d00767fa2dfa (patch)
tree4ed784c5e43ea9de8818dd7ac38f0648a76b2b4d
parent7e60d94f69d896e1f063cc52a4ba1778f91a77fc (diff)
downloadbrdo-634379299f7ab35bf64504718a77d00767fa2dfa.tar.gz
brdo-634379299f7ab35bf64504718a77d00767fa2dfa.tar.bz2
- Patch #320591 by Moshe, Crell et al: tag specific alter hook for database queries.
-rw-r--r--includes/database/select.inc6
-rw-r--r--modules/node/node.module12
-rw-r--r--modules/simpletest/tests/database_test.module14
-rw-r--r--modules/simpletest/tests/database_test.test2
-rw-r--r--modules/system/system.api.php62
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