Skip to content

Instantly share code, notes, and snippets.

@damiankloip
Last active September 29, 2015 15:23
Show Gist options
  • Save damiankloip/68ee7fd2412125d17e90 to your computer and use it in GitHub Desktop.
Save damiankloip/68ee7fd2412125d17e90 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, \Countable {
/**
* The entity storage controller to load entities.
*
* @var \Drupal\Core\Entity\EntityStorageInterface
*/
protected $entityStorage;
/**
* An array of entity IDs to iterate over.
*
* @var array
*/
protected $entityIds;
/**
* An array of queued entityIDs, IDs are removed until rewind() is called.
*
* @var array
*/
protected $entityIdQueue;
/**
* The Amount of cached entities to store before clearing the static cache.
*
* @var int
*/
protected $cacheLimit;
/**
* The current array position in $entityIds.
*
* @var int
*/
protected $current;
/**
* Currently loaded entities.
*
* @var array
*/
protected $loadedEntities = [];
/**
* A falg indicating when all queued IDs have been claimed.
*
* @var bool
*/
protected $allClaimed = FALSE;
/**
* Constructs an entity iterator object.
*
* @param \Drupal\Core\Entity\EntityStorageInterface $entity_controller
* @param array $ids
* @param int $cache_limit
*/
public function __construct(EntityStorageInterface $entity_storage_controller, array $ids, $cache_limit = 50) {
$this->entityStorage = $entity_storage_controller;
// Make sure we don't use a keyed array.
$this->entityIds = array_values($ids);
$this->cacheLimit = (int) $cache_limit;
$this->rewind();
}
/**
* Implements \Countable::count().
*/
public function count() {
return count($this->entityIds);
}
/**
* Implements \Iterator::current()
*/
public function current() {
return $this->getEntity();
}
/**
* Implements \Iterator::key()
*/
public function key() {
return $this->getEntityId();
}
/**
* Implements \Iterator::next()
*/
public function next() {
return $this->current++;
}
/**
* Implements \Iterator::rewind()
*/
public function rewind() {
$this->entityStorage->resetCache();
$this->entityIdQueue = $this->entityIds;
$this->loadedEntities = [];
$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])) {
// Remove the loaded entity before returning.
$entity = $this->loadedEntities[$id];
unset($this->loadedEntities[$id]);
return $entity;
}
if (empty($this->loadedEntities) && !$this->allClaimed) {
$this->loadEntities();
if (isset($this->loadedEntities[$id])) {
// Remove the loaded entity before returning.
$entity = $this->loadedEntities[$id];
unset($this->loadedEntities[$id]);
return $entity;
}
}
return NULL;
}
/**
* Loads a set of entities.
*
* This depends on the cacheLimit property.
*/
protected function loadEntities() {
// Reset any previously loaded entities.
$this->entityStorage->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);
// If all queued IDs have been taken, set a flag.
if (empty($this->entityIdQueue)) {
$this->allClaimed = TRUE;
}
$this->loadedEntities = $this->entityStorage->loadMultiple($ids);
return count($this->loadedEntities);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment