<?php
/**
* Iterator class for use in children of DomainMapper class.
* implements php built-in Iterator interface.
*
*
* Copyright (c) 2007 Yahoo! Inc. All rights reserved.
* The copyrights embodied in the content of this file are licensed under the BSD
* open source license
*
* @package r3
* @author Robin Baker <hide@address.com>
* @version CVS: $Id: Iterator.php,v 1.19 2009-03-18 18:39:07 zandstra Exp $
*/
/**
*requires
*/
require_once("r3/util/Exception.php");
require_once("r3/domain/Dimension.php");
require_once("r3/domain/Location.php");
require_once("r3/domain/InheritanceChain.php");
/**
* class r3_ChainIterator implements Iterator
*
* Used to cycle through a list of "vertical chains" of r3_Elements
* (each list is a r3_InheritanceChain object). Each call to
* current() produces a set of r3_Element objects, one for each
* dimension (or each child in the chain).
*
*
* @package r3
*/
class r3_ChainIterator implements Iterator {
private $inheritanceChain; // r3_InheritanceChain (Iterator)
private $child = null; // r3_ChainIterator
private $id = 0;
private $curval = array();
private $valid = true;
/**
* __construct( $inheritanceChain, $child = null )
*
* Initialise this iterator. If no child iterator is supplied,
* this iterator is at the end of the chain of iterators.
*
* @param r3_domain_InheritanceChain $inheritanceChain Iterator based class representing a "vertical chain" of r3_Element objects for one dimension, for the top r3_ChainIterator object in a chain of such objects.
* @param r3_ChainIterator $child the next r3_ChainIterator in the chain.
*/
function __construct( r3_domain_InheritanceChain $inheritanceChain, $child = null ) {
if ( ! is_null( $child ) ) {
if ( ! ( $child instanceof r3_ChainIterator ) ) {
throw new r3_util_Exception( "child should be type r3_domain_ChainIterator" );
}
}
$this->inheritanceChain = $inheritanceChain;
$this->child = $child;
}
/**
* function rewind()
*
* This must rewind every r3_InheritanceChain held by each of the
* chain of r3_ChainIterators. rewind() recursively calls its own
* list (Iterator) rewind and sets the current object to the child
* and repeats for each child until the end of the chain. Finally,
* rewind calls iterate() to generate the first element for
* current() to output.
**/
function rewind() {
$this->valid = true;
$curObj = $this;
if ( isset($curObj->inheritanceChain) ) {
$curObj->inheritanceChain->rewind();
}
while( $curObj->child != null ) {
$curObj = $curObj->child;
$curObj->inheritanceChain->rewind();
}
$this->curval = $this->iterate();
}
/**
* function current()
*
* @return array The returned array of elements computed by iterate()
*/
function current() {
return $this->curval;
}
/**
* function next()
*
* calls private iterate() method and stores in a private member for output in current()
*/
function next() {
$this->curval = $this->iterate();
}
/**
* function valid()
*
* @return boolean private member that is set to false by iterate() when all is done.
*/
function valid() {
return $this->valid;
}
function key() {
}
/**
* private function iterate()
*
* This does the hard work!
*
* Works through the child objects like a odometer. The child at the
* end of the chain cycles through fastest. The parent cycles
* slowest.
*
* @return array The computed list of elements of the current r3_Iterator and its children.
**/
private function iterate() {
$sofar = array();
if( $this->child != null ) {
$sofar = $this->child->iterate();
}
if( count($sofar) > 0 ) {
$ret = array_merge(array($this->inheritanceChain->current()), $sofar);
return $ret;
}
else {
if ( !isset($this->inheritanceChain) ) {
$this->valid = false;
return array();
}
if( $this->child != null ) {
$this->inheritanceChain->next();
}
if( ! $this->inheritanceChain->valid() ) {
$this->inheritanceChain->rewind();
$this->valid = false;
return array();
}
else if( $this->child == null ) {
$result = $this->inheritanceChain->current();
$this->inheritanceChain->next();
return array($result);
}
else {
$ret = array_merge( array($this->inheritanceChain->current()), $this->child->iterate());
return $ret;
}
}
}
}
/**
* class r3_Iterator extends r3_ChainIterator
*
* This child class overrides the constructor and current() methods of r3_ChainIterator.
*
* @package r3
*/
class r3_Iterator extends r3_ChainIterator {
/**
* __construct( r3_Location $start_loc, r3_Domain $dom )
*
* Using the value of an r3_Element for a particular dimension in
* $start_loc, the constructor builds a list of inherited values for
* this dimension using the list returned from
* $dom->getVerticalElementChains(). This list is shortened so that
* the first element in the list is the same as the value for that
* dimension supplied by $start_loc. Each list (for each dimension)
* is passed to r3_ChainIterator as a r3_InheritanceChain object.
*
* @param r3_Location $start_loc $start_loc contains a list r3_Element objects, one for each dimension.
* @param r3_Domain $dom contains the method getVerticalElementChains() which returns a vertical list of r3_Elements for one dimension.
*/
function __construct( r3_domain_Location $start_loc, r3_Domain $dom ) {
$elemChain = array();
foreach($start_loc as $elem) {
$chain = $elem->getInheritanceChain( $dom );
$elemChain[] = $chain;
}
$iter = null;
for ( $i = count($elemChain) - 1; $i > 0; $i-- ) {
$iter = new r3_ChainIterator($elemChain[$i],$iter);
}
if ( !empty($elemChain) ) {
parent::__construct( $elemChain[0], $iter);
}
}
/**
* function current()
*
* overrides r3_ChainIterator method (returns an array of
* r3_domain_Elems). Constructs a r3_domain_Location object using
* the array from r3_ChainIterator::current()
*
* @return r3_domain_Location The next location in the inheritance path.
**/
function current() {
$elems = parent::current();
return new r3_domain_Location($elems);
}
function currentElements() {
return parent::current();
}
}
class r3_UserRuleIterator extends r3_Iterator {
function __construct( r3_domain_Location $start_loc, r3_Domain $dom ) {
parent::__construct( $start_loc, $dom );
}
function current() {
return new r3_domain_UserRuleLocation( $this->currentElements() );
}
}
class r3_FilterChainIterator extends r3_ChainIterator {
function __construct( $elements ) {
$dimensions = r3_mapper_GenericInheritanceManager::getDimensions(); // excludes page
$dimensions[]=utf8('page');
$elemChain = array();
foreach ( $elements as $elname ) {
$dim = array_shift( $dimensions );
if ( $elname->eq(utf8('*')) ) {
if ( $dim->eq(utf8('page'))) {
throw new r3_util_Exception("cannot wildcard page dimension");
}
$elobjs = r3_util_Registry::inst()->genericInheritanceManager()->listElements( $dim );
$elemChain[] = new r3_domain_InheritanceChain( $elobjs );
} else {
$elobj = r3_domain_Element::create($dim, $elname);
$elemChain[] = new r3_domain_InheritanceChain( $elobj );
}
}
$iter = null;
for ( $i = count($elemChain) - 1; $i >= 0; $i-- ) {
$iter = new r3_ChainIterator($elemChain[$i],$iter);
}
$this->iter = $iter;
}
function rewind() {
$this->iter->rewind();
}
function current() {
return $this->iter->current();
}
function next() {
return $this->iter->next();
}
function valid() {
return $this->iter->valid();
}
function key() {
return $this->iter->key();
}
}
?>