Location: PHPKode > projects > Rthree > r3-1.9.0/r3/Iterator.php
<?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();
    }

}

?>
Return current item: Rthree