* - IAdjacencyTreeNode Interface der Nodeclass * - AdjacencyTreeNode Defaultnodeclass */ /** * Tree Class * ArrayObjct * @see ArrayObject */ class AdjacencyTree extends ArrayObject{ const NODE_INTERFACE = 'IAdjacencyTreeNode'; const DEFAULT_NODE_CLASS = 'AdjacencyTreeNode'; protected $nodeClass; protected $rootId; /** * Konstruktor * @param String $nodeClass Der Name der Node-Klasse mit dem Interface IAdjacencyTreeNode * @param String $rootKey ID des RootElementes */ public function __construct($nodeClass = self::DEFAULT_NODE_CLASS, $rootId = 0){ parent::__construct(array()); $this->nodeClass = $nodeClass; $this->rootId = $rootId; } /** * Hinzufügen eines Nodes. Es wird geprüft dass es ein Objekt der Klasse AdjacencyTreeNode ist. * @see ArrayObject::append() */ public function append($value){ if(is_a($value, self::NODE_INTERFACE)){ $this->offsetSet($value->id, $value); }else{ throw new ErrorException('Node-Class is not from Type ' . self::NODE_INTERFACE); } } /** * Wechselt den ganzen Array aus. Jedes ArrayItem wird auf das Interface IAdjacencyTreeNode geprüft * @param Array $input Neuer Node-Array * @see ArrayObject::exchangeArray() */ public function exchangeArray($input){ parent::exchangeArray(array()); foreach($input as $node){ $this->append($node); } } /** * Direktes Erstellen eines Nodes * @param Integer $id ID des Nodes * @param Integer $parentId ID des Parentnodes * @param String $title Beschriftung * @param Array $paramArray Ein assozierter Array mit weiteren Informationen für den Node */ public function createNode($id, $parentId, $title, $paramArray = null){ // $node = $this->nodeClass::create($id, $parentId, $title); $node = call_user_func("{$this->nodeClass}::create", $id, $parentId, $title); if(is_array($paramArray)){ foreach($paramArray as $name => $value){ $node->$name = $value; } } $this->append($node); return $node; } /** * Starte die Berechnung des Trees */ public function calcTree(){ //Den Tree aufbauen $this->addTreeInfos($this->rootId); //und sortieren $this->uasort(array($this, 'sortByNodeSort')); } /** * Wird intern für die Sortirung gebraucht */ public static function sortByNodeSort($a, $b){ if ($a->getSort() == $b->getSort()) { return 0; } return ($a->getSort() < $b->getSort()) ? -1 : 1; } /** * Nachträgliches Setzen des Root-ID * @param String rootId */ public function setRootKey($rootId){ $this->rootId = $rootId; } /** * Dei rekursive Funktion für die Treeberechnung * @param Integer $parentId ID des Parentnodes * @param String $sortParent Sortierung des ParentNodes * @param Integer $level Level dieses Nodes */ private function addTreeInfos($parent, $sortParent = '', $lvl = 0){ $iter = $this->getIterator(); foreach($iter as $key => &$node){ if((string) $node->getParentId() == (string) $parent){ $node->addTreeInfos($sortParent, $lvl); //Und dasselbe für alle Kinder des aktellen Nodes $this->addTreeInfos($node->getId(), (string)$node->getSort(), $lvl+1); } } } } /** * Interface der Node-Class * Wird verwendet wenn man eine eigene Klasse schreiben will */ interface IAdjacencyTreeNode{ /** * Konstruktor * @param Integer $id ID des Nodes * @param Integer $parentId ID des Parentnodes * @param String $title Beschriftung */ public static function create($id, $parentId, $title); /** * TreeInfos des Nodes erstellen * @param String $sortParent Sortierung des ParentNodes * @param Integer $level Level dieses Nodes */ public function addTreeInfos($sortParent, $level); /** * Getter aller Properties die in der TreeClass verwendet werden */ public function getId(); public function getParentId(); public function getSort(); } /** * Default Node Class * Ein einzelner Node des Trees * SOlange das Interface verwendet wird, kann auch eine eigene Node-Class geschrieben werden */ class AdjacencyTreeNode implements IAdjacencyTreeNode{ private $id; private $parentId; private $title; private $sort; private $level; private $treeText; private $order; /** * Damit Ableitungen mit verschiedenen Konstrukteuren arbeiten können, ist dieser nicht genau deklariert * Es kann aber ein Argument als Array oder Objekt übergeben werden. Alle Elemente des Array (Properties des Objects) * werden als Propierties im Node erstellt. Key (PropetyName) => value * Es ist dabei nicht wichtig ob es sich um die 3 Key-Argumente handelt oder nicht. * @example * $node = new AdjacencyTreeNode(); * @example * $node = new AdjacencyTreeNode(array('id'=>1, 'parentId'=>5, 'tooltip'=>'hallo Welt')); * @example * $node = $pdoStmt->fetch(PDO::FETCH_CLASS, 'AdjacencyTreeNode') */ public function __construct(){ //Prüfen ob Argumente mitgegeben wurden und das erste Argument auslesen if(func_num_args() > 1 && false !== ($arg0 = func_get_arg(0))){ //Falls es sich um ein Obejkt handelt, alle Properties in einen Array lesen if(is_object($arg0)) $arg0 = get_object_vars($arg0); if(is_array($arg0)){ //Alle Elemente des Arrays übernehmen foreach($arg0 as $name => $value){ $this->$name = $value; } } } } /** * Konstruktor * @param Integer $id ID des Nodes * @param Integer $parentId ID des Parentnodes * @param String $title Beschriftung */ public static function create($id, $parentId, $title){ $instance = new AdjacencyTreeNode(); $instance->id = $id; $instance->parentId = $parentId; $instance->title = $title; return $instance; } /** * TreeInfos des Nodes erstellen * @param String $sortParent Sortierung des ParentNodes * @param Integer $level Level dieses Nodes */ public function addTreeInfos($sortParent, $level){ $this->level = $level; $this->setSortText($sortParent); $this->createTreeText(); } /** * Setzt den TreeText des Nodes */ protected function createTreeText(){ $this->treeText = str_repeat('-- ', $this->level) . $this->title; } /** * Setzt die Sortierung richtig. In diesem Fall nach id * @param String $sortParent Sortierung des ParentNodes */ protected function setSortText($sortParent){ $this->sort = sprintf('%s.[%s]', $sortParent, $this->id); } /** * generic Getter & Setter */ public function __set($name, $value){$this->$name = $value;} public function __get($name){ //Falls ein Parameter fehlt, diesen mit NULL zurückgeben und jeden Fehler ignorieren $errLvl = error_reporting(); error_reporting(0); $retVal = $this->$name; error_reporting($errLvl); return $retVal; } /** * Getter aller Properties die in der TreeClass verwendet werden */ public function getId(){ return $this->id;} public function getParentId(){ return $this->parentId;} public function getSort(){ return $this->sort;} } ?>