Index: modules/node/node.module =================================================================== RCS file: /cvs/drupal/drupal/modules/node/node.module,v retrieving revision 1.988 diff -u -p -r1.988 node.module --- modules/node/node.module 13 Oct 2008 00:33:03 -0000 1.988 +++ modules/node/node.module 23 Oct 2008 23:18:57 -0000 @@ -726,93 +726,138 @@ function node_invoke_nodeapi(&$node, $op } /** - * Load a node object from the database. + * Load node objects from the database. * - * @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 nids. + * @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 $cache = array(); if ($reset) { - $nodes = array(); + $cache = 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]; - } + $nodes = array(); + + // Load any available nodes from the cache and exclude them from the + // database query. + foreach ($nids as $nid) { + if (isset($cache[$nid])) { + $nodes[$nid] = $cache[$nid]; + unset($nids[$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; + + // Remove nodes from the array if they don't match a condition in $conditions. + if (!empty($conditions)) { + foreach ($nodes as $node) { + foreach ($conditions as $key => $value) { + if ($node->$key != $value) { + unset($nodes[$nid]); + } + } } - $cond = implode(' AND ', $cond); - } - else { - return FALSE; } - // 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_revisions', '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_revisions} 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_revisions} r ON r.vid = n.vid WHERE ' . $cond, $arguments)); - } + // Fetch any nodes not statically cached from the database. + if (!empty($nids) || !empty($conditions)) { + // Fetch any nodes not statically cached from the database. + $query = db_select('node', 'n'); + $query->join('node_revisions', 'r', 'r.vid = n.vid'); + $query->join('users', 'u', 'u.uid = n.uid'); - 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; - } + // Add fields from the {node} table. + $node_fields = drupal_schema_fields_sql('node'); + + // vid and title are provided by node_revisions, so remove them. + unset($node_fields['vid']); + unset($node_fields['title']); + foreach ($node_fields as $field) { + $query->addField('n', $field, $field); + } + + // Add fields from the {node_revisions} table. + $node_revision_fields = drupal_schema_fields_sql('node_revisions'); + + // nid is provided by node, so remove it. + unset($node_revision_fields['nid']); + + foreach ($node_revision_fields as $field) { + $query->addField('r', $field, $field); } - if ($extra = node_invoke_nodeapi($node, 'load')) { - foreach ($extra as $key => $value) { - $node->$key = $value; + // Add fields from the {users} table. + $user_fields = array('name', 'picture', 'data'); + foreach ($user_fields as $field) { + $query->addField('u', $field, $field); + } + + if (!empty($nids)) { + $query->condition('n.nid', $nids, 'IN'); + } + + if (!empty($conditions)) { + foreach ($conditions as $field => $value) { + $query->condition('n.' . $field, $value); } } - if ($cachable) { - $nodes[$node->nid] = is_object($node) ? clone $node : $node; + + $result = $query->execute(); + + foreach ($result AS $node) { + $nodes[$node->nid] = $node; } } - return $node; + // Create an array of nodes for each content type and pass this to the + // node type specific callback. + $typed_nodes = array(); + foreach ($nodes as $nid => $node) { + $typed_nodes[$node->type][$nid] = &$node; + } + + // 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('module', $type) . '_load'; + call_user_func($function, $nodes_of_type); + } + } + + // 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'; + call_user_func($function, &$nodes, array_keys($typed_nodes)); + } + + $cache += $nodes; + return $nodes; +} + +/** + * Load a node object from the database. + * + * @param $nid + * The node id. + * @param $reset + * Whether to reset the internal node_load cache. + * + * @return + * A fully-populated node object. + */ +function node_load($nid, $reset = FALSE) { + $node = node_load_multiple(array($nid), NULL, $reset); + + return $node[$nid]; } /**