diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php b/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php index b472b8f..bdfeb37 100644 --- a/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php +++ b/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php @@ -19,6 +19,13 @@ class ConfigStorageController implements EntityStorageControllerInterface { /** + * Static cache of entities. + * + * @var array + */ + protected $entityCache; + + /** * Entity type for this controller instance. * * @var string @@ -58,6 +65,15 @@ class ConfigStorageController implements EntityStorageControllerInterface { protected $uuidKey = 'uuid'; /** + * Whether this entity type should use the static cache. + * + * Set by entity info. + * + * @var boolean + */ + protected $cache; + + /** * Implements Drupal\Core\Entity\EntityStorageControllerInterface::__construct(). * * Sets basic variables. @@ -65,16 +81,26 @@ class ConfigStorageController implements EntityStorageControllerInterface { public function __construct($entityType) { $this->entityType = $entityType; $this->entityInfo = entity_get_info($entityType); + $this->entityCache = array(); $this->hookLoadArguments = array(); $this->idKey = $this->entityInfo['entity_keys']['id']; + + // Check if the entity type supports static caching of loaded entities. + $this->cache = !empty($this->entityInfo['static_cache']); } /** * Implements Drupal\Core\Entity\EntityStorageControllerInterface::resetCache(). */ public function resetCache(array $ids = NULL) { - // The configuration system is fast enough and/or implements its own - // (advanced) caching mechanism already. + if (isset($ids)) { + foreach ($ids as $id) { + unset($this->entityCache[$id]); + } + } + else { + $this->entityCache = array(); + } } /** @@ -85,8 +111,19 @@ public function load(array $ids = NULL) { // 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. + // 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 consulting the + // storage when all requested entities are loaded from cache. $passed_ids = !empty($ids) ? array_flip($ids) : FALSE; + // Try to load entities from the static cache, if the entity type supports + // static caching. + if ($this->cache && $ids) { + $entities += $this->cacheGet($ids); + // If any entities were loaded, remove them from the ids still to load. + if ($passed_ids) { + $ids = array_keys(array_diff_key($passed_ids, $entities)); + } + } // Load any remaining entities. This is the case if $ids is set to NULL (so // we load all entities). @@ -102,13 +139,20 @@ public function load(array $ids = NULL) { $entities += $queried_entities; } + if ($this->cache) { + // Add entities to the cache. + if (!empty($queried_entities)) { + $this->cacheSet($queried_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; + $passed_ids[$entity->id()] = $entity; } $entities = $passed_ids; } @@ -159,7 +203,7 @@ public function getConfigPrefix() { * See Drupal\comment\CommentStorageController::buildQuery() or * Drupal\taxonomy\TermStorageController::buildQuery() for examples. * - * @param $ids + * @param array|null $ids * An array of entity IDs, or NULL to load all entities. * @param $revision_id * The ID of the revision to load, or FALSE if this query is asking for the @@ -228,6 +272,34 @@ protected function attachLoad(&$queried_entities, $revision_id = FALSE) { } /** + * Gets entities from the static cache. + * + * @param $ids + * If not empty, return entities that match these IDs. + * + * @return + * Array of entities from the entity cache. + */ + protected function cacheGet($ids) { + $entities = array(); + // Load any available entities from the internal cache. + if (!empty($this->entityCache)) { + $entities += array_intersect_key($this->entityCache, array_flip($ids)); + } + return $entities; + } + + /** + * Stores entities in the static entity cache. + * + * @param $entities + * Entities to store in the cache. + */ + protected function cacheSet($entities) { + $this->entityCache += $entities; + } + + /** * Implements Drupal\Core\Entity\EntityStorageControllerInterface::create(). */ public function create(array $values) { @@ -271,6 +343,9 @@ public function delete(array $entities) { ->save(); } + // Reset the cache as soon as the changes have been applied. + $this->resetCache($ids); + $this->postDelete($entities); foreach ($entities as $id => $entity) { $this->invokeHook('delete', $entity); @@ -325,6 +400,7 @@ public function save(EntityInterface $entity) { if (!$is_new) { $return = SAVED_UPDATED; $config->save(); + $this->resetCache(array($entity->id())); $this->postSave($entity, TRUE); $this->invokeHook('update', $entity); @@ -334,6 +410,8 @@ public function save(EntityInterface $entity) { else { $return = SAVED_NEW; $config->save(); + $this->resetCache(array()); + $entity->enforceIsNew(FALSE); $this->postSave($entity, FALSE); $this->invokeHook('insert', $entity);