Index: modules/entitycache/entitycache.info =================================================================== RCS file: modules/entitycache/entitycache.info diff -N modules/entitycache/entitycache.info --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/entitycache/entitycache.info 27 Oct 2009 17:09:49 -0000 @@ -0,0 +1,8 @@ +; $Id: entitycache.info,v 1.1 2009/09/24 13:10:20 catch Exp $ +name = Entity cache +description = Provides caching for core entities including nodes and taxonomy terms. + +core = 7.x + +files[] = entitycache.module +files[] = entitycache.install Index: modules/entitycache/entitycache.install =================================================================== RCS file: modules/entitycache/entitycache.install diff -N modules/entitycache/entitycache.install --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/entitycache/entitycache.install 27 Oct 2009 17:09:49 -0000 @@ -0,0 +1,17 @@ +ids = $ids; + $this->conditions = $conditions; + + $entities = array(); + $cached_entities = array(); + $queried_entities = array(); + + // Revisions are not statically cached, and require a different query to + // other conditions, so separate the revision id into its own variable. + if ($this->revisionKey && isset($this->conditions[$this->revisionKey])) { + $this->revisionId = $this->conditions[$this->revisionKey]; + unset($this->conditions[$this->revisionKey]); + } + else { + $this->revisionId = FALSE; + } + + // Create a new variable which is either a prepared version of the $ids + // array for later comparison with the entity cache, or FALSE if no $ids + // were passed. The $ids 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 entities are loaded from cache. + $passed_ids = !empty($this->ids) ? array_flip($this->ids) : FALSE; + // Try to load entities from the static cache, if the entity type supports + // static caching. + if ($this->cache) { + $entities = $this->cacheGet($this->ids, $this->conditions); + // If any entities were loaded, remove them from the ids still to load. + if ($passed_ids) { + $this->ids = array_keys(array_diff_key($passed_ids, $entities)); + } + + // Attempt to load any remaining entities from the persistent cache. + if ($this->ids && !$this->conditions) { + $cached = cache_get_multiple($this->ids, 'cache_entity_' . $this->entityType); + foreach ($cached as $item) { + $cached_entities[$item->cid] = $item->data; + } + if ($cached) { + $this->ids = array_diff($this->ids, array_keys($cached_entities)); + } + } + } + + // Load any remaining entities from the database. This is the case if $ids + // is set to FALSE (so we load all entities), if there are any ids left to + // load, if loading a revision, or if $conditions was passed without $ids. + if ($this->ids === FALSE || $this->ids || $this->revisionId || ($this->conditions && !$passed_ids)) { + // Build the query. + $this->buildQuery(); + $queried_entities = $this->query + ->execute() + ->fetchAllAssoc($this->idKey); + } + + // Pass all entities loaded from the database through $this->attachLoad(), + // which attaches fields (if supported by the entity type) and calls the + // entity type specific load callback, for example hook_node_load(). + if (!empty($queried_entities)) { + $this->attachLoad($queried_entities); + $entities += $queried_entities; + } + + if ($this->cache && !empty($queried_entities)) { + // Add entities to the cache if we are not loading a revision. + if (!$this->revisionId) { + foreach ($queried_entities as $item) { + cache_set($item->{$this->idKey}, $item, 'cache_entity_' . $this->entityType); + } + } + } + $new_entities = $queried_entities + $cached_entities; + + if (!empty($new_entities)) { + $this->attachAfterLoad($new_entities); + if (!$this->revisionId) { + $this->cacheSet($new_entities); + } + $entities += $cached_entities; + } + // Ensure that the returned array is ordered the same as the original + // $ids array if this was passed in and remove any invalid ids. + if ($passed_ids) { + // Remove any invalid ids from the array. + $passed_ids = array_intersect_key($passed_ids, $entities); + foreach ($entities as $entity) { + $passed_ids[$entity->{$this->idKey}] = $entity; + } + $entities = $passed_ids; + } + return $entities; + } + + /** + * Allow modules to implement uncached entity hooks. + * + * Adds an additional hook_entitycache_$type_load() for modules which need + * to add data to objects during the request which can't be cached. + * @see entitycache_entitycache_node_load(). + */ + protected function attachAfterLoad($new_entities) { + foreach (module_implements('entitycache_' . $this->entityType . '_load', $new_entities) as $module) { + $function = $module . '_entitycache_' . $this->entityType . '_load'; + call_user_func_array($function, $new_entities); + } + } +} + +/** + * Helper function to list all supported core entities. + * + * @return + * An array of core entities. + */ +function entitycache_supported_entities() { + return array('node', 'comment', 'taxonomy_term'); +} + +/** + * Implement hook_entitycache_node_load(). + */ +function entitycache_entitycache_node_load($nodes) { + // Both book and poll modules need to add data for the duration of the request + // only. We can't suppress their hooks being called then cached, so simply + // call them again ourselves which will overwrite the cached values with the + // correct ones. + // module_invoke() and module_exists() both break simpletest, so use + // function_exists() to avoid failures. + if (function_exists('book_node_load')) { + book_node_load($nodes, array()); + } + if (function_exists('poll_load')) { + poll_load($nodes); + } +} + +/** + * Helper function for clearing the node cache. + */ +function entitycache_node_helper($node) { + cache_clear_all($node->nid, 'cache_entity_node'); +} + +/** + * Implement hook_node_delete(). + */ +function entitycache_node_delete($node) { + entitycache_node_helper($node); +} + +/** + * Implement hook_node_update(). + */ +function entitycache_node_update($node) { + entitycache_node_helper($node); +} + +/** + * Implement hook_user_delete(). + */ +function entitycache_user_delete($account) { + cache_clear_all($account->uid, 'cache_entity_user'); +} + +/** + * Implement hook_user_update(). + */ +function entitycache_user_update(&$edit, $account) { + cache_clear_all($account->uid, 'cache_entity_user'); +} + +/** + * Implement hook_taxonomy_term_delete(). + */ +function entitycache_taxonomy_term_delete($term) { + cache_clear_all($term->tid, 'cache_entity_taxonomy_term'); +} + +/** + * Implement of hook_taxonomy_term_update(). + */ +function entitycache_taxonomy_term_update($term) { + cache_clear_all($term->tid, 'cache_entity_taxonomy_term'); +} + +/** + * Helper function to for comment hooks. + */ +function entitycache_comment_helper($comment) { + cache_clear_all($comment->cid, 'cache_entity_comment'); + cache_clear_all($comment->nid, 'cache_entity_node'); +} + + +/** + * Implement hook_comment_delete(). + */ +function entitycache_comment_delete($comment) { + entitycache_comment_helper($comment); +} + +/** + * Implement hook_comment_insert(). + */ +function hook_comment_insert($comment) { + entitycache_comment_helper($comment); +} + +/** + * Implement hook_comment_update(). + */ +function entitycache_comment_update($comment) { + entitycache_comment_helper($comment); +} + +/** + * Implement hook_comment_publish(). + */ +function entitycache_comment_publish($comment) { + entitycache_comment_helper($comment); +} + +/** + * Implement hook_comment_unpublish(). + */ +function entitycache_comment_unpublish($comment) { + entitycache_comment_helper($comment); +} Index: profiles/default/default.info =================================================================== RCS file: /cvs/drupal/drupal/profiles/default/default.info,v retrieving revision 1.7 diff -u -p -r1.7 default.info --- profiles/default/default.info 19 Oct 2009 18:28:16 -0000 1.7 +++ profiles/default/default.info 27 Oct 2009 17:09:49 -0000 @@ -19,4 +19,5 @@ dependencies[] = toolbar dependencies[] = field_ui dependencies[] = file dependencies[] = rdf +dependencies[] = entitycache files[] = default.profile