1 | <?php |
||
2 | namespace Elgg\Menu; |
||
3 | |||
4 | use Elgg\PluginHooksService; |
||
5 | use Elgg\Config; |
||
6 | use ElggMenuBuilder; |
||
7 | use ElggMenuItem; |
||
8 | |||
9 | /** |
||
10 | * Methods to construct and prepare menus for rendering |
||
11 | */ |
||
12 | class Service { |
||
13 | |||
14 | /** |
||
15 | * @var PluginHooksService |
||
16 | */ |
||
17 | private $hooks; |
||
18 | |||
19 | /** |
||
20 | * @var Config |
||
21 | */ |
||
22 | private $config; |
||
23 | |||
24 | /** |
||
25 | * Constructor |
||
26 | * |
||
27 | * @param PluginHooksService $hooks Plugin hooks |
||
28 | * @param Config $config Elgg config |
||
29 | * @access private |
||
30 | * @internal Do not use. Use `elgg()->menus`. |
||
31 | */ |
||
32 | 3 | public function __construct(PluginHooksService $hooks, Config $config) { |
|
33 | 3 | $this->hooks = $hooks; |
|
34 | 3 | $this->config = $config; |
|
35 | 3 | } |
|
36 | |||
37 | /** |
||
38 | * Build a full menu, pulling items from configuration and the "register" menu hooks. |
||
39 | * |
||
40 | * Parameters are filtered by the "parameters" hook. |
||
41 | * |
||
42 | * @param string $name Menu name |
||
43 | * @param array $params Hook/view parameters |
||
44 | * |
||
45 | * @return Menu |
||
46 | */ |
||
47 | 33 | public function getMenu($name, array $params = []) { |
|
48 | 33 | return $this->prepareMenu($this->getUnpreparedMenu($name, $params)); |
|
49 | } |
||
50 | |||
51 | /** |
||
52 | * Build an unprepared menu. |
||
53 | * |
||
54 | * @param string $name Menu name |
||
55 | * @param array $params Hook/view parameters |
||
56 | * |
||
57 | * @return UnpreparedMenu |
||
58 | */ |
||
59 | 33 | public function getUnpreparedMenu($name, array $params = []) { |
|
60 | 33 | $menus = $this->config->menus; |
|
61 | |||
62 | 33 | $items = $this->prepareMenuItems(elgg_extract('items', $params, [])); |
|
63 | 33 | unset($params['items']); |
|
64 | |||
65 | 33 | if ($menus && isset($menus[$name])) { |
|
0 ignored issues
–
show
|
|||
66 | 12 | $registered_items = elgg_extract($name, $menus, []); |
|
67 | 12 | $items = array_merge($items, $registered_items); |
|
68 | } |
||
69 | |||
70 | 33 | $params['name'] = $name; |
|
71 | |||
72 | 33 | $params = $this->hooks->trigger('parameters', "menu:$name", $params, $params); |
|
73 | |||
74 | 33 | if (!isset($params['sort_by'])) { |
|
75 | 17 | $params['sort_by'] = 'text'; |
|
76 | } |
||
77 | |||
78 | 33 | $items = $this->hooks->trigger('register', "menu:$name", $params, $items); |
|
79 | |||
80 | 33 | return new UnpreparedMenu($params, $items); |
|
81 | } |
||
82 | |||
83 | /** |
||
84 | * Split a menu into sections, and pass it through the "prepare" hook |
||
85 | * |
||
86 | * @param UnpreparedMenu $menu Menu |
||
87 | * |
||
88 | * @return Menu |
||
89 | */ |
||
90 | 33 | public function prepareMenu(UnpreparedMenu $menu) { |
|
91 | 33 | $name = $menu->getName(); |
|
92 | 33 | $params = $menu->getParams(); |
|
93 | 33 | $sort_by = $menu->getSortBy(); |
|
94 | |||
95 | 33 | $builder = new ElggMenuBuilder($menu->getItems()); |
|
96 | 33 | $params['menu'] = $builder->getMenu($sort_by); |
|
97 | 33 | $params['selected_item'] = $builder->getSelected(); |
|
98 | |||
99 | 33 | $params['menu'] = $this->hooks->trigger('prepare', "menu:$name", $params, $params['menu']); |
|
100 | |||
101 | 33 | 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 | function combineMenus(array $names = [], array $params = [], $new_name = '') { |
||
0 ignored issues
–
show
|
|||
117 | if (!$new_name) { |
||
118 | $new_name = implode('__', $names); |
||
119 | } |
||
120 | |||
121 | $all_items = []; |
||
122 | foreach ($names as $name) { |
||
123 | $items = $this->getUnpreparedMenu($name, $params)->getItems(); |
||
124 | |||
125 | foreach ($items as $item) { |
||
126 | $section = $item->getSection(); |
||
127 | if ($section == 'default') { |
||
128 | $item->setSection($name); |
||
129 | } |
||
130 | $item->setData('menu_name', $name); |
||
131 | $all_items[] = $item; |
||
132 | } |
||
133 | } |
||
134 | |||
135 | $params['name'] = $new_name; |
||
136 | |||
137 | return new UnpreparedMenu($params, $all_items); |
||
138 | } |
||
139 | |||
140 | /** |
||
141 | * Prepare menu items |
||
142 | * |
||
143 | * @param array $items An array of ElggMenuItem instances or menu item factory options |
||
144 | * @return ElggMenuItem[] |
||
145 | */ |
||
146 | 33 | public function prepareMenuItems(array $items = []) { |
|
147 | 33 | $prepared_items = []; |
|
148 | |||
149 | 33 | foreach ($items as $item) { |
|
150 | 2 | if (is_array($item)) { |
|
151 | 2 | $options = $item; |
|
152 | 2 | $item = ElggMenuItem::factory($options); |
|
153 | } |
||
154 | |||
155 | 2 | if (!$item instanceof ElggMenuItem) { |
|
156 | continue; |
||
157 | } |
||
158 | |||
159 | 2 | $prepared_items[] = $item; |
|
160 | } |
||
161 | |||
162 | 33 | return $prepared_items; |
|
163 | } |
||
164 | } |
||
165 |
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.