* @license PHP License * @package WB * @subpackage content */ /** * Datasource Tree Menu * * Acces to tree menu itms * * @version 0.2.0 * @package WB * @subpackage content */ class WBDatasource_TreeMenu extends WBStdClass { const SELECT_FIRST = 'first'; const SELECT_LAST = 'last'; const SELECT_SHORT = 'short'; const SELECT_LONG = 'long'; /** * Tree datasource object * @var WBDatasource_Tree */ private $tree; /** * URL dictionary * @var WBDictionary_URL */ protected $url; /** * Id of root item * @var string */ private $rootId = null; /** * List of child trees * @var array WBDatasource_TreeMenu_Child */ private $childTrees = array(); /** * Map URLIDs to child trees * @var WBDatasource_TreeMenu_Child */ private $childTreeMap = array(); /** * constructor * * */ public function __construct() { $params = array( 'treetable' => 'menu', 'alphalength' => 4, ); $this->tree = WBClass::create('WBDatasource_Tree', $params); $this->url = WBClass::create('WBDictionary_URL'); } /** * Inject cache parameter * * Cache parameters are used to create a unique cache id. * Implement this function to add custom parameters for caching. * * It is recommended to prefix custom parameter with a namespace plus colon. * * @param array $params */ public function addCacheIdParams(&$params) { } /** * Use list of child-trees * * @param array $list */ public function useChildTrees($list) { if (!is_array($list) || empty($list)) { return; } foreach ($list as $l) { // normalize config if (is_array($l)) { if (!is_array($l['params'])) { $l['params'] = array(); } if (empty($l['name'])) { $ex = array( 'code' => 1, 'class' => __CLASS__, 'msg' => 'Config of menu tree child is corrupt - the name is missing.' ); throw WBClass::create('WBException_Config', $ex); } } else { $l = array( 'name' => $l, 'params' => array() ); } $obj = WBClass::create('WBDatasource_TreeMenu_Child_' . $l['name'], $l['params']); $this->childTrees[] = $obj; } } /** * Set root id * * Use menu root * * @param string $id */ public function setRoot($id) { $this->tree->get($id); $this->rootId = $id; } /** * Get current root id * * @return string */ protected function getRootId() { return $this->rootId; } /** * Get URL id of current page * * Auxilliary method, can be overwritten * * @param string $uri * @return string $urlid */ public function getUrlId($uri) { $this->url->addWord($uri); return $this->url->getId(); } /** * Get selected menu record by URLid * * @param string $urlid * @param string $select * @return array curren node */ public function getMenuCurrent($urlid, $select = self::SELECT_FIRST) { // find current URL in menu $clause = array(); $clause[] = array( 'field' => 'urlid', 'value' => $urlid ); $current = $this->tree->getChildren($this->rootId, 0, array(), $clause); $childCurrent = $this->getMenuCurrentChild($urlid); if (empty($current)) { $current = $childCurrent; // if nothing matches load at least the menu if (empty($current)) { $current = $this->tree->get($this->rootId); } } else { $current = $this->selectNode($current, $select); } $this->injectUrl($current); return $current; } /** * Select one node * * @param array $node list of nodes * @param string $select * @param array selected node */ private function selectNode($node, $select) { if (1 == count($node)) { return $node[0]; } // simply select by position in list if (self::SELECT_FIRST == $select) { return array_shift($node); } if (self::SELECT_LAST == $select) { return array_pop($node); } // select by path length - depth in hirachie $i = 0; $pathLength = strlen($node[0]['path']); for($j = 1; $j < count($node); ++$j) { $pl = strlen($node[$j]['path']); switch ($select) { case self::SELECT_SHORT: if ($pl < $pathLength) { $pathLength = $pl; $i = $j; } break; case self::SELECT_LONG: if ($pl > $pathLength) { $pathLength = $pl; $i = $j; } break; } } return $node[$i]; } private function getMenuCurrentChild($urlid) { $url = clone $this->url; $url->load($urlid); if (empty($this->childTrees)) { return array(); } foreach ($this->childTrees as $ct) { if ($ct->checkUrl($url->getWord())) { return $ct->getNode($url->getId(), $url->getWord()); } } return array(); } /** * Get ancestors * * Receive list of parents from menu tree. Auxilliary method can be overwritten * * @param array $current node * @return array */ public function getMenuParents($current) { $childish = array(); foreach ($this->childTrees as $ct) { if ($ct->checkUrl($current['url'])) { $childish = $ct->getParents($current); break; } } // load ascending parents if (empty($childish)) { $parents = $this->tree->getParent($current['id'], 0); } else { $clause = array(); $clause[] = array( 'field' => 'urlid', 'value' => $childish[0]['urlid'] ); array_pop($childish); $tmp = $this->tree->getChildren($this->rootId, 0, array(), $clause); $childish[0] = $tmp[0]; $parents = $this->tree->getParent($tmp[0]['id'], 0); $parents = array_merge($parents, $childish); } $parents[] = $current; foreach ($parents as &$node) { $this->injectUrl($node); } return $parents; } /** * Get direct offspring of parent node * * Receive children from menu tree * * @param array $parent node * @return array */ public function getMenuChildren($parent) { foreach ($this->childTrees as $ct) { if ($ct->checkUrl($parent['url'])) { return $ct->getChildren($parent['url']); } } $children = $this->tree->getChildren($parent['id']); foreach ($children as &$node) { $this->injectUrl($node); } return $children; } /** * Select menu node by id * * @param string $id * @return array */ public function getMenuNode($id) { $node = $this->tree->get($id); $this->injectUrl($node); return $node; } /** * Inject URL into node * * Locate URL-id and set "url" either to [[SERVICE_HTML]] * or the actual URL of the Dictionary_URL item * * @param array $node */ private function injectUrl(&$node) { if (isset($node['url']) && !empty($node['url'])) { return; } if (0 == $node['urlid']) { $node['url'] = '[[SERVICE_HTML]]'; return; } $this->url->load($node['urlid']); $node['url'] = $this->url->getWord(); } }