Total Complexity | 102 |
Total Lines | 579 |
Duplicated Lines | 0 % |
Changes | 2 | ||
Bugs | 1 | Features | 0 |
Complex classes like admin_ui often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use admin_ui, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
22 | class admin_ui |
||
23 | { |
||
24 | /** |
||
25 | * Methods callable via menuaction |
||
26 | * @var array |
||
27 | */ |
||
28 | public $public_functions = array( |
||
29 | 'index' => true, |
||
30 | ); |
||
31 | |||
32 | /** |
||
33 | * Reference to global accounts object |
||
34 | * |
||
35 | * @var Api\Accounts |
||
36 | */ |
||
37 | private static $accounts; |
||
38 | |||
39 | /** |
||
40 | * New index page |
||
41 | * |
||
42 | * @param array $content |
||
43 | */ |
||
44 | public function index(array $content=null) |
||
45 | { |
||
46 | if (admin_statistics::check(false)) |
||
47 | { |
||
48 | $_GET['load'] = 'admin.admin_statistics.submit'; |
||
49 | $_GET['ajax'] = 'false'; |
||
50 | $_GET['required'] = 'true'; |
||
51 | } |
||
52 | $tpl = new Etemplate('admin.index'); |
||
53 | |||
54 | if (!is_array($content)) $content = array(); |
||
55 | $content['nm'] = array( |
||
56 | 'get_rows' => 'admin_ui::get_users', |
||
57 | 'no_cat' => true, |
||
58 | 'no_filter2' => true, |
||
59 | 'filter_no_lang' => true, |
||
60 | 'lettersearch' => true, |
||
61 | 'order' => 'account_lid', |
||
62 | 'sort' => 'ASC', |
||
63 | 'row_id' => 'account_id', |
||
64 | 'default_cols' => '!account_id,created,account_lastlogin,account_lastloginfrom,account_lastpwd_change', |
||
65 | 'actions' => self::user_actions(), |
||
66 | 'placeholder_actions' => array('add') |
||
67 | ); |
||
68 | $content['groups'] = array( |
||
69 | 'get_rows' => 'admin_ui::get_groups', |
||
70 | 'no_cat' => true, |
||
71 | 'no_filter' => true, |
||
72 | 'no_filter2' => true, |
||
73 | 'row_id' => 'account_id', |
||
74 | 'actions' => self::group_actions(), |
||
75 | 'placeholder_actions' => array('add') |
||
76 | ); |
||
77 | |||
78 | //$content['msg'] = 'Hi Ralf ;-)'; |
||
79 | $sel_options['tree'] = $this->tree_data(); |
||
|
|||
80 | $sel_options['filter'] = array('' => lang('All groups')); |
||
81 | foreach(self::$accounts->search(array( |
||
82 | 'type' => 'groups', |
||
83 | 'start' => false, |
||
84 | 'order' => 'account_lid', |
||
85 | 'sort' => 'ASC', |
||
86 | )) as $data) |
||
87 | { |
||
88 | $sel_options['filter'][$data['account_id']] = empty($data['account_description']) ? $data['account_lid'] : array( |
||
89 | 'label' => $data['account_lid'], |
||
90 | 'title' => $data['account_description'], |
||
91 | ); |
||
92 | } |
||
93 | $sel_options['account_primary_group'] = $sel_options['filter']; |
||
94 | unset($sel_options['account_primary_group']['']); |
||
95 | |||
96 | $tpl->setElementAttribute('tree', 'actions', self::tree_actions()); |
||
97 | |||
98 | // switching between iframe and nm/accounts-list depending on load parameter |
||
99 | // important for first time load eg. from an other application calling it's site configuration |
||
100 | $tpl->setElementAttribute('iframe', 'disabled', empty($_GET['load'])); |
||
101 | $content['iframe'] = 'about:blank'; // we show accounts-list be default now |
||
102 | if (!empty($_GET['load'])) |
||
103 | { |
||
104 | $vars = $_GET; |
||
105 | $vars['menuaction'] = $vars['load']; |
||
106 | unset($vars['load']); |
||
107 | $content[$vars['ajax'] ? 'ajax_target':'iframe'] = Egw::link('/index.php', $vars); |
||
108 | } |
||
109 | |||
110 | $tpl->exec('admin.admin_ui.index', $content, $sel_options); |
||
111 | } |
||
112 | |||
113 | /** |
||
114 | * Actions on tree / groups |
||
115 | * |
||
116 | * @return array |
||
117 | */ |
||
118 | public static function tree_actions() |
||
131 | } |
||
132 | |||
133 | /** |
||
134 | * Actions on users |
||
135 | * |
||
136 | * @return array |
||
137 | */ |
||
138 | public static function user_actions() |
||
139 | { |
||
140 | static $actions = null; |
||
141 | |||
142 | if (!isset($actions)) |
||
143 | { |
||
144 | $actions = array( |
||
145 | 'edit' => array( |
||
146 | 'caption' => 'Open', |
||
147 | 'default' => true, |
||
148 | 'allowOnMultiple' => false, |
||
149 | 'onExecute' => 'javaScript:app.admin.account', |
||
150 | 'group' => $group=0, |
||
151 | ), |
||
152 | 'add' => array( |
||
153 | 'caption' => 'Add user', |
||
154 | 'onExecute' => 'javaScript:app.admin.account', |
||
155 | 'group' => $group, |
||
156 | ), |
||
157 | 'copy' => array( |
||
158 | 'caption' => 'Copy', |
||
159 | 'url' => 'menuaction=addressbook.addressbook_ui.edit&makecp=1&contact_id=$id', |
||
160 | 'onExecute' => 'javaScript:app.admin.account', |
||
161 | 'allowOnMultiple' => false, |
||
162 | 'icon' => 'copy', |
||
163 | ), |
||
164 | ); |
||
165 | // generate urls for add/edit accounts via addressbook |
||
166 | $edit = Link::get_registry('addressbook', 'edit'); |
||
167 | $edit['account_id'] = '$id'; |
||
168 | foreach($edit as $name => $val) |
||
169 | { |
||
170 | $actions['edit']['url'] .= ($actions['edit']['url'] ? '&' : '').$name.'='.$val; |
||
171 | } |
||
172 | unset($edit['account_id']); |
||
173 | $edit['owner'] = 0; |
||
174 | foreach($edit as $name => $val) |
||
175 | { |
||
176 | $actions['add']['url'] .= ($actions['edit']['url'] ? '&' : '').$name.'='.$val; |
||
177 | } |
||
178 | ++$group; |
||
179 | // supporting both old way using $GLOBALS['menuData'] and new just returning data in hook |
||
180 | $apps = array_unique(array_merge(array('admin'), Api\Hooks::implemented('edit_user'))); |
||
181 | foreach($apps as $app) |
||
182 | { |
||
183 | $GLOBALS['menuData'] = $data = array(); |
||
184 | $data = Api\Hooks::single('edit_user', $app); |
||
185 | if (!is_array($data)) $data = $GLOBALS['menuData']; |
||
186 | foreach($data as $item) |
||
187 | { |
||
188 | // allow hook to return "real" actions, but still support legacy: description, url, extradata, options |
||
189 | if (empty($item['caption'])) |
||
190 | { |
||
191 | $item['caption'] = $item['description']; |
||
192 | unset($item['description']); |
||
193 | } |
||
194 | if (isset($item['url']) && isset($item['extradata'])) |
||
195 | { |
||
196 | $item['url'] = $item['extradata'].'&account_id=$id'; |
||
197 | $item['id'] = substr($item['extradata'], 11); |
||
198 | unset($item['extradata']); |
||
199 | $matches = null; |
||
200 | if ($item['options'] && preg_match('/(egw_openWindowCentered2?|window.open)\([^)]+,(\d+),(\d+).*(title="([^"]+)")?/', $item['options'], $matches)) |
||
201 | { |
||
202 | $item['popup'] = $matches[2].'x'.$matches[3]; |
||
203 | if (isset($matches[5])) $item['tooltip'] = $matches[5]; |
||
204 | unset($item['options']); |
||
205 | } |
||
206 | } |
||
207 | if (empty($item['icon'])) $item['icon'] = $app.'/navbar'; |
||
208 | if (empty($item['group'])) $item['group'] = $group; |
||
209 | if (empty($item['onExecute'])) $item['onExecute'] = $item['popup'] ? |
||
210 | 'javaScript:nm_action' : 'javaScript:app.admin.iframe_location'; |
||
211 | if (!isset($item['allowOnMultiple'])) $item['allowOnMultiple'] = false; |
||
212 | |||
213 | $actions[$item['id']] = $item; |
||
214 | } |
||
215 | } |
||
216 | $actions['delete'] = array( |
||
217 | 'caption' => 'Delete', |
||
218 | 'group' => ++$group, |
||
219 | 'popup' => '615x600', |
||
220 | 'url' => 'menuaction=admin.admin_account.delete&account_id=$id', |
||
221 | 'allowOnMultiple' => false, |
||
222 | ); |
||
223 | } |
||
224 | //error_log(__METHOD__."() actions=".array2string($actions)); |
||
225 | return $actions; |
||
226 | } |
||
227 | |||
228 | /** |
||
229 | * Actions on groups |
||
230 | * |
||
231 | * @return array |
||
232 | */ |
||
233 | public static function group_actions() |
||
234 | { |
||
235 | $user_actions = self::user_actions(); |
||
236 | $actions = array( |
||
237 | 'view' => array( |
||
238 | 'onExecute' => 'javaScript:app.admin.group', |
||
239 | 'caption' => 'Show members', |
||
240 | 'default' => true, |
||
241 | 'group' => $group=1, |
||
242 | 'allowOnMultiple' => false |
||
243 | ), |
||
244 | 'add' => array( |
||
245 | 'group' => $group, |
||
246 | )+$user_actions['add'], |
||
247 | 'acl' => array( |
||
248 | 'onExecute' => 'javaScript:app.admin.group', |
||
249 | 'caption' => 'Access control', |
||
250 | 'url' => 'menuaction=admin.admin_acl.index&account_id=$id', |
||
251 | 'popup' => '900x450', |
||
252 | 'icon' => 'lock', |
||
253 | 'group' => 2, |
||
254 | 'allowOnMultiple' => false |
||
255 | ), |
||
256 | ); |
||
257 | if (!$GLOBALS['egw']->acl->check('account_access',64,'admin')) // no rights to set ACL-rights |
||
258 | { |
||
259 | $actions['deny'] = array( |
||
260 | 'caption' => 'Deny access', |
||
261 | 'url' => 'menuaction=admin.admin_denyaccess.list_apps&account_id=$id', |
||
262 | 'onExecute' => 'javaScript:app.admin.group', |
||
263 | 'icon' => 'cancel', |
||
264 | 'group' => 2, |
||
265 | 'allowOnMultiple' => false |
||
266 | ); |
||
267 | } |
||
268 | |||
269 | $group = 5; // allow to place actions in different groups by hook, this is the default |
||
270 | |||
271 | // supporting both old way using $GLOBALS['menuData'] and new just returning data in hook |
||
272 | $apps = array_unique(array_merge(array('admin'), Api\Hooks::implemented('edit_group'))); |
||
273 | foreach($apps as $app) |
||
274 | { |
||
275 | $GLOBALS['menuData'] = $data = array(); |
||
276 | $data = Api\Hooks::single('edit_group', $app); |
||
277 | if (!is_array($data)) $data = $GLOBALS['menuData']; |
||
278 | |||
279 | foreach($data as $item) |
||
280 | { |
||
281 | // allow hook to return "real" actions, but still support legacy: description, url, extradata, options |
||
282 | if (empty($item['caption'])) |
||
283 | { |
||
284 | $item['caption'] = $item['description']; |
||
285 | unset($item['description']); |
||
286 | } |
||
287 | if (isset($item['url']) && isset($item['extradata'])) |
||
288 | { |
||
289 | $item['url'] = $item['extradata'].'&account_id=$id'; |
||
290 | $item['id'] = substr($item['extradata'], 11); |
||
291 | unset($item['extradata']); |
||
292 | $matches = null; |
||
293 | if ($item['options'] && preg_match('/(egw_openWindowCentered2?|window.open)\([^)]+,(\d+),(\d+).*(title="([^"]+)")?/', $item['options'], $matches)) |
||
294 | { |
||
295 | $item['popup'] = $matches[2].'x'.$matches[3]; |
||
296 | $item['onExecute'] = 'javaScript:nm_action'; |
||
297 | if (isset($matches[5])) $item['tooltip'] = $matches[5]; |
||
298 | unset($item['options']); |
||
299 | } |
||
300 | } |
||
301 | if (empty($item['icon'])) $item['icon'] = $app.'/navbar'; |
||
302 | if (empty($item['group'])) $item['group'] = $group; |
||
303 | if (empty($item['onExecute'])) $item['onExecute'] = 'javaScript:app.admin.group'; |
||
304 | if (!isset($item['allowOnMultiple'])) $item['allowOnMultiple'] = false; |
||
305 | |||
306 | $actions[$item['id']] = $item; |
||
307 | } |
||
308 | } |
||
309 | return $actions; |
||
310 | } |
||
311 | |||
312 | /** |
||
313 | * Callback for nextmatch to fetch users |
||
314 | * |
||
315 | * @param array $query |
||
316 | * @param array &$rows=null |
||
317 | * @return int total number of rows available |
||
318 | */ |
||
319 | public static function get_users(array $query, array &$rows=null) |
||
320 | { |
||
321 | $params = array( |
||
322 | 'type' => (int)$query['filter'] ? (int)$query['filter'] : 'accounts', |
||
323 | 'start' => $query['start'], |
||
324 | 'offset' => $query['num_rows'], |
||
325 | 'order' => $query['order'], |
||
326 | 'sort' => $query['sort'], |
||
327 | 'active' => !empty($query['active']) ? $query['active'] : false, |
||
328 | ); |
||
329 | if ($query['searchletter']) |
||
330 | { |
||
331 | $params['query'] = $query['searchletter']; |
||
332 | $params['query_type'] = 'start'; |
||
333 | } |
||
334 | elseif($query['search']) |
||
335 | { |
||
336 | $params['query'] = $query['search']; |
||
337 | $params['query_type'] = 'all'; |
||
338 | } |
||
339 | |||
340 | $rows = array_values(self::$accounts->search($params)); |
||
341 | //error_log(__METHOD__."() accounts->search(".array2string($params).") total=".self::$accounts->total); |
||
342 | |||
343 | foreach($rows as &$row) |
||
344 | { |
||
345 | $row['status'] = self::$accounts->is_expired($row) ? |
||
346 | lang('Expired').' '.Api\DateTime::to($row['account_expires'], true) : |
||
347 | (!self::$accounts->is_active($row) ? lang('Disabled') : |
||
348 | ($row['account_expires'] != -1 ? lang('Expires').' '.Api\DateTime::to($row['account_expires'], true) : |
||
349 | lang('Enabled'))); |
||
350 | |||
351 | if (!self::$accounts->is_active($row)) $row['status_class'] = 'adminAccountInactive'; |
||
352 | } |
||
353 | |||
354 | return self::$accounts->total; |
||
355 | } |
||
356 | |||
357 | /** |
||
358 | * Callback for the nextmatch to get groups |
||
359 | */ |
||
360 | public static function get_groups(&$query, &$rows) |
||
361 | { |
||
362 | $groups = $GLOBALS['egw']->accounts->search(array( |
||
363 | 'type' => 'groups', |
||
364 | 'query' => $query['search'], |
||
365 | 'order' => $query['order'], |
||
366 | 'sort' => $query['sort'], |
||
367 | 'start' => (int)$query['start'], |
||
368 | 'offset' => (int)$query['num_rows'] |
||
369 | )); |
||
370 | |||
371 | $apps = array(); |
||
372 | foreach($GLOBALS['egw_info']['apps'] as $app => $data) |
||
373 | { |
||
374 | if (!$data['enabled'] || !$data['status'] || $data['status'] == 3) |
||
375 | { |
||
376 | continue; // do NOT show disabled apps, or our API (status = 3) |
||
377 | } |
||
378 | |||
379 | $apps[] = $app; |
||
380 | } |
||
381 | |||
382 | $rows = array(); |
||
383 | foreach($groups as &$group) |
||
384 | { |
||
385 | $run_rights = $GLOBALS['egw']->acl->get_user_applications($group['account_id'], false, false); |
||
386 | foreach($apps as $app) |
||
387 | { |
||
388 | if((boolean)$run_rights[$app]) |
||
389 | { |
||
390 | $group['apps'][] = $app; |
||
391 | } |
||
392 | } |
||
393 | |||
394 | $group['members'] = $GLOBALS['egw']->accounts->members($group['account_id'],true); |
||
395 | $rows[] = $group; |
||
396 | } |
||
397 | |||
398 | return $GLOBALS['egw']->accounts->total; |
||
399 | } |
||
400 | |||
401 | /** |
||
402 | * Autoload tree from $_GET['id'] on |
||
403 | */ |
||
404 | public static function ajax_tree() |
||
407 | } |
||
408 | |||
409 | /** |
||
410 | * Get data for navigation tree |
||
411 | * |
||
412 | * Example: |
||
413 | * array( |
||
414 | * 'id' => 0, 'item' => array( |
||
415 | * array('id' => '/INBOX', 'text' => 'INBOX', 'tooltip' => 'Your inbox', 'open' => 1, 'im1' => 'kfm_home.png', 'im2' => 'kfm_home.png', 'child' => '1', 'item' => array( |
||
416 | * array('id' => '/INBOX/sub', 'text' => 'sub', 'im0' => 'folderClosed.gif'), |
||
417 | * array('id' => '/INBOX/sub2', 'text' => 'sub2', 'im0' => 'folderClosed.gif'), |
||
418 | * )), |
||
419 | * array('id' => '/user', 'text' => 'user', 'child' => '1', 'item' => array( |
||
420 | * array('id' => '/user/birgit', 'text' => 'birgit', 'im0' => 'folderClosed.gif'), |
||
421 | * )), |
||
422 | * )); |
||
423 | * |
||
424 | * @param string $root ='/' |
||
425 | * @return array |
||
426 | */ |
||
427 | public static function tree_data($root = '/') |
||
428 | { |
||
429 | $tree = array(Tree::ID => $root === '/' ? 0 : $root, Tree::CHILDREN => array(), 'child' => 1); |
||
430 | |||
431 | if ($root == '/') |
||
432 | { |
||
433 | $hook_data = self::call_hook(); |
||
434 | foreach($hook_data as $app => $app_data) |
||
435 | { |
||
436 | if(!is_array($app_data)) |
||
437 | { |
||
438 | // Application has no data |
||
439 | continue; |
||
440 | } |
||
441 | foreach($app_data as $text => $data) |
||
442 | { |
||
443 | if (!is_array($data)) |
||
444 | { |
||
445 | $data = array( |
||
446 | 'link' => $data, |
||
447 | ); |
||
448 | } |
||
449 | if (empty($data[Tree::LABEL])) $data[Tree::LABEL] = $text; |
||
450 | if (empty($data[Tree::ID])) |
||
451 | { |
||
452 | $data['id'] = $root.($app == 'admin' ? 'admin' : 'apps/'.$app).'/'; |
||
453 | $matches = null; |
||
454 | if (preg_match_all('/(menuaction|load)=([^&]+)/', $data['link'], $matches)) |
||
455 | { |
||
456 | $data[Tree::ID] .= $matches[2][(int)array_search('load', $matches[1])]; |
||
457 | } |
||
458 | } |
||
459 | if (!empty($data['icon'])) |
||
460 | { |
||
461 | $icon = Etemplate\Widget\Tree::imagePath($data['icon']); |
||
462 | if ($data['child'] || $data[Tree::CHILDREN]) |
||
463 | { |
||
464 | $data[Tree::IMAGE_FOLDER_OPEN] = $data[Tree::IMAGE_FOLDER_CLOSED] = $icon; |
||
465 | } |
||
466 | else |
||
467 | { |
||
468 | $data[Tree::IMAGE_LEAF] = $icon; |
||
469 | } |
||
470 | } |
||
471 | unset($data['icon']); |
||
472 | $parent =& $tree[Tree::CHILDREN]; |
||
473 | $parts = explode('/', $data[Tree::ID]); |
||
474 | if ($data[Tree::ID][0] == '/') array_shift($parts); // remove root |
||
475 | array_pop($parts); |
||
476 | $path = ''; |
||
477 | foreach($parts as $part) |
||
478 | { |
||
479 | $path .= ($path == '/' ? '' : '/').$part; |
||
480 | if (!isset($parent[$path])) |
||
481 | { |
||
482 | $icon = Etemplate\Widget\Tree::imagePath($part == 'apps' ? Api\Image::find('api', 'home') : |
||
483 | (($i=Api\Image::find($part, 'navbar')) ? $i : Api\Image::find('api', 'nonav'))); |
||
484 | $parent[$path] = array( |
||
485 | Tree::ID => $path, |
||
486 | Tree::LABEL => $part == 'apps' ? lang('Applications') : lang($part), |
||
487 | //'im0' => 'folderOpen.gif', |
||
488 | Tree::IMAGE_FOLDER_OPEN => $icon, |
||
489 | Tree::IMAGE_FOLDER_CLOSED => $icon, |
||
490 | Tree::CHILDREN => array(), |
||
491 | 'child' => 1, |
||
492 | ); |
||
493 | if ($path == '/admin') $parent[$path]['open'] = true; |
||
494 | } |
||
495 | $parent =& $parent[$path][Tree::CHILDREN]; |
||
496 | } |
||
497 | $data[Tree::LABEL] = lang($data[Tree::LABEL]); |
||
498 | if (!empty($data['tooltip'])) $data['tooltip'] = lang($data['tooltip']); |
||
499 | // make sure keys are unique, as we overwrite tree entries otherwise |
||
500 | if (isset($parent[$data[Tree::ID]])) $data[Tree::ID] .= md5($data['link']); |
||
501 | $parent[$data[Tree::ID]] = self::fix_userdata($data); |
||
502 | } |
||
503 | } |
||
504 | } |
||
505 | elseif ($root == '/groups') |
||
506 | { |
||
507 | foreach($GLOBALS['egw']->accounts->search(array( |
||
508 | 'type' => 'groups', |
||
509 | 'order' => 'account_lid', |
||
510 | 'sort' => 'ASC', |
||
511 | )) as $group) |
||
512 | { |
||
513 | $tree[Tree::CHILDREN][] = self::fix_userdata(array( |
||
514 | Tree::LABEL => $group['account_lid'], |
||
515 | Tree::TOOLTIP => $group['account_description'], |
||
516 | Tree::ID => $root.'/'.$group['account_id'], |
||
517 | )); |
||
518 | } |
||
519 | } |
||
520 | self::strip_item_keys($tree[Tree::CHILDREN]); |
||
521 | //_debug_array($tree); exit; |
||
522 | return $tree; |
||
523 | } |
||
524 | |||
525 | /** |
||
526 | * Fix userdata as understood by tree |
||
527 | * |
||
528 | * @param array $data |
||
529 | * @return array |
||
530 | */ |
||
531 | private static function fix_userdata(array $data) |
||
532 | { |
||
533 | if(!$data[Tree::LABEL]) |
||
534 | { |
||
535 | $data[Tree::LABEL] = $data['text']; |
||
536 | } |
||
537 | // store link as userdata, maybe we should store everything not directly understood by tree this way ... |
||
538 | foreach(array_diff_key($data, array_flip(array( |
||
539 | Tree::ID,Tree::LABEL,Tree::TOOLTIP,'im0','im1','im2','item','child','select','open','call', |
||
540 | ))) as $name => $content) |
||
541 | { |
||
542 | $data['userdata'][] = array( |
||
543 | 'name' => $name, |
||
544 | 'content' => $content, |
||
545 | ); |
||
546 | unset($data[$name]); |
||
547 | } |
||
548 | return $data; |
||
549 | } |
||
550 | |||
551 | /** |
||
552 | * Attribute 'item' has to be an array |
||
553 | * |
||
554 | * @param array $items |
||
555 | */ |
||
556 | private static function strip_item_keys(array &$items) |
||
557 | { |
||
558 | $items = array_values($items); |
||
559 | foreach($items as &$item) |
||
560 | { |
||
561 | if (is_array($item) && isset($item['item'])) |
||
562 | { |
||
563 | self::strip_item_keys($item['item']); |
||
564 | } |
||
565 | } |
||
566 | } |
||
567 | |||
568 | public static $hook_data = array(); |
||
569 | /** |
||
570 | * Return data from regular admin hook calling display_section() instead of returning it |
||
571 | * |
||
572 | * @return array appname => array of label => link/data pairs |
||
573 | */ |
||
574 | protected static function call_hook() |
||
575 | { |
||
576 | self::$hook_data = array(); |
||
577 | function display_section($appname,$file,$file2=False) |
||
578 | { |
||
579 | admin_ui::$hook_data[$appname] = $file2 ? $file2 : $file; |
||
580 | //error_log(__METHOD__."(".array2string(func_get_args()).")"); |
||
581 | } |
||
582 | self::$hook_data = array_merge(Api\Hooks::process('admin', array('admin')), self::$hook_data); |
||
583 | |||
584 | // sort apps alphabetic by their title / Api\Translation of app-name |
||
585 | uksort(self::$hook_data, function($a, $b) |
||
586 | { |
||
587 | return strcasecmp(lang($a), lang($b)); |
||
588 | }); |
||
589 | // make sure admin is first |
||
590 | self::$hook_data = array_merge(array('admin' => self::$hook_data['admin']), self::$hook_data); |
||
591 | |||
592 | return self::$hook_data; |
||
593 | } |
||
594 | |||
595 | /** |
||
596 | * Init static variables |
||
597 | */ |
||
598 | public static function init_static() |
||
601 | } |
||
602 | } |
||
603 | admin_ui::init_static(); |
||
604 |