| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335 | 
							- <?php
 
- /**
 
-  * Elgg Menu Builder
 
-  *
 
-  * @package    Elgg.Core
 
-  * @subpackage Navigation
 
-  * @since      1.8.0
 
-  */
 
- class ElggMenuBuilder {
 
- 	/**
 
- 	 * @var \ElggMenuItem[]
 
- 	 */
 
- 	protected $menu = array();
 
- 	protected $selected = null;
 
- 	/**
 
- 	 * \ElggMenuBuilder constructor
 
- 	 *
 
- 	 * @param \ElggMenuItem[] $menu Array of \ElggMenuItem objects
 
- 	 */
 
- 	public function __construct(array $menu) {
 
- 		$this->menu = $menu;
 
- 	}
 
- 	/**
 
- 	 * Get a prepared menu array
 
- 	 *
 
- 	 * @param mixed $sort_by Method to sort the menu by. @see \ElggMenuBuilder::sort()
 
- 	 * @return array
 
- 	 */
 
- 	public function getMenu($sort_by = 'text') {
 
- 		$this->selectFromContext();
 
- 		$this->selected = $this->findSelected();
 
- 		$this->setupSections();
 
- 		$this->setupTrees();
 
- 		$this->sort($sort_by);
 
- 		return $this->menu;
 
- 	}
 
- 	/**
 
- 	 * Get the selected menu item
 
- 	 *
 
- 	 * @return \ElggMenuItem
 
- 	 */
 
- 	public function getSelected() {
 
- 		return $this->selected;
 
- 	}
 
- 	/**
 
- 	 * Select menu items for the current context
 
- 	 *
 
- 	 * @return void
 
- 	 */
 
- 	protected function selectFromContext() {
 
- 		if (!isset($this->menu)) {
 
- 			$this->menu = array();
 
- 			return;
 
- 		}
 
- 		// get menu items for this context
 
- 		$selected_menu = array();
 
- 		foreach ($this->menu as $menu_item) {
 
- 			if (!is_object($menu_item)) {
 
- 				_elgg_services()->logger->error("A non-object was passed to \ElggMenuBuilder");
 
- 				continue;
 
- 			}
 
- 			if ($menu_item->inContext()) {
 
- 				$selected_menu[] = $menu_item;
 
- 			}
 
- 		}
 
- 		$this->menu = $selected_menu;
 
- 	}
 
- 	/**
 
- 	 * Group the menu items into sections
 
- 	 * 
 
- 	 * @return void
 
- 	 */
 
- 	protected function setupSections() {
 
- 		$sectioned_menu = array();
 
- 		foreach ($this->menu as $menu_item) {
 
- 			if (!isset($sectioned_menu[$menu_item->getSection()])) {
 
- 				$sectioned_menu[$menu_item->getSection()] = array();
 
- 			}
 
- 			$sectioned_menu[$menu_item->getSection()][] = $menu_item;
 
- 		}
 
- 		$this->menu = $sectioned_menu;
 
- 	}
 
- 	/**
 
- 	 * Create trees for each menu section
 
- 	 *
 
- 	 * @internal The tree is doubly linked (parent and children links)
 
- 	 * @return void
 
- 	 */
 
- 	protected function setupTrees() {
 
- 		$menu_tree = array();
 
- 		foreach ($this->menu as $key => $section) {
 
- 			$parents = array();
 
- 			$children = array();
 
- 			$all_menu_items = array();
 
- 			
 
- 			// divide base nodes from children
 
- 			foreach ($section as $menu_item) {
 
- 				/* @var \ElggMenuItem $menu_item */
 
- 				$parent_name = $menu_item->getParentName();
 
- 				$menu_item_name = $menu_item->getName();
 
- 				
 
- 				if (!$parent_name) {
 
- 					// no parents so top level menu items
 
- 					$parents[$menu_item_name] = $menu_item;
 
- 				} else {
 
- 					$children[$menu_item_name] = $menu_item;
 
- 				}
 
- 				
 
- 				$all_menu_items[$menu_item_name] = $menu_item;
 
- 			} 
 
- 			
 
- 			if (empty($all_menu_items)) {
 
- 				// empty sections can be skipped
 
- 				continue;
 
- 			}
 
- 						
 
- 			if (empty($parents)) {
 
- 				// menu items without parents? That is sad.. report to the log
 
- 				$message = _elgg_services()->translator->translate('ElggMenuBuilder:Trees:NoParents');
 
- 				_elgg_services()->logger->notice($message);
 
- 				
 
- 				// skip section as without parents menu can not be drawn
 
- 				continue;
 
- 			}
 
- 						
 
- 			foreach ($children as $menu_item_name => $menu_item) {
 
- 				$parent_name = $menu_item->getParentName();
 
- 								
 
- 				if (!array_key_exists($parent_name, $all_menu_items)) {
 
- 					// orphaned child, inform authorities and skip to next item
 
- 					$message = _elgg_services()->translator->translate('ElggMenuBuilder:Trees:OrphanedChild', array($menu_item_name, $parent_name));
 
- 					_elgg_services()->logger->notice($message);
 
- 					
 
- 					continue;
 
- 				}
 
- 				
 
- 				if (!in_array($menu_item, $all_menu_items[$parent_name]->getData('children'))) {
 
- 					$all_menu_items[$parent_name]->addChild($menu_item);
 
- 					$menu_item->setParent($all_menu_items[$parent_name]);
 
- 				} else {
 
- 					// menu item already existed in parents children, report the duplicate registration
 
- 					$message = _elgg_services()->translator->translate('ElggMenuBuilder:Trees:DuplicateChild', array($menu_item_name));
 
- 					_elgg_services()->logger->notice($message);
 
- 					
 
- 					continue;
 
- 				}
 
- 			}
 
- 			// convert keys to indexes for first level of tree
 
- 			$parents = array_values($parents);
 
- 			$menu_tree[$key] = $parents;
 
- 		}
 
- 		$this->menu = $menu_tree;
 
- 	}
 
- 	/**
 
- 	 * Find the menu item that is currently selected
 
- 	 *
 
- 	 * @return \ElggMenuItem
 
- 	 */
 
- 	protected function findSelected() {
 
- 		// do we have a selected menu item already
 
- 		foreach ($this->menu as $menu_item) {
 
- 			if ($menu_item->getSelected()) {
 
- 				return $menu_item;
 
- 			}
 
- 		}
 
- 		// scan looking for a selected item
 
- 		foreach ($this->menu as $menu_item) {
 
- 			if ($menu_item->getHref()) {
 
- 				if (elgg_http_url_is_identical(current_page_url(), $menu_item->getHref())) {
 
- 					$menu_item->setSelected(true);
 
- 					return $menu_item;
 
- 				}
 
- 			}
 
- 		}
 
- 		return null;
 
- 	}
 
- 	/**
 
- 	 * Sort the menu sections and trees
 
- 	 *
 
- 	 * @param mixed $sort_by Sort type as string or php callback
 
- 	 * @return void
 
- 	 */
 
- 	protected function sort($sort_by) {
 
- 		// sort sections
 
- 		ksort($this->menu);
 
- 		switch ($sort_by) {
 
- 			case 'text':
 
- 				$sort_callback = array('\ElggMenuBuilder', 'compareByText');
 
- 				break;
 
- 			case 'name':
 
- 				$sort_callback = array('\ElggMenuBuilder', 'compareByName');
 
- 				break;
 
- 			case 'priority':
 
- 				$sort_callback = array('\ElggMenuBuilder', 'compareByPriority');
 
- 				break;
 
- 			case 'register':
 
- 				// use registration order - usort breaks this
 
- 				return;
 
- 				break;
 
- 			default:
 
- 				if (is_callable($sort_by)) {
 
- 					$sort_callback = $sort_by;
 
- 				} else {
 
- 					return;
 
- 				}
 
- 				break;
 
- 		}
 
- 		// sort each section
 
- 		foreach ($this->menu as $index => $section) {
 
- 			foreach ($section as $key => $node) {
 
- 				$section[$key]->setData('original_order', $key);
 
- 			}
 
- 			usort($section, $sort_callback);
 
- 			$this->menu[$index] = $section;
 
- 			// depth first traversal of tree
 
- 			foreach ($section as $root) {
 
- 				$stack = array();
 
- 				array_push($stack, $root);
 
- 				while (!empty($stack)) {
 
- 					$node = array_pop($stack);
 
- 					/* @var \ElggMenuItem $node */
 
- 					$node->sortChildren($sort_callback);
 
- 					$children = $node->getChildren();
 
- 					if ($children) {
 
- 						$stack = array_merge($stack, $children);
 
- 					}
 
- 				}
 
- 			}
 
- 		}
 
- 	}
 
- 	/**
 
- 	 * Compare two menu items by their display text
 
- 	 * HTML tags are stripped before comparison
 
- 	 *
 
- 	 * @param \ElggMenuItem $a Menu item
 
- 	 * @param \ElggMenuItem $b Menu item
 
- 	 * @return bool
 
- 	 */
 
- 	public static function compareByText($a, $b) {
 
- 		$at = strip_tags($a->getText());
 
- 		$bt = strip_tags($b->getText());
 
- 		$result = strnatcmp($at, $bt);
 
- 		if ($result === 0) {
 
- 			return $a->getData('original_order') - $b->getData('original_order');
 
- 		}
 
- 		return $result;
 
- 	}
 
- 	/**
 
- 	 * Compare two menu items by their identifiers
 
- 	 *
 
- 	 * @param \ElggMenuItem $a Menu item
 
- 	 * @param \ElggMenuItem $b Menu item
 
- 	 * @return bool
 
- 	 */
 
- 	public static function compareByName($a, $b) {
 
- 		$an = $a->getName();
 
- 		$bn = $b->getName();
 
- 		$result = strnatcmp($an, $bn);
 
- 		if ($result === 0) {
 
- 			return $a->getData('original_order') - $b->getData('original_order');
 
- 		}
 
- 		return $result;
 
- 	}
 
- 	/**
 
- 	 * Compare two menu items by their priority
 
- 	 *
 
- 	 * @param \ElggMenuItem $a Menu item
 
- 	 * @param \ElggMenuItem $b Menu item
 
- 	 * @return bool
 
- 	 * @since 1.9.0
 
- 	 */
 
- 	public static function compareByPriority($a, $b) {
 
- 		$aw = $a->getPriority();
 
- 		$bw = $b->getPriority();
 
- 		if ($aw == $bw) {
 
- 			return $a->getData('original_order') - $b->getData('original_order');
 
- 		}
 
- 		return $aw - $bw;
 
- 	}
 
- 	/**
 
- 	 * Compare two menu items by their priority
 
- 	 *
 
- 	 * @param \ElggMenuItem $a Menu item
 
- 	 * @param \ElggMenuItem $b Menu item
 
- 	 * @return bool
 
- 	 * @deprecated 1.9 Use compareByPriority()
 
- 	 */
 
- 	public static function compareByWeight($a, $b) {
 
- 		elgg_deprecated_notice("\ElggMenuBuilder::compareByWeight() deprecated by \ElggMenuBuilder::compareByPriority", 1.9);
 
- 		$aw = $a->getPriority();
 
- 		$bw = $b->getPriority();
 
- 		if ($aw == $bw) {
 
- 			return $a->getData('original_order') - $b->getData('original_order');
 
- 		}
 
- 		return $aw - $bw;
 
- 	}
 
- }
 
 
  |