Skip to content

Instantly share code, notes, and snippets.

@damiankloip
Created July 3, 2013 07:46
Show Gist options
  • Save damiankloip/5916161 to your computer and use it in GitHub Desktop.
Save damiankloip/5916161 to your computer and use it in GitHub Desktop.
<?php
/**
* @file
* Contains \Drupal\Core\Entity\EntityIterator.
*/
namespace Drupal\Core\Entity;
/**
* Provides an Iterator class for dealing with large amounts of entities
* but not loading them all into memory.
*/
class EntityIterator implements \Iterator {
/**
* The entity storage controller to load entities.
*
* @var \Drupal\Core\Entity\EntityStorageControllerInterface
*/
protected $entityStorageController;
/**
* An array of entity IDs to iterate over.
*
* @var array
*/
protected $entityIds;
/**
* An array of queued entityIDs. Loaded IDs are removed (until rewind() is called).
*
* @var array
*/
protected $entityIdQueue;
/**
* The Amount of cached entities to store before clearing out the static cache.
*
* @var int
*/
protected $cacheLimit;
/**
* The current array position in $entityIds.
*
* @var int
*/
protected $current;
/**
* Currently loaded entities.
*
* @var array
*/
protected $loadedEntities = array();
/**
* Constructs an entity iterator object.
*
* @param \Drupal\Core\Entity\EntityControllerInterface $entity_controller
* @param array $ids
* @param int $cache_limit
*/
public function __construct(EntityStorageControllerInterface $entity_storage_controller, array $ids, $cache_limit = 10) {
$this->entityStorageController = $entity_storage_controller;
// Make sure we don't use a keyed array.
$this->entityIds = array_values($ids);
$this->cacheLimit = (int) $cache_limit;
$this->rewind();
}
/**
* Gets the total count for all passed entity IDs.
*
* @return int
*/
public function getEntityIdCount() {
return count($this->entityIds);
}
/**
* Implements \Iterator::current()
*/
public function current() {
// Increment the entity cache count.
return $this->getEntity();
}
/**
* Implements \Iterator::key()
*/
public function key() {
return $this->current;
}
/**
* Implements \Iterator::next()
*/
public function next() {
return $this->current++;
}
/**
* Implements \Iterator::rewind()
*/
public function rewind() {
$this->entityStorageController->resetCache();
$this->entityIdQueue = $this->entityIds;
$this->loadedEntities = array();
$this->current = key($this->entityIds);
}
/**
* Implements \Iterator::valid()
*/
public function valid() {
return $this->getEntityId();
}
/**
* Returns the entity ID from the value of the current $entityIds array position.
*
* @return bool
*/
protected function getEntityId() {
if (isset($this->entityIds[$this->current])) {
return $this->entityIds[$this->current];
}
return NULL;
}
/**
* Returns a loaded entity.
*
* @return \Drupal\Core\Entity\EntityInterface.
*/
protected function getEntity() {
$id = $this->getEntityId();
if (isset($this->loadedEntities[$id])) {
return $this->loadedEntities[$id];
}
// If no entity is loaded. Try to load new entities and try again. This
// should only need to happen once to know if there are any more to load.
$this->loadEntities();
if (isset($this->loadedEntities[$id])) {
return $this->loadedEntities[$id];
}
}
/**
* Loads a set of entities. Depends on the cacheLimit.
*/
protected function loadEntities() {
// Reset any previously loaded entities.
$this->entityStorageController->resetCache();
// Take the cacheLimit amount of IDs from the beginning of the array and
// load them. This will keep reducing the queued Ids until they are gone. It
// doesn't make sense to use SqlQueue or anything, as we want multiple at
// once.
$ids = array_splice($this->entityIdQueue, 0, $this->cacheLimit);
$this->loadedEntities = $this->entityStorageController->load($ids);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment