1<?php 2 3namespace Elgg\Menu; 4 5use Elgg\PluginHooksService; 6use Elgg\Config; 7use ElggMenuBuilder; 8use ElggMenuItem; 9 10/** 11 * Methods to construct and prepare menus for rendering 12 */ 13class Service { 14 15 /** 16 * @var PluginHooksService 17 */ 18 private $hooks; 19 20 /** 21 * @var Config 22 */ 23 private $config; 24 25 /** 26 * Constructor 27 * 28 * @param PluginHooksService $hooks Plugin hooks 29 * @param Config $config Elgg config 30 */ 31 public function __construct(PluginHooksService $hooks, Config $config) { 32 $this->hooks = $hooks; 33 $this->config = $config; 34 } 35 36 /** 37 * Build a full menu, pulling items from configuration and the "register" menu hooks. 38 * 39 * Parameters are filtered by the "parameters" hook. 40 * 41 * @param string $name Menu name 42 * @param array $params Hook/view parameters 43 * 44 * @return Menu 45 */ 46 public function getMenu($name, array $params = []) { 47 return $this->prepareMenu($this->getUnpreparedMenu($name, $params)); 48 } 49 50 /** 51 * Build an unprepared menu. 52 * 53 * @param string $name Menu name 54 * @param array $params Hook/view parameters 55 * 56 * @return UnpreparedMenu 57 */ 58 public function getUnpreparedMenu($name, array $params = []) { 59 $items = $this->prepareMenuItems(elgg_extract('items', $params, [])); 60 unset($params['items']); 61 62 $registered_items = elgg_extract($name, $this->config->menus); 63 if (is_array($registered_items)) { 64 $items->merge($registered_items); 65 } 66 67 $params['name'] = $name; 68 69 $params = $this->hooks->trigger('parameters', "menu:$name", $params, $params); 70 71 if (!isset($params['sort_by'])) { 72 $params['sort_by'] = 'priority'; 73 } 74 75 $items = $this->hooks->trigger('register', "menu:$name", $params, $items); 76 77 return new UnpreparedMenu($params, $items); 78 } 79 80 /** 81 * Split a menu into sections, and pass it through the "prepare" hook 82 * 83 * @param UnpreparedMenu $menu Menu 84 * 85 * @return Menu 86 */ 87 public function prepareMenu(UnpreparedMenu $menu) { 88 $name = $menu->getName(); 89 $params = $menu->getParams(); 90 $sort_by = $menu->getSortBy(); 91 $selected_menu_item_name = elgg_extract('selected_item_name', $params, ''); 92 93 $builder = new ElggMenuBuilder($menu->getItems()); 94 $builder->setSelected($selected_menu_item_name); 95 96 $params['menu'] = $builder->getMenu($sort_by); 97 $params['selected_item'] = $builder->getSelected(); 98 99 $params['menu'] = $this->hooks->trigger('prepare', "menu:$name", $params, $params['menu']); 100 101 return new Menu($params); 102 } 103 104 /** 105 * Combine several menus into one 106 * 107 * Unprepared menus will be built separately, then combined, with items reassigned to sections 108 * named after their origin menu. The returned menu must be prepared before display. 109 * 110 * @param string[] $names Menu names 111 * @param array $params Menu params 112 * @param string $new_name Combined menu name (used for the prepare hook) 113 * 114 * @return UnpreparedMenu 115 */ 116 public function combineMenus(array $names = [], array $params = [], $new_name = '') { 117 if (!$new_name) { 118 $new_name = implode('__', $names); 119 } 120 121 $all_items = new MenuItems(); 122 123 foreach ($names as $name) { 124 $items = $this->getUnpreparedMenu($name, $params)->getItems(); 125 126 foreach ($items as $item) { 127 $section = $item->getSection(); 128 if ($section == 'default') { 129 $item->setSection($name); 130 } 131 $item->setData('menu_name', $name); 132 133 $all_items->add($item); 134 } 135 } 136 137 $params['name'] = $new_name; 138 139 return new UnpreparedMenu($params, $all_items); 140 } 141 142 /** 143 * Prepare menu items 144 * 145 * @param array $items An array of ElggMenuItem instances or menu item factory options 146 * 147 * @return MenuItems 148 */ 149 public function prepareMenuItems($items = []) { 150 $prepared_items = new MenuItems(); 151 152 foreach ($items as $item) { 153 if (is_array($item)) { 154 $options = $item; 155 $item = ElggMenuItem::factory($options); 156 } 157 158 if (!$item instanceof ElggMenuItem) { 159 continue; 160 } 161 162 $prepared_items->add($item); 163 } 164 165 return $prepared_items; 166 } 167} 168