ItemVisitor. *

* Level 1 and 2 *

* TraversingItemVisitor is an abstract utility class * which allows to easily traverse an Item hierarchy. *

*

TraversingItemVisitor makes use of the Visitor Pattern * as described in the book 'Design Patterns' by the Gang Of Four * (Gamma et al.). *

*

Tree traversal is done observing the left-to-right order of * child Items if such an order is supported and exists. * * @author Markus Nix * @package phpcr * @subpackage util */ abstract class TraversingItemVisitor implements ItemVisitor { /**$currentQueue * indicates if traversal should be done in a breadth-first * manner rather than depth-first (which is the default) * * @var bool */ protected $breadthFirst = false; /** * the 0-based level up to which the hierarchy should be traversed * (if it's -1, the hierarchy will be traversed until there are no * more children of the current item) * * @var int */ protected $maxLevel = -1; /** * queues used to implement breadth-first traversal * * @var array */ private $currentQueue; private $nextQueue; /** * used to track hierarchy level of item currently being processed * * @var int */ private $currentLevel; /** * Constructs a new instance of this class. * * @param breadthFirst if breadthFirst is true then traversal * is done in a breadth-first manner; otherwise it is done in a * depth-first manner (which is the default behaviour). */ public function __construct( $breadthFirst = false, $maxLevel = -1 ) { $this->breadthFirst = $breadthFirst; if ( $this->breadthFirst === true ) { $this->currentQueue = array(); $this->nextQueue = array(); } $this->currentLevel = 0; $this->maxLevel = $maxLevel; } /** * Implement this method to add behaviour performed before a * Property or Node is visited. * * @param entry that is accepting this visitor. * @param level hierarchy level of this property (the root node starts at level 0) * @throws RepositoryException if an error occurrs */ protected abstract function entering( $entry, $level ); /** * Implement this method to add behaviour performed after a * Property is visited. * * @param entry the Property that is accepting this visitor. * @param level hierarchy level of this property (the root node starts at level 0) * @throws RepositoryException if an error occurrs */ protected abstract function leaving( $entry, $level ); /** * Called when the Visitor is passed to a Node. *

* It calls TraversingItemVisitor.entering(Node, int) followed by * TraversingItemVisitor.leaving(Node, int). Implement these abstract methods to * specify behaviour on 'arrival at' and 'after leaving' the Node. *

* If this method throws, the visiting process is aborted. * * @param Either Node or Property that is accepting this visitor. * @throws RepositoryException if an error occurrs */ public function visit( $entry ) { if ( $entry instanceof Property ) { $this->entering( $entry, $this->currentLevel ); $this->leaving( $entry, $this->currentLevel ); } else { try { if ( !$this->breadthFirst ) { // depth-first traversal $this->entering( $entry, $this->currentLevel ); if ( $this->maxLevel == -1 || $this->currentLevel < $this->maxLevel ) { $this->currentLevel++; $nodeIter = $entry->getNodes(); while ( $nodeIter->hasNext() ) { $nodeIter->nextNode()->accept( $this ); } $propIter = $entry->getProperties(); while ( $propIter->hasNext()) { $propIter->nextProperty()->accept( $this ); } $currentLevel--; } $this->leaving( $entry, $this->currentLevel ); } else { // breadth-first traversal $this->entering( $entry, $this->currentLevel ); $this->leaving( $entry, $this->currentLevel ); if ( $this->maxLevel == -1 || $this->currentLevel < $this->maxLevel ) { $nodeIter = $entry->getNodes(); while ( $nodeIter->hasNext() ) { $this->nextQueue[] = $nodeIter->nextNode(); } $propIter = $entry->getProperties(); while ( $propIter->hasNext() ) { $this->nextQueue[] = $propIter->nextProperty(); } } while ( !empty( $this->currentQueue ) || !empty( $this->nextQueue ) ) { if ( empty( $this->currentQueue ) ) { $this->currentLevel++; $this->currentQueue = $this->nextQueue; $this->nextQueue = array(); } $this->currentQueue = array_shift( $this->currentQueue ); } $this->currentLevel = 0; } } catch ( RepositoryException $re ) { $this->currentLevel = 0; throw $re; } } } } ?>