1<?php 2/* 3 * $Id: Node.php 7490 2010-03-29 19:53:27Z jwage $ 4 * 5 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 6 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 7 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 8 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 9 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 10 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 11 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 12 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 13 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 14 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 15 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 16 * 17 * This software consists of voluntary contributions made by many individuals 18 * and is licensed under the LGPL. For more information, see 19 * <http://www.doctrine-project.org>. 20 */ 21 22/** 23 * Doctrine_Node 24 * 25 * @package Doctrine 26 * @subpackage Node 27 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL 28 * @link www.doctrine-project.org 29 * @since 1.0 30 * @version $Revision: 7490 $ 31 * @author Joe Simms <joe.simms@websites4.com> 32 */ 33class Doctrine_Node implements IteratorAggregate 34{ 35 /** 36 * @param object $record reference to associated Doctrine_Record instance 37 */ 38 protected $record; 39 40 /** 41 * @param array $options 42 */ 43 protected $options; 44 45 /** 46 * @param string $iteratorType (Pre | Post | Level) 47 */ 48 protected $iteratorType; 49 50 /** 51 * @param array $iteratorOptions 52 */ 53 protected $iteratorOptions; 54 55 /** 56 * The tree to which the node belongs. 57 * 58 * @var unknown_type 59 */ 60 protected $_tree; 61 62 /** 63 * contructor, creates node with reference to record and any options 64 * 65 * @param object $record instance of Doctrine_Record 66 * @param array $options options 67 */ 68 public function __construct(Doctrine_Record $record, $options) 69 { 70 $this->record = $record; 71 $this->options = $options; 72 73 // Make sure that the tree object of the root class is used in the case 74 // of column aggregation inheritance (single table inheritance). 75 $class = $record->getTable()->getComponentName(); 76 $thisTable = $record->getTable(); 77 $table = $thisTable; 78 if ($thisTable->getOption('inheritanceMap')) { 79 // Move up the hierarchy until we find the "subclasses" option. This option 80 // MUST be set on the root class of the user's hierarchy that uses STI. 81 while ( ! $subclasses = $table->getOption('subclasses')) { 82 $class = get_parent_class($class); 83 $reflectionClass = new ReflectionClass($class); 84 if ($reflectionClass->isAbstract()) { 85 continue; 86 } 87 if ($class == 'Doctrine_Record') { 88 throw new Doctrine_Node_Exception("No subclasses specified. You are " 89 . "using Single Table Inheritance with NestedSet but you have " 90 . "not specified the subclasses correctly. Make sure you use " 91 . "setSubclasses() in the root class of your hierarchy."); 92 } 93 $table = $table->getConnection()->getTable($class); 94 } 95 } 96 if ($thisTable !== $table) { 97 $this->_tree = $table->getTree(); 98 } else { 99 $this->_tree = $thisTable->getTree(); 100 } 101 } 102 103 /** 104 * Factory method for creating a Node. 105 * 106 * This is a factory method that returns node instance based upon chosen 107 * implementation. 108 * 109 * @param object $record instance of Doctrine_Record 110 * @param string $implName implementation (NestedSet, AdjacencyList, MaterializedPath) 111 * @param array $options options 112 * @return Doctrine_Node 113 * @throws Doctrine_Node_Exception if $implName is not a valid class 114 */ 115 public static function factory(Doctrine_Record $record, $implName, $options = array()) 116 { 117 $class = 'Doctrine_Node_' . $implName; 118 119 if ( ! class_exists($class)) { 120 throw new Doctrine_Node_Exception("The class $class must exist and extend Doctrine_Node"); 121 } 122 123 return new $class($record, $options); 124 } 125 126 /** 127 * setter for record attribute 128 * 129 * @param object $record instance of Doctrine_Record 130 */ 131 public function setRecord(Doctrine_Record $record) 132 { 133 $this->record = $record; 134 } 135 136 /** 137 * getter for record attribute 138 * 139 * @return Doctrine_Record 140 */ 141 public function getRecord() 142 { 143 return $this->record; 144 } 145 146 /** 147 * convenience function for getIterator 148 * 149 * @param string $type type of iterator (Pre | Post | Level) 150 * @param array $options options 151 */ 152 public function traverse($type = 'Pre', $options = array()) 153 { 154 return $this->getIterator($type, $options); 155 } 156 157 /** 158 * get iterator 159 * 160 * @param string $type type of iterator (Pre | Post | Level) 161 * @param array $options options 162 */ 163 public function getIterator($type = null, $options = null) 164 { 165 if ($type === null) { 166 $type = (isset($this->iteratorType) ? $this->iteratorType : 'Pre'); 167 } 168 169 if ($options === null) { 170 $options = (isset($this->iteratorOptions) ? $this->iteratorOptions : array()); 171 } 172 173 $implName = $this->record->getTable()->getOption('treeImpl'); 174 $iteratorClass = 'Doctrine_Node_' . $implName . '_' . ucfirst(strtolower($type)) . 'OrderIterator'; 175 176 return new $iteratorClass($this->record, $options); 177 } 178 179 /** 180 * sets node's iterator type 181 * 182 * @param int 183 */ 184 public function setIteratorType($type) 185 { 186 $this->iteratorType = $type; 187 } 188 189 /** 190 * sets node's iterator options 191 * 192 * @param int 193 */ 194 public function setIteratorOptions($options) 195 { 196 $this->iteratorOptions = $options; 197 } 198} 199