class EntityDependencyIterator in Entity Dependency API 7
Iterator class which does the heavy lifting for detecting dependencies.
This iterator is reponsible for taking in an array of entity types and ids, figuring out all their dependencies, and returning an iterable object of all of them in a sane order (dependencies first). And since dependencies in theory are nested and recursive, we are using a recursive iterator here.
@todo We need to throw an exception when we detect a circular dependency.
Hierarchy
- class \EntityDependencyIterator implements \RecursiveIterator
Expanded class hierarchy of EntityDependencyIterator
1 string reference to 'EntityDependencyIterator'
- entity_dependency_entity_dependency_iterator in ./
entity_dependency.module - Implements hook_entity_dependency_iterator().
File
- ./
EntityDependencyIterator.inc, line 24 - Entity Dependency classes.
View source
class EntityDependencyIterator implements RecursiveIterator {
/**
* The entities to be iterated over.
*
* @var array
*/
public $entities = array();
/**
* The entity type of the entity currently being iterated over.
*
* @var string
*/
public $entityType = NULL;
/**
* The entity ID of the entity currently being iterated over.
*
* @var string
*/
public $entityId = NULL;
/**
* An array of dependencies to the entity being parsed.
*
* @var array
*/
public $dependencies = array();
/**
* An array of belongings to the entity being parsed.
*
* @var array
*/
public $belongings = array();
/**
* An array with information on the cause/reason why an entity exists in the
* tree. Basically, the cause for term A's existance in the tree, might be
* becasue node B depends on it.
*
* @var array
*/
public $causes = array();
/**
* Keeps track of entities that have already been checked for dependencies.
*
* @var array
*/
public $checked = array();
/**
* Keeps track of entities that have already been traversed (output).
*
* @var array
*/
public $traversed = array();
/**
* Constructor.
*
* @param array $entities
* A structured array of entity ids and their entity types.
* @param array $parent
* The parent array of the current entity.
*
* @see entity_dependency_iterator()
*/
public function __construct($entities, &$parent = NULL) {
$this->entities = array();
foreach ($entities as $entity_arr) {
$entity_obj = entity_load($entity_arr['type'], array(
$entity_arr['id'],
));
if (empty($entity_obj)) {
if (isset($parent)) {
$error_msg = 'Failed to load %type ID %id, which is a dependency of %parent_type ID %parent_id.';
$error_vars = array(
'%type' => $entity_arr['type'],
'%id' => $entity_arr['id'],
'%parent_type' => $parent->current['type'],
'%parent_id' => $parent->current['id'],
);
}
else {
$error_msg = t('Failed to load requested %type ID %id.');
$error_vars = array(
'%type' => $entity_arr['type'],
'%id' => $entity_arr['id'],
);
}
watchdog('Entity Dependency', $error_msg, $error_vars, WATCHDOG_WARNING);
}
else {
$this->entities[] = $entity_arr;
}
}
if (empty($parent)) {
foreach ($this->entities as $key => $entity) {
$this->causes[$entity['type']][$entity['id']] = FALSE;
}
}
else {
$this->causes =& $parent->causes;
$this->checked =& $parent->checked;
$this->traversed =& $parent->traversed;
}
}
/**
* Returns TRUE if an iterator can be created for the current item in the
* entities array.
*
* @return boolean
*/
public function hasChildren() {
$current = $this->current;
// Don't check for dependencies twice.
if (!empty($this->current['id']) && !isset($this->checked[$current['type']][$current['id']])) {
// Load the current entity.
if (!empty($current['revision_id'])) {
$entity_info = entity_get_info($current['type']);
if (!empty($entity_info['entity keys']['revision'])) {
$conditions = array(
$entity_info['entity keys']['revision'] => $current['revision_id'],
);
}
}
else {
$conditions = array();
}
$entities = entity_load($current['type'], array(
$current['id'],
), $conditions);
$entity = reset($entities);
// When $entity does not exist (may be the case with references
// to deleted taxonomy terms), skip and remove it from $this->entites.
if (!$entity) {
watchdog('entity_dependency', "Missing entity %id of type %type", array(
'%id' => $current['id'],
'%type' => $current['type'],
), WATCHDOG_WARNING);
// We can't do anything useful with the no-existent entity,
// therfore we just remove it.
array_shift($this->entities);
return FALSE;
}
$this->dependencies = module_invoke_all('entity_dependencies', $entity, $current['type']);
//$this->belongings = module_invoke_all('entity_belongings', $entity, $this->entityType);
// Don't add dependencies that already were checked.
foreach ($this->dependencies as $key => $dependency) {
if ($dependency['type'] == $current['type'] && $dependency['id'] == $current['id'] || isset($this->checked[$dependency['type']][$dependency['id']])) {
unset($this->dependencies[$key]);
}
else {
$this->causes[$dependency['type']][$dependency['id']] = $current;
}
}
// Let other modules have their say.
drupal_alter('entity_dependencies', $this->dependencies, $entity, $current['type']);
// Now mark this as checked.
$this->checked[$current['type']][$current['id']] = TRUE;
if (!empty($this->dependencies)) {
return TRUE;
}
}
return FALSE;
}
/**
* Helper method to get entity dependencies.
*/
public function getChildrenEntities() {
$entities = array();
$current = current($this->entities);
if (!empty($this->dependencies)) {
$entities = $this->dependencies;
// In an iterator, having children means that the current key itself
// isn't a part of the entities. However, we need that entity.. So we add
// the parent as a part of the entities. And since children always should
// go first, we add the parent last.
$entities[] = $current;
}
return $entities;
}
/**
* Returns an iterator for the current entry.
*
* @return EntityDependencyIterator
*/
public function getChildren() {
return new EntityDependencyIterator($this
->getChildrenEntities(), $this);
}
/**
* Get the current entity formatted with some extra metadata according to
* the OData protocol.
*
* @see http://www.odata.org/developers/protocols
*/
public function current() {
$current = current($this->entities);
// Load the current entity.
$entities = entity_load($current['type'], array(
$current['id'],
));
$entity = reset($entities);
// Add necessary metadata to the entity.
$cause = FALSE;
if (!empty($this->causes[$current['type']][$current['id']])) {
$cause = $this->causes[$current['type']][$current['id']]['type'] . '/' . $this->causes[$current['type']][$current['id']]['id'];
}
$entity->__metadata = array(
'type' => $current['type'],
'uri' => $current['type'] . '/' . $current['id'],
'cause' => $cause,
);
// Now mark this as traversed.
$this->traversed[$current['type']][$current['id']] = TRUE;
return $entity;
}
/**
* Returns the key of the current element.
*/
public function key() {
return key($this->entities);
}
/**
* Moves the current position to the next element.
*/
public function next() {
do {
$current = next($this->entities);
} while (!empty($current) && isset($this->traversed[$current['type']][$current['id']]));
}
/**
* Rewinds the Iterator to the first element.
*/
public function rewind() {
reset($this->entities);
}
/**
* Checks if current position is valid.
*
* @return boolean
*/
public function valid() {
$current = current($this->entities);
if (!empty($current) && is_array($current) && isset($current['type']) && isset($current['id']) && !isset($this->traversed[$current['type']][$current['id']])) {
$this->current = $current;
return TRUE;
}
return FALSE;
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
EntityDependencyIterator:: |
public | property | An array of belongings to the entity being parsed. | |
EntityDependencyIterator:: |
public | property | An array with information on the cause/reason why an entity exists in the tree. Basically, the cause for term A's existance in the tree, might be becasue node B depends on it. | |
EntityDependencyIterator:: |
public | property | Keeps track of entities that have already been checked for dependencies. | |
EntityDependencyIterator:: |
public | property | An array of dependencies to the entity being parsed. | |
EntityDependencyIterator:: |
public | property | The entities to be iterated over. | |
EntityDependencyIterator:: |
public | property | The entity ID of the entity currently being iterated over. | |
EntityDependencyIterator:: |
public | property | The entity type of the entity currently being iterated over. | |
EntityDependencyIterator:: |
public | property | Keeps track of entities that have already been traversed (output). | |
EntityDependencyIterator:: |
public | function | Get the current entity formatted with some extra metadata according to the OData protocol. | |
EntityDependencyIterator:: |
public | function | Returns an iterator for the current entry. | |
EntityDependencyIterator:: |
public | function | Helper method to get entity dependencies. | |
EntityDependencyIterator:: |
public | function | Returns TRUE if an iterator can be created for the current item in the entities array. | |
EntityDependencyIterator:: |
public | function | Returns the key of the current element. | |
EntityDependencyIterator:: |
public | function | Moves the current position to the next element. | |
EntityDependencyIterator:: |
public | function | Rewinds the Iterator to the first element. | |
EntityDependencyIterator:: |
public | function | Checks if current position is valid. | |
EntityDependencyIterator:: |
public | function | Constructor. |