summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
authorDries Buytaert <dries@buytaert.net>2008-12-05 22:18:46 +0000
committerDries Buytaert <dries@buytaert.net>2008-12-05 22:18:46 +0000
commit58b0235a72859aa433d743a9f284504f24664857 (patch)
tree524132d2e7ca157baa1059117244a5b27b1f51fb /modules
parent0b06c68b988410c49c9f4ffbf8c3160d4e9da2c7 (diff)
downloadbrdo-58b0235a72859aa433d743a9f284504f24664857.tar.gz
brdo-58b0235a72859aa433d743a9f284504f24664857.tar.bz2
- Patch #324313 by catch et al: load multiple nodes and terms at once.
Diffstat (limited to 'modules')
-rw-r--r--modules/book/book.module19
-rw-r--r--modules/book/book.test2
-rw-r--r--modules/comment/comment.module29
-rw-r--r--modules/dblog/dblog.test2
-rw-r--r--modules/filter/filter.test2
-rw-r--r--modules/forum/forum.module29
-rw-r--r--modules/forum/forum.test2
-rw-r--r--modules/node/node.api.php60
-rw-r--r--modules/node/node.module246
-rw-r--r--modules/node/node.test84
-rw-r--r--modules/path/path.module14
-rw-r--r--modules/path/path.test6
-rw-r--r--modules/poll/poll.module54
-rw-r--r--modules/poll/poll.test2
-rw-r--r--modules/simpletest/drupal_web_test_case.php16
-rw-r--r--modules/simpletest/tests/taxonomy_test.module6
-rw-r--r--modules/system/system.test2
-rw-r--r--modules/taxonomy/taxonomy.api.php17
-rw-r--r--modules/taxonomy/taxonomy.module179
-rw-r--r--modules/taxonomy/taxonomy.test62
-rw-r--r--modules/translation/translation.test4
-rw-r--r--modules/trigger/trigger.test4
-rw-r--r--modules/upload/upload.module9
23 files changed, 648 insertions, 202 deletions
diff --git a/modules/book/book.module b/modules/book/book.module
index fad546bda..a0e0b674f 100644
--- a/modules/book/book.module
+++ b/modules/book/book.module
@@ -705,18 +705,13 @@ function book_build_active_trail($book_link) {
/**
* Implementation of hook_nodeapi_load().
*/
-function book_nodeapi_load(&$node, $teaser, $page) {
- // Note - we cannot use book_link_load() because it will call node_load().
- $info['book'] = db_query('SELECT * FROM {book} b INNER JOIN {menu_links} ml ON b.mlid = ml.mlid WHERE b.nid = :nid', array(
- ':nid' => $node->nid
- ))->fetchAssoc();
-
- if ($info['book']) {
- $info['book']['href'] = $info['book']['link_path'];
- $info['book']['title'] = $info['book']['link_title'];
- $info['book']['options'] = unserialize($info['book']['options']);
-
- return $info;
+function book_nodeapi_load($nodes, $types) {
+ $result = db_query("SELECT * FROM {book} b INNER JOIN {menu_links} ml ON b.mlid = ml.mlid WHERE b.nid IN (" . db_placeholders(array_keys($nodes)) . ")", array_keys($nodes), array('fetch' => PDO::FETCH_ASSOC));
+ foreach ($result as $record) {
+ $nodes[$record['nid']]->book = $record;
+ $nodes[$record['nid']]->book['href'] = $record['link_path'];
+ $nodes[$record['nid']]->book['title'] = $record['link_title'];
+ $nodes[$record['nid']]->book['options'] = unserialize($record['options']);
}
}
diff --git a/modules/book/book.test b/modules/book/book.test
index 5843957fd..df7b2d6fd 100644
--- a/modules/book/book.test
+++ b/modules/book/book.test
@@ -146,7 +146,7 @@ class BookTestCase extends DrupalWebTestCase {
}
// Check to make sure the book node was created.
- $node = node_load(array('title' => $edit['title']));
+ $node = $this->drupalGetNodeByTitle($edit['title']);
$this->assertNotNull(($node === FALSE ? NULL : $node), t('Book node found in database.'));
$number++;
diff --git a/modules/comment/comment.module b/modules/comment/comment.module
index b01940319..759bcc9f3 100644
--- a/modules/comment/comment.module
+++ b/modules/comment/comment.module
@@ -579,11 +579,32 @@ function comment_form_alter(&$form, $form_state, $form_id) {
/**
* Implementation of hook_nodeapi_load().
*/
-function comment_nodeapi_load(&$node, $arg = 0) {
- if ($node->comment != COMMENT_NODE_DISABLED) {
- return db_query('SELECT last_comment_timestamp, last_comment_name, comment_count FROM {node_comment_statistics} WHERE nid = :nid', array(':nid' => $node->nid))->fetchAssoc();
+function comment_nodeapi_load($nodes, $types) {
+ $comments_enabled = array();
+
+ // Check if comments are enabled for each node. If comments are disabled,
+ // assign values without hitting the database.
+ foreach ($nodes as $node) {
+ // Store whether comments are enabled for this node.
+ if ($node->comment != COMMENT_NODE_DISABLED) {
+ $comments_enabled[] = $node->nid;
+ }
+ else {
+ $node->last_comment_timestamp = $node->created;
+ $node->last_comment_name = '';
+ $node->comment_count = 0;
+ }
+ }
+
+ // For nodes with comments enabled, fetch information from the database.
+ if (!empty($comments_enabled)) {
+ $result = db_query('SELECT nid, last_comment_timestamp, last_comment_name, comment_count FROM {node_comment_statistics} WHERE nid IN(' . db_placeholders($comments_enabled) . ')', $comments_enabled);
+ foreach ($result as $record) {
+ $nodes[$record->nid]->last_comment_timestamp = $record->last_comment_timestamp;
+ $nodes[$record->nid]->last_comment_name = $record->last_comment_name;
+ $nodes[$record->nid]->comment_count = $record->comment_count;
+ }
}
- return array('last_comment_timestamp' => $node->created, 'last_comment_name' => '', 'comment_count' => 0);
}
/**
diff --git a/modules/dblog/dblog.test b/modules/dblog/dblog.test
index c95ae6552..5e151c232 100644
--- a/modules/dblog/dblog.test
+++ b/modules/dblog/dblog.test
@@ -262,7 +262,7 @@ class DBLogTestCase extends DrupalWebTestCase {
$this->drupalPost('node/add/' . $type, $edit, t('Save'));
$this->assertResponse(200);
// Retrieve node object.
- $node = node_load(array('title' => $title));
+ $node = $this->drupalGetNodeByTitle($title);
$this->assertTrue($node != null, t('Node @title was loaded', array('@title' => $title)));
// Edit node.
$edit = $this->getContentUpdate($type);
diff --git a/modules/filter/filter.test b/modules/filter/filter.test
index 331af74a6..3015bf91e 100644
--- a/modules/filter/filter.test
+++ b/modules/filter/filter.test
@@ -114,7 +114,7 @@ class FilterAdminTestCase extends DrupalWebTestCase {
$this->drupalPost('node/add/page', $edit, t('Save'));
$this->assertRaw(t('Page %title has been created.', array('%title' => $edit['title'])), t('Filtered node created.'));
- $node = node_load(array('title' => $edit['title']));
+ $node = $this->drupalGetNodeByTitle($edit['title']);
$this->assertTrue($node, t('Node found in database.'));
$this->drupalGet('node/' . $node->nid);
diff --git a/modules/forum/forum.module b/modules/forum/forum.module
index 8473ddde5..ee3b2df98 100644
--- a/modules/forum/forum.module
+++ b/modules/forum/forum.module
@@ -341,11 +341,25 @@ function forum_nodeapi_delete(&$node, $teaser, $page) {
/**
* Implementation of hook_nodeapi_load().
*/
-function forum_nodeapi_load(&$node, $teaser, $page) {
+function forum_nodeapi_load($nodes, $types) {
$vid = variable_get('forum_nav_vocabulary', '');
+ // If no forum vocabulary is set up, return.
+ if ($vid == '') {
+ return;
+ }
$vocabulary = taxonomy_vocabulary_load($vid);
- if (_forum_nodeapi_check_node_type($node, $vocabulary)) {
- return db_fetch_array(db_query('SELECT tid AS forum_tid FROM {forum} WHERE vid = %d', $node->vid));
+
+ $node_vids = array();
+ foreach ($nodes as $node) {
+ if (isset($vocabulary->nodes[$node->type])) {
+ $node_vids[] = $node->vid;
+ }
+ }
+ if (!empty($node_vids)) {
+ $result = db_query('SELECT nid, tid FROM {forum} WHERE vid IN(' . db_placeholders($node_vids) . ')', $node_vids);
+ foreach ($result as $record) {
+ $nodes[$record->nid]->forum_tid = $record->tid;
+ }
}
}
@@ -452,15 +466,6 @@ function forum_form_alter(&$form, $form_state, $form_id) {
}
/**
- * Implementation of hook_load().
- */
-function forum_load($node) {
- $forum = db_fetch_object(db_query('SELECT * FROM {term_node} WHERE vid = %d', $node->vid));
-
- return $forum;
-}
-
-/**
* Implementation of hook_block().
*
* Generates a block containing the currently active forum topics and the
diff --git a/modules/forum/forum.test b/modules/forum/forum.test
index 1ca169c57..01ec526d1 100644
--- a/modules/forum/forum.test
+++ b/modules/forum/forum.test
@@ -236,7 +236,7 @@ class ForumTestCase extends DrupalWebTestCase {
}
// Retrieve node object.
- $node = node_load(array('title' => $title), null, true); // Are these last two parameters necessary?
+ $node = $this->drupalGetNodeByTitle($title);
$this->assertTrue($node != null, t('Node @title was loaded', array('@title' => $title)));
// View forum topic.
diff --git a/modules/node/node.api.php b/modules/node/node.api.php
index 9bf2816ed..6fc5659e9 100644
--- a/modules/node/node.api.php
+++ b/modules/node/node.api.php
@@ -155,6 +155,39 @@ function hook_node_operations() {
}
/**
+ * Act on node objects when loaded.
+ *
+ * This hook allows you to add information to node objects when loaded from
+ * the database. It takes an array of nodes indexed by nid as its first
+ * parameter. For performance reasons, information for all available nodes
+ * should be loaded in a single query where possible.
+ *
+ * The types of all nodes being passed in are also available in the $types
+ * parameter. If your module keeps track of the node types it supports, this
+ * allows for an early return if nothing needs to be done.
+ *
+ * Due to the internal cache in node_load_multiple(), you should not use this
+ * hook to modify information returned from the {node} table itself, since
+ * this may affect the way nodes are returned from the cache in subsequent
+ * calls to the function.
+ *
+ * @see comment_nodeapi_load()
+ * @see taxonomy_nodeapi_load()
+ * @see forum_nodeapi_load()
+ *
+ * @param $nodes
+ * An array of node objects indexed by nid.
+ * @param $types
+ * An array containing the types of the nodes.
+ */
+function hook_nodeapi_load($nodes, $types) {
+ $result = db_query('SELECT nid, foo FROM {mytable} WHERE nid IN(' . db_placeholders(array_keys($nodes)) . ')', array_keys($nodes));
+ foreach ($result as $record) {
+ $nodes[$record->nid]->foo = $record->foo;
+ }
+}
+
+/**
* Act on nodes defined by other modules.
*
* Despite what its name might make you think, hook_nodeapi() is not
@@ -521,25 +554,22 @@ function hook_insert($node) {
* Load node-type-specific information.
*
* This is a hook used by node modules. It is called to allow the module
- * a chance to load extra information that it stores about a node, or
- * possibly replace already loaded information - which can be dangerous.
+ * a chance to load extra information that it stores about a node. The hook
+ * should not be used to replace information from the core {node} table since
+ * this may interfere with the way nodes are fetched from cache.
*
- * @param $node
- * The node being loaded. At call time, node.module has already loaded
- * the basic information about the node, such as its node ID (nid),
- * title, and body.
- * @return
- * An object containing properties of the node being loaded. This will
- * be merged with the passed-in $node to result in an object containing
- * a set of properties resulting from adding the extra properties to
- * the passed-in ones, and overwriting the passed-in ones with the
- * extra properties if they have the same name as passed-in properties.
+ * @param $nodes
+ * An array of the nodes being loaded, keyed by nid. At call time,
+ * node.module has already loaded the basic information about the nodes, such
+ * as node ID (nid), title, and body.
*
* For a detailed usage example, see node_example.module.
*/
-function hook_load($node) {
- $additions = db_fetch_object(db_query('SELECT * FROM {mytable} WHERE vid = %d', $node->vid));
- return $additions;
+function hook_load($nodes) {
+ $result = db_fetch_object(db_query('SELECT nid, foo FROM {mytable} WHERE nid IN (' . db_placeholders(array_keys($nodes)) . ')', array_keys($nodes)));
+ foreach ($result as $record) {
+ $nodes[$record->nid]->foo = $record->foo;
+ }
}
/**
diff --git a/modules/node/node.module b/modules/node/node.module
index 8fb6f456b..634da3987 100644
--- a/modules/node/node.module
+++ b/modules/node/node.module
@@ -730,93 +730,177 @@ function node_invoke_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
}
/**
- * Load a node object from the database.
+ * Load node objects from the database.
+ *
+ * This function should be used whenever you need to load more than one node
+ * from the database. Nodes are loaded into memory and will not require
+ * database access if loaded again during the same page request.
*
- * @param $param
- * Either the nid of the node or an array of conditions to match against in the database query
- * @param $revision
- * Which numbered revision to load. Defaults to the current version.
+ * @param $nids
+ * An array of node IDs.
+ * @param $conditions
+ * An array of conditions on the {node} table in the form 'field' => $value.
* @param $reset
* Whether to reset the internal node_load cache.
*
* @return
- * A fully-populated node object.
+ * An array of node objects indexed by nid.
*/
-function node_load($param = array(), $revision = NULL, $reset = NULL) {
- static $nodes = array();
-
+function node_load_multiple($nids = array(), $conditions = array(), $reset = FALSE) {
+ static $node_cache = array();
if ($reset) {
- $nodes = array();
- }
-
- $cachable = ($revision == NULL);
- $arguments = array();
- if (is_numeric($param)) {
- if ($cachable) {
- // Is the node statically cached?
- if (isset($nodes[$param])) {
- return is_object($nodes[$param]) ? clone $nodes[$param] : $nodes[$param];
+ $node_cache = array();
+ }
+ $nodes = array();
+
+ // Create a new variable which is either a prepared version of the $nids
+ // array for later comparison with the node cache, or FALSE if no $nids were
+ // passed. The $nids array is reduced as items are loaded from cache, and we
+ // need to know if it's empty for this reason to avoid querying the database
+ // when all requested nodes are loaded from cache.
+ $passed_nids = !empty($nids) ? array_flip($nids) : FALSE;
+
+ // Revisions are not statically cached, and require a different query to
+ // other conditions, so separate vid into its own variable.
+ $vid = isset($conditions['vid']) ? $conditions['vid'] : FALSE;
+ unset($conditions['vid']);
+
+ // Load any available nodes from the internal cache.
+ if ($node_cache && !$vid) {
+ if ($nids) {
+ $nodes += array_intersect_key($node_cache, $passed_nids);
+ // If any nodes were loaded, remove them from the $nids still to load.
+ $nids = array_keys(array_diff_key($passed_nids, $nodes));
+ }
+ // If loading nodes only by conditions, fetch all available nodes from
+ // the cache. Nodes which don't match are removed later.
+ elseif ($conditions) {
+ $nodes = $node_cache;
+ }
+ }
+
+ // Exclude any nodes loaded from cache if they don't match $conditions.
+ // This ensures the same behaviour whether loading from memory or database.
+ if ($conditions) {
+ foreach ($nodes as $node) {
+ $node_values = (array) $node;
+ if (array_diff_assoc($conditions, $node_values)) {
+ unset($nodes[$node->nid]);
}
}
- $cond = 'n.nid = %d';
- $arguments[] = $param;
}
- elseif (is_array($param)) {
- // Turn the conditions into a query.
- foreach ($param as $key => $value) {
- $cond[] = 'n.' . db_escape_table($key) . " = '%s'";
- $arguments[] = $value;
+
+ // Load any remaining nodes from the database. This is the case if there are
+ // any $nids left to load, if loading a revision, or if $conditions was
+ // passed without $nids.
+ if ($nids || $vid || ($conditions && !$passed_nids)) {
+ $query = db_select('node', 'n');
+
+ if ($vid) {
+ $query->join('node_revision', 'r', 'r.nid = n.nid AND r.vid = :vid', array(':vid' => $vid));
}
- $cond = implode(' AND ', $cond);
- }
- else {
- return FALSE;
- }
+ else {
+ $query->join('node_revision', 'r', 'r.vid = n.vid');
+ }
+ $query->join('users', 'u', 'u.uid = n.uid');
- // Retrieve a field list based on the site's schema.
- $fields = drupal_schema_fields_sql('node', 'n');
- $fields = array_merge($fields, drupal_schema_fields_sql('node_revision', 'r'));
- $fields = array_merge($fields, array('u.name', 'u.picture', 'u.data'));
- // Remove fields not needed in the query: n.vid and r.nid are redundant,
- // n.title is unnecessary because the node title comes from the
- // node_revisions table. We'll keep r.vid, r.title, and n.nid.
- $fields = array_diff($fields, array('n.vid', 'n.title', 'r.nid'));
- $fields = implode(', ', $fields);
- // Rename timestamp field for clarity.
- $fields = str_replace('r.timestamp', 'r.timestamp AS revision_timestamp', $fields);
- // Change name of revision uid so it doesn't conflict with n.uid.
- $fields = str_replace('r.uid', 'r.uid AS revision_uid', $fields);
-
- // Retrieve the node.
- // No db_rewrite_sql is applied so as to get complete indexing for search.
- if ($revision) {
- array_unshift($arguments, $revision);
- $node = db_fetch_object(db_query('SELECT ' . $fields . ' FROM {node} n INNER JOIN {users} u ON u.uid = n.uid INNER JOIN {node_revision} r ON r.nid = n.nid AND r.vid = %d WHERE ' . $cond, $arguments));
- }
- else {
- $node = db_fetch_object(db_query('SELECT ' . $fields . ' FROM {node} n INNER JOIN {users} u ON u.uid = n.uid INNER JOIN {node_revision} r ON r.vid = n.vid WHERE ' . $cond, $arguments));
- }
+ // Add fields from the {node} table.
+ $node_fields = drupal_schema_fields_sql('node');
+
+ // vid and title are provided by node_revision, so remove them.
+ unset($node_fields['vid']);
+ unset($node_fields['title']);
+ $query->fields('n', $node_fields);
+
+ // Add all fields from the {node_revision} table.
+ $node_revision_fields = drupal_schema_fields_sql('node_revision');
+
+ // nid is provided by node, so remove it.
+ unset($node_revision_fields['nid']);
- if ($node && $node->nid) {
- // Call the node specific callback (if any) and piggy-back the
- // results to the node or overwrite some values.
- if ($extra = node_invoke($node, 'load')) {
- foreach ($extra as $key => $value) {
- $node->$key = $value;
+ // Change timestamp to revision_timestamp before adding it to the query.
+ unset($node_revision_fields['timestamp']);
+ $query->addField('r', 'timestamp', 'revision_timestamp');
+ $query->fields('r', $node_revision_fields);
+
+ // Add fields from the {users} table.
+ $user_fields = array('name', 'picture', 'data');
+ $query->fields('u', $user_fields);
+
+ if ($nids) {
+ $query->condition('n.nid', $nids, 'IN');
+ }
+ if ($conditions) {
+ foreach ($conditions as $field => $value) {
+ $query->condition('n.' . $field, $value);
}
}
+ $queried_nodes = $query->execute()->fetchAllAssoc('nid');
+ }
+
+ // Pass all nodes loaded from the database through the node type specific
+ // callbacks and hook_nodeapi_load(), then add them to the internal cache.
+ if (!empty($queried_nodes)) {
+ // Create an array of nodes for each content type and pass this to the
+ // node type specific callback.
+ $typed_nodes = array();
+ foreach ($queried_nodes as $nid => $node) {
+ $typed_nodes[$node->type][$nid] = $node;
+ }
- if ($extra = node_invoke_nodeapi($node, 'load')) {
- foreach ($extra as $key => $value) {
- $node->$key = $value;
+ // Call node type specific callbacks on each typed array of nodes.
+ foreach ($typed_nodes as $type => $nodes_of_type) {
+ if (node_hook($type, 'load')) {
+ $function = node_get_types('base', $type) . '_load';
+ $function($nodes_of_type);
}
}
- if ($cachable) {
- $nodes[$node->nid] = is_object($node) ? clone $node : $node;
+
+ // Call hook_nodeapi_load(), pass the node types so modules can return early
+ // if not acting on types in the array.
+ foreach (module_implements('nodeapi_load') as $module) {
+ $function = $module . '_nodeapi_load';
+ $function($queried_nodes, array_keys($typed_nodes));
+ }
+ $nodes += $queried_nodes;
+ // Add nodes to the cache if we're not loading a revision.
+ if (!$vid) {
+ $node_cache += $queried_nodes;
}
}
- return $node;
+ // Ensure that the returned array is ordered the same as the original $nids
+ // array if this was passed in and remove any invalid nids.
+ if ($passed_nids) {
+ // Remove any invalid nids from the array.
+ $passed_nids = array_intersect_key($passed_nids, $nodes);
+ foreach ($nodes as $node) {
+ $passed_nids[$node->nid] = $node;
+ }
+ $nodes = $passed_nids;
+ }
+
+ return $nodes;
+}
+
+/**
+ * Load a node object from the database.
+ *
+ * @param $nid
+ * The node ID.
+ * @param $vid
+ * The revision ID.
+ * @param $reset
+ * Whether to reset the internal node_load cache.
+ *
+ * @return
+ * A fully-populated node object.
+ */
+function node_load($nid, $vid = array(), $reset = FALSE) {
+ $vid = isset($vid) ? array('vid' => $vid) : NULL;
+ $node = node_load_multiple(array($nid), $vid, $reset);
+
+ return $node ? $node[$nid] : FALSE;
}
/**
@@ -1740,22 +1824,18 @@ function node_feed($nids = FALSE, $channel = array()) {
global $base_url, $language;
if ($nids === FALSE) {
- $nids = array();
- $result = db_query_range(db_rewrite_sql('SELECT n.nid, n.created FROM {node} n WHERE n.promote = 1 AND n.status = 1 ORDER BY n.created DESC'), 0, variable_get('feed_default_items', 10));
- while ($row = db_fetch_object($result)) {
- $nids[] = $row->nid;
- }
+ $nids = db_query_range(db_rewrite_sql('SELECT n.nid, n.created FROM {node} n WHERE n.promote = 1 AND n.status = 1 ORDER BY n.created DESC'), 0, variable_get('feed_default_items', 10))->fetchCol();
}
$item_length = variable_get('feed_item_length', 'teaser');
$namespaces = array('xmlns:dc' => 'http://purl.org/dc/elements/1.1/');
+ // Load all nodes to be rendered.
+ $nodes = node_load_multiple($nids);
$items = '';
- foreach ($nids as $nid) {
- // Load the specified node:
- $item = node_load($nid);
+ foreach ($nodes as $item) {
$item->build_mode = NODE_BUILD_RSS;
- $item->link = url("node/$nid", array('absolute' => TRUE));
+ $item->link = url("node/$item->nid", array('absolute' => TRUE));
if ($item_length != 'title') {
$teaser = ($item_length == 'teaser');
@@ -1822,16 +1902,14 @@ function node_feed($nids = FALSE, $channel = array()) {
* Menu callback; Generate a listing of promoted nodes.
*/
function node_page_default() {
- $result = pager_query(db_rewrite_sql('SELECT n.nid, n.sticky, n.created FROM {node} n WHERE n.promote = 1 AND n.status = 1 ORDER BY n.sticky DESC, n.created DESC'), variable_get('default_nodes_main', 10));
-
- $output = '';
- $num_rows = FALSE;
- while ($node = db_fetch_object($result)) {
- $output .= node_view(node_load($node->nid), 1);
- $num_rows = TRUE;
- }
+ $nids = pager_query(db_rewrite_sql('SELECT n.nid FROM {node} n WHERE n.promote = 1 AND n.status = 1 ORDER BY n.sticky DESC, n.created DESC'), variable_get('default_nodes_main', 10))->fetchCol();
+ if (!empty($nids)) {
+ $nodes = node_load_multiple($nids);
+ $output = '';
+ foreach ($nodes as $node) {
+ $output .= node_view($node, TRUE);
+ }
- if ($num_rows) {
$feed_url = url('rss.xml', array('absolute' => TRUE));
drupal_add_feed($feed_url, variable_get('site_name', 'Drupal') . ' ' . t('RSS'));
$output .= theme('pager', NULL, variable_get('default_nodes_main', 10));
diff --git a/modules/node/node.test b/modules/node/node.test
index f45225922..7f5e5c303 100644
--- a/modules/node/node.test
+++ b/modules/node/node.test
@@ -1,6 +1,86 @@
<?php
// $Id$
+/**
+ * Test the node_load_multiple() function.
+ */
+class NodeLoadMultipleUnitTest extends DrupalWebTestCase {
+
+ function getInfo() {
+ return array(
+ 'name' => t('Load multiple nodes'),
+ 'description' => t('Test the loading of multiple nodes.'),
+ 'group' => t('Node'),
+ );
+ }
+
+ function setUp() {
+ parent::setUp();
+ $web_user = $this->drupalCreateUser(array('create article content', 'create page content'));
+ $this->drupalLogin($web_user);
+ }
+
+ /**
+ * Create four nodes and ensure they're loaded correctly.
+ */
+ function testNodeMultipleLoad() {
+ $node1 = $this->drupalCreateNode(array('type' => 'article', 'promote' => 1));
+ $node2 = $this->drupalCreateNode(array('type' => 'article', 'promote' => 1));
+ $node3 = $this->drupalCreateNode(array('type' => 'article', 'promote' => 0));
+ $node4 = $this->drupalCreateNode(array('type' => 'page', 'promote' => 0));
+
+ // Confirm that promoted nodes appear in the default node listing.
+ $this->drupalGet('node');
+ $this->assertText($node1->title, t('Node title appears on the default listing.'));
+ $this->assertText($node2->title, t('Node title appears on the default listing.'));
+ $this->assertNoText($node3->title, t('Node title does not appear in the default listing.'));
+ $this->assertNoText($node4->title, t('Node title does not appear in the default listing.'));
+
+ // Load nodes with only a condition. Nodes 3 and 4 will be loaded.
+ $nodes = node_load_multiple(NULL, array('promote' => 0));
+ $this->assertEqual($node3->title, $nodes[$node3->nid]->title, t('Node was loaded.'));
+ $this->assertEqual($node4->title, $nodes[$node4->nid]->title, t('Node was loaded.'));
+ $count = count($nodes);
+ $this->assertTrue($count == 2, t('@count nodes loaded.', array('@count' => $count)));
+
+ // Load nodes by nid. Nodes 1, 2 and 4 will be loaded.
+ $nodes = node_load_multiple(array(1, 2, 4));
+ $count = count($nodes);
+ $this->assertTrue(count($nodes) == 3, t('@count nodes loaded', array('@count' => $count)));
+ $this->assertTrue(isset($nodes[$node1->nid]), t('Node is correctly keyed in the array'));
+ $this->assertTrue(isset($nodes[$node2->nid]), t('Node is correctly keyed in the array'));
+ $this->assertTrue(isset($nodes[$node4->nid]), t('Node is correctly keyed in the array'));
+ foreach ($nodes as $node) {
+ $this->assertTrue(is_object($node), t('Node is an object'));
+ }
+
+ // Load nodes by nid, where type = article. Nodes 1, 2 and 3 will be loaded.
+ $nodes = node_load_multiple(array(1, 2, 3, 4), array('type' => 'article'));
+ $count = count($nodes);
+ $this->assertTrue($count == 3, t('@count nodes loaded', array('@count' => $count)));
+ $this->assertEqual($nodes[$node1->nid]->title, $node1->title, t('Node successfully loaded.'));
+ $this->assertEqual($nodes[$node2->nid]->title, $node2->title, t('Node successfully loaded.'));
+ $this->assertEqual($nodes[$node3->nid]->title, $node3->title, t('Node successfully loaded.'));
+ $this->assertFalse(isset($nodes[$node4->nid]));
+
+ // Now that all nodes have been loaded into the static cache, ensure that
+ // they are loaded correctly again when a condition is passed.
+ $nodes = node_load_multiple(array(1, 2, 3, 4), array('type' => 'article'));
+ $count = count($nodes);
+ $this->assertTrue($count == 3, t('@count nodes loaded.', array('@count' => $count)));
+ $this->assertEqual($nodes[$node1->nid]->title, $node1->title, t('Node successfully loaded'));
+ $this->assertEqual($nodes[$node2->nid]->title, $node2->title, t('Node successfully loaded'));
+ $this->assertEqual($nodes[$node3->nid]->title, $node3->title, t('Node successfully loaded'));
+ $this->assertFalse(isset($nodes[$node4->nid]), t('Node was not loaded'));
+
+ // Load nodes by nid, where type = article and promote = 0.
+ $nodes = node_load_multiple(array(1, 2, 3, 4), array('type' => 'article', 'promote' => 0));
+ $count = count($nodes);
+ $this->assertTrue($count == 1, t('@count node loaded', array('@count' => $count)));
+ $this->assertEqual($nodes[$node3->nid]->title, $node3->title, t('Node successfully loaded.'));
+ }
+}
+
class NodeRevisionsTestCase extends DrupalWebTestCase {
protected $nodes;
protected $logs;
@@ -258,7 +338,7 @@ class PageEditTestCase extends DrupalWebTestCase {
$this->drupalPost('node/add/page', $edit, t('Save'));
// Check that the node exists in the database.
- $node = node_load(array('title' => $edit['title']));
+ $node = $this->drupalGetNodeByTitle($edit['title']);
$this->assertTrue($node, t('Node found in database.'));
// Check that "edit" link points to correct page.
@@ -352,7 +432,7 @@ class PageCreationTestCase extends DrupalWebTestCase {
$this->assertRaw(t('!post %title has been created.', array('!post' => 'Page', '%title' => $edit['title'])), t('Page created.'));
// Check that the node exists in the database.
- $node = node_load(array('title' => $edit['title']));
+ $node = $this->drupalGetNodeByTitle($edit['title']);
$this->assertTrue($node, t('Node found in database.'));
}
}
diff --git a/modules/path/path.module b/modules/path/path.module
index bdc4b2ee5..449b72aba 100644
--- a/modules/path/path.module
+++ b/modules/path/path.module
@@ -135,12 +135,14 @@ function path_nodeapi_validate(&$node, $arg) {
/**
* Implementation of hook_nodeapi_load().
*/
-function path_nodeapi_load(&$node, $arg) {
- $language = isset($node->language) ? $node->language : '';
- $path = 'node/' . $node->nid;
- $alias = drupal_get_path_alias($path, $language);
- if ($path != $alias) {
- $node->path = $alias;
+function path_nodeapi_load($nodes, $types) {
+ foreach ($nodes as $node) {
+ $language = isset($node->language) ? $node->language : '';
+ $path = 'node/' . $node->nid;
+ $alias = drupal_get_path_alias($path, $language);
+ if ($path != $alias) {
+ $node->path = $alias;
+ }
}
}
diff --git a/modules/path/path.test b/modules/path/path.test
index 40023996d..6479abc03 100644
--- a/modules/path/path.test
+++ b/modules/path/path.test
@@ -131,7 +131,7 @@ class PathTestCase extends DrupalWebTestCase {
$this->drupalPost('node/add/page', $edit, t('Save'));
// Check to make sure the node was created.
- $node = node_load(array('title' => $edit['title']));
+ $node = $this->drupalGetNodeByTitle($edit['title']);
$this->assertNotNull(($node === FALSE ? NULL : $node), 'Node found in database. %s');
@@ -188,7 +188,7 @@ class PathLanguageTestCase extends DrupalWebTestCase {
$this->drupalPost('node/add/page', $edit, t('Save'));
// Check to make sure the node was created.
- $english_node = node_load(array('title' => $edit['title']));
+ $english_node = $this->drupalGetNodeByTitle($edit['title']);
$this->assertTrue(($english_node), 'Node found in database.');
// Confirm that the alias works.
@@ -209,7 +209,7 @@ class PathLanguageTestCase extends DrupalWebTestCase {
// Ensure the node was created.
// Check to make sure the node was created.
- $french_node = node_load(array('title' => $edit['title']));
+ $french_node = $this->drupalGetNodeByTitle($edit['title']);
$this->assertTrue(($french_node), 'Node found in database.');
// Confirm that the alias works.
diff --git a/modules/poll/poll.module b/modules/poll/poll.module
index 2cbd8edcd..52afd0973 100644
--- a/modules/poll/poll.module
+++ b/modules/poll/poll.module
@@ -148,11 +148,9 @@ function poll_block($op = 'list', $delta = '') {
}
elseif ($op == 'view') {
// Retrieve the latest poll.
- $sql = db_rewrite_sql("SELECT MAX(n.created) FROM {node} n INNER JOIN {poll} p ON p.nid = n.nid WHERE n.status = 1 AND p.active = 1");
- $timestamp = db_result(db_query($sql));
- if ($timestamp) {
- $poll = node_load(array('type' => 'poll', 'created' => $timestamp, 'status' => 1));
-
+ $record = db_query_range(db_rewrite_sql("SELECT n.nid FROM {node} n INNER JOIN {poll} p ON p.nid = n.nid WHERE n.status = :status AND p.active = :active ORDER BY n.created DESC"), array(':status' => 1, ':active' => 1), 0, 1)->fetch();
+ if ($record) {
+ $poll = node_load($record->nid);
if ($poll->nid) {
$poll = poll_view($poll, TRUE, FALSE, TRUE);
}
@@ -451,35 +449,35 @@ function poll_validate($node) {
/**
* Implementation of hook_load().
*/
-function poll_load($node) {
+function poll_load($nodes) {
global $user;
+ foreach ($nodes as $node) {
+ $poll = db_query("SELECT runtime, active FROM {poll} WHERE nid = :nid", array(':nid' => $node->nid))->fetch();
- $poll = db_fetch_object(db_query("SELECT runtime, active FROM {poll} WHERE nid = %d", $node->nid));
-
- // Load the appropriate choices into the $poll object.
- $result = db_query("SELECT chid, chtext, chvotes, weight FROM {poll_choice} WHERE nid = %d ORDER BY weight", $node->nid);
- while ($choice = db_fetch_array($result)) {
- $poll->choice[$choice['chid']] = $choice;
- }
+ // Load the appropriate choices into the $poll object.
+ $poll->choice = db_query("SELECT chid, chtext, chvotes, weight FROM {poll_choice} WHERE nid = :nid ORDER BY weight", array(':nid' => $node->nid))->fetchAllAssoc('chid', PDO::FETCH_ASSOC);
- // Determine whether or not this user is allowed to vote.
- $poll->allowvotes = FALSE;
- if (user_access('vote on polls') && $poll->active) {
- if ($user->uid) {
- $result = db_fetch_object(db_query('SELECT chid FROM {poll_vote} WHERE nid = %d AND uid = %d', $node->nid, $user->uid));
- }
- else {
- $result = db_fetch_object(db_query("SELECT chid FROM {poll_vote} WHERE nid = %d AND hostname = '%s'", $node->nid, ip_address()));
- }
- if (isset($result->chid)) {
- $poll->vote = $result->chid;
+ // Determine whether or not this user is allowed to vote.
+ $poll->allowvotes = FALSE;
+ if (user_access('vote on polls') && $poll->active) {
+ if ($user->uid) {
+ $result = db_query('SELECT chid FROM {poll_vote} WHERE nid = :nid AND uid = :uid', array(':nid' => $node->nid, ':uid' => $user->uid))->fetch();
+ }
+ else {
+ $result = db_query("SELECT chid FROM {poll_vote} WHERE nid = :nid AND hostname = :hostname", array(':nid' => $node->nid, ':hostname' => ip_address()))->fetch();
+ }
+ if ($result) {
+ $poll->vote = $result->chid;
+ }
+ else {
+ $poll->vote = -1;
+ $poll->allowvotes = TRUE;
+ }
}
- else {
- $poll->vote = -1;
- $poll->allowvotes = TRUE;
+ foreach ($poll as $key => $value) {
+ $nodes[$node->nid]->$key = $value;
}
}
- return $poll;
}
/**
diff --git a/modules/poll/poll.test b/modules/poll/poll.test
index e91f689c7..83ac61778 100644
--- a/modules/poll/poll.test
+++ b/modules/poll/poll.test
@@ -40,7 +40,7 @@ class PollTestCase extends DrupalWebTestCase {
}
$this->drupalPost(NULL, $edit, t('Save'));
- $node = node_load(array('title' => $title));
+ $node = $this->drupalGetNodeByTitle($title);
$this->assertRaw(t('@type %title has been created.', array('@type' => node_get_types('name', 'poll'), '%title' => $title)), 'Poll has been created.');
$this->assertTrue($node->nid, t('Poll has been found in the database'));
diff --git a/modules/simpletest/drupal_web_test_case.php b/modules/simpletest/drupal_web_test_case.php
index 8fecb9ea0..9660d4483 100644
--- a/modules/simpletest/drupal_web_test_case.php
+++ b/modules/simpletest/drupal_web_test_case.php
@@ -447,6 +447,22 @@ class DrupalWebTestCase {
}
/**
+ * Get a node from the database based on its title.
+ *
+ * @param title
+ * A node title, usually generated by $this->randomName().
+ *
+ * @return
+ * A node object matching $title.
+ */
+ function drupalGetNodeByTitle($title) {
+ $nodes = node_load_multiple(array(), array('title' => $title));
+ // Load the first node returned from the database.
+ $returned_node = reset($nodes);
+ return $returned_node;
+ }
+
+ /**
* Creates a node based on default settings.
*
* @param $settings
diff --git a/modules/simpletest/tests/taxonomy_test.module b/modules/simpletest/tests/taxonomy_test.module
index 2bbcf2453..d90148fa2 100644
--- a/modules/simpletest/tests/taxonomy_test.module
+++ b/modules/simpletest/tests/taxonomy_test.module
@@ -9,8 +9,10 @@
/**
* Implementation of hook_taxonomy_term_load().
*/
-function taxonomy_test_taxonomy_term_load($term) {
- $term->antonyms = taxonomy_test_get_antonyms($term->tid);
+function taxonomy_test_taxonomy_term_load(&$terms) {
+ foreach ($terms as $term) {
+ $term->antonyms = taxonomy_test_get_antonyms($term->tid);
+ }
}
/**
diff --git a/modules/system/system.test b/modules/system/system.test
index a88cef457..7e039428b 100644
--- a/modules/system/system.test
+++ b/modules/system/system.test
@@ -570,7 +570,7 @@ class PageTitleFiltering extends DrupalWebTestCase {
// Create the node with HTML in the title.
$this->drupalPost('node/add/page', $edit, t('Save'));
- $node = node_load(array('title' => $edit['title']));
+ $node = $this->drupalGetNodeByTitle($edit['title']);
$this->assertNotNull($node, 'Node created and found in database');
$this->drupalGet("node/" . $node->nid);
$this->assertText(check_plain($edit['title']), 'Check to make sure tags in the node title are converted.');
diff --git a/modules/taxonomy/taxonomy.api.php b/modules/taxonomy/taxonomy.api.php
index 553386000..fd6d2bcd7 100644
--- a/modules/taxonomy/taxonomy.api.php
+++ b/modules/taxonomy/taxonomy.api.php
@@ -74,12 +74,21 @@ function hook_taxonomy_vocabulary_delete($vocabulary) {
*
* Modules implementing this hook can act on the term object returned by
* taxonomy_term_load().
+ * For performance reasons, information to be added to term objects should be
+ * loaded in a single query for all terms where possible.
*
- * @param $term
- * A taxonomy term object.
+ * Since terms are stored and retrieved from cache during a page request, avoid
+ * altering properties provided by the {term_data} table, since this may
+ * affect the way results are loaded from cache in subsequent calls.
+ *
+ * @param $terms
+ * An array of term objects, indexed by tid.
*/
-function hook_taxonomy_term_load($term) {
- $term->synonyms = taxonomy_get_synonyms($term->tid);
+function hook_taxonomy_term_load($terms) {
+ $result = db_query('SELECT tid, foo FROM {mytable} WHERE tid IN (' . db_placeholders(array_keys($terms)) . ')', array_keys($terms));
+ foreach ($result as $record) {
+ $terms[$record->tid]->foo = $record->foo;
+ }
}
/**
diff --git a/modules/taxonomy/taxonomy.module b/modules/taxonomy/taxonomy.module
index 958f83773..eaddef26d 100644
--- a/modules/taxonomy/taxonomy.module
+++ b/modules/taxonomy/taxonomy.module
@@ -623,6 +623,33 @@ function taxonomy_node_get_terms_by_vocabulary($node, $vid, $key = 'tid') {
}
/**
+ * Find all term IDs associated with a set of nodes.
+ *
+ * @param $nodes
+ * An array of node objects.
+ *
+ * @return
+ * An array of term and node IDs ordered by vocabulary and term weight.
+ */
+function taxonomy_get_tids_from_nodes($nodes) {
+ $node_vids = array();
+ foreach ($nodes as $node) {
+ $node_vids[] = $node->vid;
+ }
+ $query = db_select('term_node', 'r');
+ $query->fields('r', array('tid', 'nid', 'vid'));
+ $query->join('term_data', 't', 'r.tid = t.tid');
+ $query->join('vocabulary', 'v', 't.vid = v.vid');
+ $query->condition('r.vid', $node_vids, 'IN');
+ $query->orderBy('v.weight');
+ $query->orderBy('t.weight');
+ $query->orderBy('t.name');
+ $query->addTag('term_access');
+
+ return $query->execute()->fetchAll();
+}
+
+/**
* Find all terms associated with the given node, ordered by vocabulary and term weight.
*/
function taxonomy_node_get_terms($node, $key = 'tid') {
@@ -1050,24 +1077,124 @@ function taxonomy_terms_load($str_tids) {
}
/**
+ * Load multiple taxonomy terms based on certain conditions.
+ *
+ * This function should be used whenever you need to load more than one term
+ * from the database. Terms are loaded into memory and will not require
+ * database access if loaded again during the same page request.
+ *
+ * @param $tids
+ * An array of taxonomy term IDs.
+ * @param $conditions
+ * An array of conditions to add to the query.
+ * @param $reset
+ * Whether to reset the internal cache.
+ *
+ * @return
+ * An array of term objects, indexed by tid.
+ */
+function taxonomy_term_load_multiple($tids = array(), $conditions = array(), $reset = FALSE) {
+ static $term_cache = array();
+
+ if ($reset) {
+ $term_cache = array();
+ }
+
+ $terms = array();
+
+ // Create a new variable which is either a prepared version of the $tids
+ // array for later comparison with the term cache, or FALSE if no $tids were
+ // passed. The $tids array is reduced as items are loaded from cache, and we
+ // need to know if it's empty for this reason to avoid querying the database
+ // when all requested terms are loaded from cache.
+ $passed_tids = !empty($tids) ? array_flip($tids) : FALSE;
+
+ // Load any available terms from the internal cache.
+ if ($term_cache) {
+ if ($tids) {
+ $terms += array_intersect_key($term_cache, $passed_tids);
+ // If any terms were loaded, remove them from the $tids still to load.
+ $tids = array_keys(array_diff_key($passed_tids, $terms));
+ }
+ // If only conditions is passed, load all terms from the cache. Terms
+ // which don't match conditions will be removed later.
+ elseif ($conditions) {
+ $terms = $term_cache;
+ }
+ }
+
+ // Remove any loaded terms from the array if they don't match $conditions.
+ if ($conditions) {
+ foreach ($terms as $term) {
+ $term_values = (array) $term;
+ if (array_diff_assoc($conditions, $term_values)) {
+ unset($terms[$term->tid]);
+ }
+ }
+ }
+
+ // Load any remaining terms from the database, this is necessary if we have
+ // $tids still to load, or if $conditions was passed without $tids.
+ if ($tids || ($conditions && !$passed_tids)) {
+ $query = db_select('term_data', 't');
+ $term_data = drupal_schema_fields_sql('term_data');
+ $query->fields('t', $term_data);
+
+ // If the $tids array is populated, add those to the query.
+ if ($tids) {
+ $query->condition('t.tid', $tids, 'IN');
+ }
+
+ // If the conditions array is populated, add those to the query.
+ if ($conditions) {
+ foreach ($conditions as $field => $value) {
+ $query->conditions('t.' . $field, $value);
+ }
+ }
+ $queried_terms = $query->execute()->fetchAllAssoc('tid');
+ // Invoke hook_taxonomy_term_load() on the terms loaded from the database
+ // and add them to the static cache.
+ if (!empty($queried_terms)) {
+ foreach (module_implements('taxonomy_term_load') as $module) {
+ $function = $module . '_taxonomy_term_load';
+ $function($queried_terms);
+ }
+ $terms += $queried_terms;
+ $term_cache += $queried_terms;
+ }
+ }
+
+ // Ensure that the returned array is ordered the same as the original $tids
+ // array if this was passed in and remove any invalid tids.
+ if ($passed_tids) {
+ // Remove any invalid tids from the array.
+ $passed_tids = array_intersect_key($passed_tids, $terms);
+ foreach ($terms as $term) {
+ $passed_tids[$term->tid] = $term;
+ }
+ $terms = $passed_tids;
+ }
+
+ return $terms;
+}
+
+/**
* Return the term object matching a term ID.
*
* @param $tid
* A term's ID
+ * @param $reset
+ * Whether to reset the static cache.
*
- * @return Object
+ * @return
* A term object. Results are statically cached.
*/
function taxonomy_term_load($tid, $reset = FALSE) {
if (!is_numeric($tid)) {
return FALSE;
}
- static $terms = array();
- if (!isset($terms[$tid]) || $reset) {
- $terms[$tid] = taxonomy_get_term_data($tid, $reset);
- module_invoke_all('taxonomy_term_load', $terms[$tid]);
- }
- return $terms[$tid];
+ $term = taxonomy_term_load_multiple(array($tid), array(), $reset);
+ return $term ? $term[$tid] : FALSE;
}
/**
@@ -1193,12 +1320,16 @@ function taxonomy_select_nodes($tids = array(), $operator = 'or', $depth = 0, $p
*/
function taxonomy_render_nodes($result) {
$output = '';
- $has_rows = FALSE;
- while ($node = db_fetch_object($result)) {
- $output .= node_view(node_load($node->nid), 1);
- $has_rows = TRUE;
+ $nids = array();
+ foreach ($result as $record) {
+ $nids[] = $record->nid;
}
- if ($has_rows) {
+ if (!empty($nids)) {
+ $nodes = node_load_multiple($nids);
+
+ foreach ($nodes as $node) {
+ $output .= node_view($node, 1);
+ }
$output .= theme('pager', NULL, variable_get('default_nodes_main', 10), 0);
}
else {
@@ -1210,9 +1341,27 @@ function taxonomy_render_nodes($result) {
/**
* Implementation of hook_nodeapi_load().
*/
-function taxonomy_nodeapi_load($node, $arg = 0) {
- $output['taxonomy'] = taxonomy_node_get_terms($node);
- return $output;
+function taxonomy_nodeapi_load($nodes) {
+ // Get an array of tid, vid associations ordered by vocabulary and term
+ // weight.
+ $tids = taxonomy_get_tids_from_nodes($nodes);
+
+ // Extract the tids only from this array.
+ $term_ids = array();
+ foreach ($tids as $term) {
+ $term_ids[$term->tid] = $term->tid;
+ }
+
+ // Load the full term objects for these tids.
+ $terms = taxonomy_term_load_multiple($term_ids);
+ foreach ($tids as $term) {
+ $nodes[$term->nid]->taxonomy[$term->tid] = $terms[$term->tid];
+ }
+ foreach ($nodes as $node) {
+ if (!isset($nodes[$node->nid]->taxonomy)) {
+ $node->taxonomy = array();
+ }
+ }
}
/**
diff --git a/modules/taxonomy/taxonomy.test b/modules/taxonomy/taxonomy.test
index bc85bbe68..9f36b680e 100644
--- a/modules/taxonomy/taxonomy.test
+++ b/modules/taxonomy/taxonomy.test
@@ -344,7 +344,7 @@ class TaxonomyTermTestCase extends TaxonomyWebTestCase {
$this->drupalPost('node/add/article', $edit, t('Save'));
// Check that the term is displayed when the node is viewed.
- $node = node_load(array('title' => $edit['title']));
+ $node = $this->drupalGetNodeByTitle($edit['title']);
$this->drupalGet('node/' . $node->nid);
$this->assertText($term1->name, t('Term is displayed when viewing the node.'));
@@ -433,3 +433,63 @@ class TaxonomyTermTestCase extends TaxonomyWebTestCase {
$this->assertText($edit['description'], t('The randomly generated term description is present.'));
}
}
+
+/**
+ * Test the taxonomy_term_load_multiple() function.
+ */
+class TaxonomyLoadMultipleUnitTest extends TaxonomyWebTestCase {
+
+ function getInfo() {
+ return array(
+ 'name' => t('Taxonomy term multiple loading'),
+ 'description' => t('Test the loading of multiple taxonomy terms at once'),
+ 'group' => t('Taxonomy'),
+ );
+ }
+
+ function setUp() {
+ parent::setUp();
+ $this->taxonomy_admin = $this->drupalCreateUser(array('administer taxonomy'));
+ $this->drupalLogin($this->taxonomy_admin);
+ }
+
+ /**
+ * Create a vocabulary and some taxonomy terms, ensuring they're loaded
+ * correctly using taxonomy_term_load_multiple().
+ */
+ function testTaxonomyTermMultipleLoad() {
+ // Create a vocabulary.
+ $vocabulary = $this->createVocabulary();
+
+ // Create five terms in the vocabulary.
+ $i = 0;
+ while ($i < 5) {
+ $i++;
+ $this->createTerm($vocabulary->vid);
+ }
+ // Load the terms from the vocabulary.
+ $terms = taxonomy_term_load_multiple(NULL, array('vid' => $vocabulary->vid));
+ $count = count($terms);
+ $this->assertTrue($count == 5, t('Correct number of terms were loaded. !count terms.', array('!count' => $count)));
+
+ // Load the same terms again by tid.
+ $terms2 = taxonomy_term_load_multiple(array_keys($terms));
+ $this->assertTrue($count == count($terms2), t('Five terms were loaded by tid'));
+ $this->assertEqual($terms, $terms2, t('Both arrays contain the same terms'));
+
+ // Load the terms by tid, with a condition on vid.
+ $terms3 = taxonomy_term_load_multiple(array_keys($terms2), array('vid' => $vocabulary->vid));
+ $this->assertEqual($terms2, $terms3);
+
+ // Remove one term from the array, then delete it.
+ $deleted = array_shift($terms3);
+ taxonomy_term_delete($deleted->tid);
+ $deleted_term = taxonomy_term_load($deleted->tid, TRUE);
+ $this->assertFalse($deleted_term);
+
+ // Load terms from the vocabulary by vid.
+ $terms4 = taxonomy_term_load_multiple(NULL, array('vid' => $vocabulary->vid), TRUE);
+ $this->assertTrue(count($terms4 == 4), t('Correct number of terms were loaded.'));
+ $this->assertFalse(isset($terms4[$deleted->tid]));
+ }
+}
diff --git a/modules/translation/translation.test b/modules/translation/translation.test
index e7a97790a..d8dd43b31 100644
--- a/modules/translation/translation.test
+++ b/modules/translation/translation.test
@@ -117,7 +117,7 @@ class TranslationTestCase extends DrupalWebTestCase {
$this->assertRaw(t('Page %title has been created.', array('%title' => $edit['title'])), t('Page created.'));
// Check to make sure the node was created.
- $node = node_load(array('title' => $edit['title']));
+ $node = $this->drupalGetNodeByTitle($edit['title']);
$this->assertTrue($node, t('Node found in database.'));
return $node;
@@ -141,7 +141,7 @@ class TranslationTestCase extends DrupalWebTestCase {
$this->assertRaw(t('Page %title has been created.', array('%title' => $edit['title'])), t('Translation created.'));
// Check to make sure that translation was successfull.
- $node = node_load(array('title' => $edit['title']));
+ $node = $this->drupalGetNodeByTitle($edit['title']);
$this->assertTrue($node, t('Node found in database.'));
return $node;
diff --git a/modules/trigger/trigger.test b/modules/trigger/trigger.test
index fab53e5f4..e11429306 100644
--- a/modules/trigger/trigger.test
+++ b/modules/trigger/trigger.test
@@ -44,7 +44,7 @@ class TriggerContentTestCase extends DrupalWebTestCase {
// Make sure the text we want appears.
$this->assertRaw(t('!post %title has been created.', array ('!post' => 'Page', '%title' => $edit['title'])), t('Make sure the page has actually been created'));
// Action should have been fired.
- $loaded_node = node_load(array('title' => $edit['title']), NULL, TRUE);
+ $loaded_node = $this->drupalGetNodeByTitle($edit['title']);;
$this->assertTrue($loaded_node->$info['property'] == $info['expected'], t('Make sure the @action action fired.', array('@action' => $info['name'])));
// Leave action assigned for next test
@@ -108,4 +108,4 @@ class TriggerContentTestCase extends DrupalWebTestCase {
);
return $info[$action];
}
-} \ No newline at end of file
+}
diff --git a/modules/upload/upload.module b/modules/upload/upload.module
index c4eacc2bd..fce0b2aff 100644
--- a/modules/upload/upload.module
+++ b/modules/upload/upload.module
@@ -300,10 +300,11 @@ function upload_file_delete(&$file) {
/**
* Implementation of hook_nodeapi_load().
*/
-function upload_nodeapi_load(&$node, $teaser) {
- if (variable_get("upload_$node->type", 1) == 1) {
- $output = array('files' => upload_load($node));
- return $output;
+function upload_nodeapi_load($nodes, $types) {
+ foreach ($nodes as $node) {
+ if (variable_get("upload_$node->type", 1) == 1) {
+ $node->files = upload_load($node);
+ }
}
}