Passed
Push — master ( c0a3a7...3b84a4 )
by Jeroen
58:51
created

elgg_get_view_extensions()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
ccs 0
cts 3
cp 0
crap 2
1
<?php
2
/**
3
 * Elgg's view system.
4
 *
5
 * The view system is the primary templating engine in Elgg and renders
6
 * all output.  Views are short, parameterised PHP scripts for displaying
7
 * output that can be regsitered, overridden, or extended.  The view type
8
 * determines the output format and location of the files that renders the view.
9
 *
10
 * Elgg uses a two step process to render full output: first
11
 * content-specific elements are rendered, then the resulting
12
 * content is inserted into a layout and displayed.  This makes it
13
 * easy to maintain a consistent look on all pages.
14
 *
15
 * A view corresponds to a single file on the filesystem and the views
16
 * name is its directory structure.  A file in
17
 * <code>mod/plugins/views/default/myplugin/example.php</code>
18
 * is called by saying (with the default viewtype):
19
 * <code>echo elgg_view('myplugin/example');</code>
20
 *
21
 * View names that are registered later override those that are
22
 * registered earlier.  For plugins this corresponds directly
23
 * to their load order: views in plugins lower in the list override
24
 * those higher in the list.
25
 *
26
 * Plugin views belong in the views/ directory under an appropriate
27
 * viewtype.  Views are automatically registered.
28
 *
29
 * Views can be embedded-you can call a view from within a view.
30
 * Views can also be prepended or extended by any other view.
31
 *
32
 * Any view can extend any other view if registered with
33
 * {@link elgg_extend_view()}.
34
 *
35
 * Viewtypes are set by passing $_REQUEST['view'].  The viewtype
36
 * 'default' is a standard HTML view.  Types can be defined on the fly
37
 * and you can get the current viewtype with {@link elgg_get_viewtype()}.
38
 *
39
 * @note Internal: Plugin views are autoregistered before their init functions
40
 * are called, so the init order doesn't affect views.
41
 *
42
 * @note Internal: The file that determines the output of the view is the last
43
 * registered by {@link elgg_set_view_location()}.
44
 *
45
 * @package Elgg.Core
46
 * @subpackage Views
47
 */
48
49
use Elgg\Menu\Menu;
50
use Elgg\Menu\UnpreparedMenu;
51
use Elgg\Project\Paths;
52
53
/**
54
 * Manually set the viewtype.
55
 *
56
 * View types are detected automatically.  This function allows
57
 * you to force subsequent views to use a different viewtype.
58
 *
59
 * @tip Call elgg_set_viewtype() with no parameter to reset.
60
 *
61
 * @param string $viewtype The view type, e.g. 'rss', or 'default'.
62
 *
63
 * @return bool
64
 */
65
function elgg_set_viewtype($viewtype = '') {
66 19
	return _elgg_services()->views->setViewtype($viewtype);
67
}
68
69
/**
70
 * Return the current view type.
71
 *
72
 * Viewtypes are automatically detected and can be set with $_REQUEST['view']
73
 * or {@link elgg_set_viewtype()}.
74
 *
75
 * @return string The viewtype
76
 * @see elgg_set_viewtype()
77
 */
78
function elgg_get_viewtype() {
79 181
	return _elgg_services()->views->getViewtype();
80
}
81
82
/**
83
 * Checks if $viewtype is a string suitable for use as a viewtype name
84
 *
85
 * @param string $viewtype Potential viewtype name. Alphanumeric chars plus _ allowed.
86
 *
87
 * @return bool
88
 * @access private
89
 * @since 1.9
90
 */
91
function _elgg_is_valid_viewtype($viewtype) {
92
	return _elgg_services()->views->isValidViewtype($viewtype);
93
}
94
95
/**
96
 * Register a viewtype to fall back to a default view if a view isn't
97
 * found for that viewtype.
98
 *
99
 * @tip This is useful for alternate html viewtypes (such as for mobile devices).
100
 *
101
 * @param string $viewtype The viewtype to register
102
 *
103
 * @return void
104
 * @since 1.7.2
105
 */
106
function elgg_register_viewtype_fallback($viewtype) {
107
	_elgg_services()->views->registerViewtypeFallback($viewtype);
108
}
109
110
/**
111
 * Checks if a viewtype falls back to default.
112
 *
113
 * @param string $viewtype Viewtype
114
 *
115
 * @return boolean
116
 * @since 1.7.2
117
 */
118
function elgg_does_viewtype_fallback($viewtype) {
119
	return _elgg_services()->views->doesViewtypeFallback($viewtype);
120
}
121
122
/**
123
 * Register a view to be available for ajax calls
124
 *
125
 * @warning Only views that begin with 'js/' and 'css/' have their content
126
 * type set to 'text/javascript' and 'text/css'. Other views are served as
127
 * 'text/html'.
128
 *
129
 * @param string $view The view name
130
 * @return void
131
 * @since 1.8.3
132
 */
133
function elgg_register_ajax_view($view) {
134 40
	elgg_register_external_view($view, false);
135 40
}
136
137
/**
138
 * Unregister a view for ajax calls
139
 *
140
 * @param string $view The view name
141
 * @return void
142
 * @since 1.8.3
143
 */
144
function elgg_unregister_ajax_view($view) {
145
	elgg_unregister_external_view($view);
146
}
147
148
/**
149
 * Registers a view as being available externally (i.e. via URL).
150
 *
151
 * @param string  $view      The name of the view.
152
 * @param boolean $cacheable Whether this view can be cached.
153
 * @return void
154
 * @since 1.9.0
155
 */
156
function elgg_register_external_view($view, $cacheable = false) {
157
	
158 46
	_elgg_services()->ajax->registerView($view);
159
160 46
	if ($cacheable) {
161 37
		_elgg_services()->views->registerCacheableView($view);
162
	}
163 46
}
164
165
/**
166
 * Unregister a view for ajax calls
167
 *
168
 * @param string $view The view name
169
 * @return void
170
 * @since 1.9.0
171
 */
172
function elgg_unregister_external_view($view) {
173
	_elgg_services()->ajax->unregisterView($view);
174
}
175
176
/**
177
 * Set an alternative base location for a view.
178
 *
179
 * Views are expected to be in plugin_name/views/.  This function can
180
 * be used to change that location.
181
 *
182
 * @tip This is useful to optionally register views in a plugin.
183
 *
184
 * @param string $view     The name of the view
185
 * @param string $location The full path to the view
186
 * @param string $viewtype The view type
187
 *
188
 * @return void
189
 */
190
function elgg_set_view_location($view, $location, $viewtype = '') {
191
	_elgg_services()->views->setViewDir($view, $location, $viewtype);
192
}
193
194
/**
195
 * Returns whether the specified view exists
196
 *
197
 * @note If $recurse is true, also checks if a view exists only as an extension.
198
 *
199
 * @param string $view     The view name
200
 * @param string $viewtype If set, forces the viewtype
201
 * @param bool   $recurse  If false, do not check extensions
202
 *
203
 * @return bool
204
 */
205
function elgg_view_exists($view, $viewtype = '', $recurse = true) {
206 362
	return _elgg_services()->views->viewExists($view, $viewtype, $recurse);
207
}
208
209
/**
210
 * List all views in a viewtype
211
 *
212
 * @param string $viewtype Viewtype
213
 *
214
 * @return string[]
215
 *
216
 * @since 2.0
217
 */
218
function elgg_list_views($viewtype = 'default') {
219
	return _elgg_services()->views->listViews($viewtype);
220
}
221
222
/**
223
 * Return a parsed view.
224
 *
225
 * Views are rendered by a template handler and returned as strings.
226
 *
227
 * Views are called with a special $vars variable set,
228
 * which includes any variables passed as the second parameter.
229
 *
230
 * The input of views can be intercepted by registering for the
231
 * view_vars, $view_name plugin hook.
232
 *
233
 * If the input contains the key "__view_output", the view will output this value as a string.
234
 * No extensions are used, and the "view" hook is not triggered).
235
 *
236
 * The output of views can be intercepted by registering for the
237
 * view, $view_name plugin hook.
238
 *
239
 * @param string $view     The name and location of the view to use
240
 * @param array  $vars     Variables to pass to the view.
241
 * @param string $viewtype If set, forces the viewtype for the elgg_view call to be
242
 *                          this value (default: standard detection)
243
 *
244
 * @return string The parsed view
245
 */
246
function elgg_view($view, $vars = [], $viewtype = '') {
247 280
	if (func_num_args() == 5) {
248
		elgg_log(__FUNCTION__ . ' now has only 3 arguments. Update your usage.', 'ERROR');
249
		$viewtype = func_get_arg(4);
250
	}
251 280
	return _elgg_services()->views->renderView($view, $vars, $viewtype);
252
}
253
254
/**
255
 * Display a view with a deprecation notice. No missing view NOTICE is logged
256
 *
257
 * @param string $view       The name and location of the view to use
258
 * @param array  $vars       Variables to pass to the view
259
 * @param string $suggestion Suggestion with the deprecation message
260
 * @param string $version    Human-readable *release* version: 1.7, 1.8, ...
261
 *
262
 * @return string The parsed view
263
 *
264
 * @see elgg_view()
265
 * @access private
266
 */
267
function elgg_view_deprecated($view, array $vars, $suggestion, $version) {
268
	return _elgg_services()->views->renderDeprecatedView($view, $vars, $suggestion, $version);
269
}
270
271
/**
272
 * Extends a view with another view.
273
 *
274
 * The output of any view can be prepended or appended to any other view.
275
 *
276
 * The default action is to append a view.  If the priority is less than 500,
277
 * the output of the extended view will be appended to the original view.
278
 *
279
 * Views can be extended multiple times, and extensions are not checked for
280
 * uniqueness. Use {@link elgg_unextend_view()} to help manage duplicates.
281
 *
282
 * Priority can be specified and affects the order in which extensions
283
 * are appended or prepended.
284
 *
285
 * @see elgg_prepend_css_urls() If the extension is CSS, you may need to use this to fix relative URLs.
286
 *
287
 * @param string $view           The view to extend.
288
 * @param string $view_extension This view is added to $view
289
 * @param int    $priority       The priority, from 0 to 1000, to add at (lowest numbers displayed first)
290
 *
291
 * @return void
292
 * @since 1.7.0
293
 */
294
function elgg_extend_view($view, $view_extension, $priority = 501) {
295 32
	_elgg_services()->views->extendView($view, $view_extension, $priority);
296 32
}
297
298
/**
299
 * Unextends a view.
300
 *
301
 * @param string $view           The view that was extended.
302
 * @param string $view_extension This view that was added to $view
303
 *
304
 * @return bool
305
 * @since 1.7.2
306
 */
307
function elgg_unextend_view($view, $view_extension) {
308 31
	return _elgg_services()->views->unextendView($view, $view_extension);
309
}
310
311
/**
312
 * Get the views (and priorities) that extend a view.
313
 *
314
 * @note extensions may change anytime, especially during the [init, system] event
315
 *
316
 * @param string $view View name
317
 *
318
 * @return string[] Keys returned are view priorities.
319
 * @since 2.3
320
 */
321
function elgg_get_view_extensions($view) {
322
	$list = _elgg_services()->views->getViewList($view);
323
	unset($list[500]);
324
	return $list;
325
}
326
327
/**
328
 * In CSS content, prepend a path to relative URLs.
329
 *
330
 * This is useful to process a CSS view being used as an extension.
331
 *
332
 * @param string $css  CSS
333
 * @param string $path Path to prepend. E.g. "foo/bar/" or "../"
334
 *
335
 * @return string
336
 * @since 2.2
337
 */
338
function elgg_prepend_css_urls($css, $path) {
339
	return Minify_CSS_UriRewriter::prepend($css, $path);
340
}
341
342
/**
343
 * Assembles and outputs a full page.
344
 *
345
 * A "page" in Elgg is determined by the current view type and
346
 * can be HTML for a browser, RSS for a feed reader, or
347
 * Javascript, PHP and a number of other formats.
348
 *
349
 * For HTML pages, use the 'head', 'page' plugin hook for setting meta elements
350
 * and links.
351
 *
352
 * @param string $title      Title
353
 * @param string $body       Body
354
 * @param string $page_shell Optional page shell to use. See page/shells view directory
355
 * @param array  $vars       Optional vars array to pass to the page
356
 *                           shell. Automatically adds title, body, head, and sysmessages
357
 *
358
 * @return string The contents of the page
359
 * @since  1.8
360
 */
361
function elgg_view_page($title, $body, $page_shell = 'default', $vars = []) {
362 12
	$timer = _elgg_services()->timer;
363 12
	if (!$timer->hasEnded(['build page'])) {
364 9
		$timer->end(['build page']);
365
	}
366 12
	$timer->begin([__FUNCTION__]);
367
368 12
	$params = [];
369 12
	$params['identifier'] = _elgg_services()->request->getFirstUrlSegment();
370 12
	$params['segments'] = _elgg_services()->request->getUrlSegments();
371 12
	array_shift($params['segments']);
372 12
	$page_shell = elgg_trigger_plugin_hook('shell', 'page', $params, $page_shell);
373
374
375 12
	$system_messages = _elgg_services()->systemMessages;
376
377 12
	$messages = null;
378 12
	if ($system_messages->count()) {
379 2
		$messages = $system_messages->dumpRegister();
380
381 2
		if (isset($messages['error'])) {
382
			// always make sure error is the first type
383
			$errors = [
384 2
				'error' => $messages['error']
385
			];
386
387 2
			unset($messages['error']);
388 2
			$messages = array_merge($errors, $messages);
389
		}
390
	}
391
392 12
	$vars['title'] = $title;
393 12
	$vars['body'] = $body;
394 12
	$vars['sysmessages'] = $messages;
395 12
	$vars['page_shell'] = $page_shell;
396
397
	// head has keys 'title', 'metas', 'links'
398 12
	$head_params = _elgg_views_prepare_head($title);
399
400 12
	$vars['head'] = elgg_trigger_plugin_hook('head', 'page', $vars, $head_params);
401
402 12
	$vars = elgg_trigger_plugin_hook('output:before', 'page', null, $vars);
403
404 12
	$output = elgg_view("page/$page_shell", $vars);
405
406
407
	// Allow plugins to modify the output
408 12
	$output = elgg_trigger_plugin_hook('output', 'page', $vars, $output);
409
410 12
	$timer->end([__FUNCTION__]);
411 12
	return $output;
412
}
413
414
/**
415
 * Render a resource view. Use this in your page handler to hand off page rendering to
416
 * a view in "resources/". If not found in the current viewtype, we try the "default" viewtype.
417
 *
418
 * @param string $name The view name without the leading "resources/"
419
 * @param array  $vars Arguments passed to the view
420
 *
421
 * @return string
422
 * @throws \Elgg\PageNotFoundException
423
 */
424
function elgg_view_resource($name, array $vars = []) {
425 6
	$view = "resources/$name";
426
427 6
	if (elgg_view_exists($view)) {
428 6
		return _elgg_services()->views->renderView($view, $vars);
429
	}
430
431
	if (elgg_get_viewtype() !== 'default' && elgg_view_exists($view, 'default')) {
432
		return _elgg_services()->views->renderView($view, $vars, 'default');
433
	}
434
435
	_elgg_services()->logger->error("The view $view is missing.");
436
437
	// only works for default viewtype
438
	throw new \Elgg\PageNotFoundException();
439
}
440
441
/**
442
 * Prepare the variables for the html head
443
 *
444
 * @param string $title Page title for <head>
445
 * @return array
446
 * @access private
447
 */
448
function _elgg_views_prepare_head($title) {
449
	$params = [
450 12
		'links' => [],
451
		'metas' => [],
452
	];
453
454 12
	if (empty($title)) {
455
		$params['title'] = _elgg_config()->sitename;
456
	} else {
457 12
		$params['title'] = $title . ' : ' . _elgg_config()->sitename;
458
	}
459
460 12
	$params['metas']['content-type'] = [
461
		'http-equiv' => 'Content-Type',
462
		'content' => 'text/html; charset=utf-8',
463
	];
464
465 12
	$params['metas']['description'] = [
466 12
		'name' => 'description',
467 12
		'content' => _elgg_config()->sitedescription
468
	];
469
470
	// https://developer.chrome.com/multidevice/android/installtohomescreen
471 12
	$params['metas']['viewport'] = [
472
		'name' => 'viewport',
473
		'content' => 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0',
474
	];
475 12
	$params['metas']['mobile-web-app-capable'] = [
476
		'name' => 'mobile-web-app-capable',
477
		'content' => 'yes',
478
	];
479 12
	$params['metas']['apple-mobile-web-app-capable'] = [
480
		'name' => 'apple-mobile-web-app-capable',
481
		'content' => 'yes',
482
	];
483
	
484
	// RSS feed link
485 12
	if (_elgg_has_rss_link()) {
486
		$url = current_page_url();
487
		if (substr_count($url, '?')) {
488
			$url .= "&view=rss";
489
		} else {
490
			$url .= "?view=rss";
491
		}
492
		$params['links']['rss'] = [
493
			'rel' => 'alternative',
494
			'type' => 'application/rss+xml',
495
			'title' => 'RSS',
496
			'href' => $url,
497
		];
498
	}
499
	
500 12
	return $params;
501
}
502
503
504
/**
505
 * Add favicon link tags to HTML head
506
 *
507
 * @param string $hook        "head"
508
 * @param string $type        "page"
509
 * @param array  $head_params Head params
510
 *                            <code>
511
 *                               [
512
 *                                  'title' => '',
513
 *                                  'metas' => [],
514
 *                                  'links' => [],
515
 *                               ]
516
 *                            </code>
517
 * @param array  $params      Hook params
518
 * @return array
519
 */
520
function _elgg_views_prepare_favicon_links($hook, $type, $head_params, $params) {
521
522 2
	$head_params['links']['apple-touch-icon'] = [
523 2
		'rel' => 'apple-touch-icon',
524 2
		'href' => elgg_get_simplecache_url('graphics/favicon-128.png'),
525
	];
526
527
	// favicons
528 2
	$head_params['links']['icon-ico'] = [
529 2
		'rel' => 'icon',
530 2
		'href' => elgg_get_simplecache_url('graphics/favicon.ico'),
531
	];
532 2
	$head_params['links']['icon-vector'] = [
533 2
		'rel' => 'icon',
534 2
		'sizes' => '16x16 32x32 48x48 64x64 128x128',
535 2
		'type' => 'image/svg+xml',
536 2
		'href' => elgg_get_simplecache_url('graphics/favicon.svg'),
537
	];
538 2
	$head_params['links']['icon-16'] = [
539 2
		'rel' => 'icon',
540 2
		'sizes' => '16x16',
541 2
		'type' => 'image/png',
542 2
		'href' => elgg_get_simplecache_url('graphics/favicon-16.png'),
543
	];
544 2
	$head_params['links']['icon-32'] = [
545 2
		'rel' => 'icon',
546 2
		'sizes' => '32x32',
547 2
		'type' => 'image/png',
548 2
		'href' => elgg_get_simplecache_url('graphics/favicon-32.png'),
549
	];
550 2
	$head_params['links']['icon-64'] = [
551 2
		'rel' => 'icon',
552 2
		'sizes' => '64x64',
553 2
		'type' => 'image/png',
554 2
		'href' => elgg_get_simplecache_url('graphics/favicon-64.png'),
555
	];
556 2
	$head_params['links']['icon-128'] = [
557 2
		'rel' => 'icon',
558 2
		'sizes' => '128x128',
559 2
		'type' => 'image/png',
560 2
		'href' => elgg_get_simplecache_url('graphics/favicon-128.png'),
561
	];
562
563 2
	return $head_params;
564
}
565
566
/**
567
 * Displays a layout with optional parameters.
568
 *
569
 * Layouts are templates provide consistency by organizing blocks of content on the page.
570
 *
571
 * Plugins should use one of the core layouts:
572
 *  - default     Primary template with one, two or no sidebars
573
 *  - admin       Admin page template
574
 *  - error       Error page template
575
 *  - widgets     Widgets canvas
576
 *
577
 * Plugins can create and use custom layouts by placing a layout view
578
 * in "page/layouts/<layout_name>" and calling elgg_view_layout(<layout_name>).
579
 *
580
 * For a full list of parameters supported by each of these layouts see
581
 * corresponding layout views.
582
 *
583
 * @param string $layout_name Layout name
584
 *                            Corresponds to a view in "page/layouts/<layout_name>".
585
 * @param array  $vars        Layout parameters
586
 *                            An associative array of parameters to pass to
587
 *                            the layout hooks and views.
588
 *                            Route 'identifier' and 'segments' of the page being
589
 *                            rendered will be added to this array automatially,
590
 *                            allowing plugins to alter layout views and subviews
591
 *                            based on the current route.
592
 * @return string
593
 */
594
function elgg_view_layout($layout_name, $vars = []) {
595 3
	$timer = _elgg_services()->timer;
596 3
	if (!$timer->hasEnded(['build page'])) {
597 2
		$timer->end(['build page']);
598
	}
599 3
	$timer->begin([__FUNCTION__]);
600
601
	// Help plugins transition without breaking them
602 3
	switch ($layout_name) {
603
		case 'content' :
604 1
			$layout_name = 'default';
605 1
			$vars = _elgg_normalize_content_layout_vars($vars);
606 1
			break;
607
608
		case 'one_sidebar' :
609
			$layout_name = 'default';
610
			$vars['sidebar'] = elgg_extract('sidebar', $vars, '', false);
611
			$vars['sidebar_alt'] = false;
612
			break;
613
614
		case 'one_column' :
615
			$layout_name = 'default';
616
			$vars['sidebar'] = false;
617
			$vars['sidebar_alt'] = false;
618
			break;
619
620
		case 'two_sidebar' :
621
			$layout_name = 'default';
622
			$vars['sidebar'] = elgg_extract('sidebar', $vars, '', false);
623
			$vars['sidebar_alt'] = elgg_extract('sidebar_alt', $vars, '', false);
624
			break;
625
	}
626
627 3
	if (isset($vars['nav'])) {
628
		// Temporary helper until all core views are updated
629
		$vars['breadcrumbs'] = $vars['nav'];
630
		unset($vars['nav']);
631
	}
632
633 3
	$vars['identifier'] = _elgg_services()->request->getFirstUrlSegment();
634 3
	$vars['segments'] = _elgg_services()->request->getUrlSegments();
635 3
	array_shift($vars['segments']);
636
637 3
	$layout_name = elgg_trigger_plugin_hook('layout', 'page', $vars, $layout_name);
638
639 3
	$vars['layout'] = $layout_name;
640
641
	$layout_views = [
642 3
		"page/layouts/$layout_name",
643 3
		"page/layouts/default",
644
	];
645
646 3
	$output = '';
647 3
	foreach ($layout_views as $layout_view) {
648 3
		if (elgg_view_exists($layout_view)) {
649 2
			$output = elgg_view($layout_view, $vars);
650 3
			break;
651
		}
652
	}
653
654 3
	$timer->end([__FUNCTION__]);
655 3
	return $output;
656
}
657
658
/**
659
 * Normalizes deprecated content layout $vars for use in default layout
660
 * Helper function to assist plugins transitioning to 3.0
661
 *
662
 * @param array $vars Vars
663
 * @return array
664
 * @access private
665
 */
666
function _elgg_normalize_content_layout_vars(array $vars = []) {
667
668 1
	$context = elgg_extract('context', $vars, elgg_get_context());
669
670 1
	$vars['title'] = elgg_extract('title', $vars, '');
671 1
	if (!$vars['title'] && $vars['title'] !== false) {
672
		$vars['title'] = elgg_echo($context);
673
	}
674
675
	// 1.8 supported 'filter_override'
676 1
	if (isset($vars['filter_override'])) {
677
		$vars['filter'] = $vars['filter_override'];
678
	}
679
680
	// register the default content filters
681 1
	if (!isset($vars['filter']) && $context) {
682
		$selected = elgg_extract('filter_context', $vars);
683
		$vars['filter'] = elgg_get_filter_tabs($context, $selected, null, $vars);
684
		$vars['filter_id'] = $context;
685
		$vars['filter_value'] = $selected;
686
	}
687
	
688 1
	return $vars;
689
}
690
691
/**
692
 * Render a menu
693
 *
694
 * @see elgg_register_menu_item() for documentation on adding menu items and
695
 * navigation.php for information on the different menus available.
696
 *
697
 * This function triggers a 'register', 'menu:<menu name>' plugin hook that enables
698
 * plugins to add menu items just before a menu is rendered. This is used by
699
 * dynamic menus (menus that change based on some input such as the user hover
700
 * menu). Using elgg_register_menu_item() in response to the hook can cause
701
 * incorrect links to show up. See the blog plugin's blog_owner_block_menu()
702
 * for an example of using this plugin hook.
703
 *
704
 * An additional hook is the 'prepare', 'menu:<menu name>' which enables plugins
705
 * to modify the structure of the menu (sort it, remove items, set variables on
706
 * the menu items).
707
 *
708
 * Preset (unprepared) menu items passed to the this function with the $vars
709
 * argument, will be merged with the registered items (registered with
710
 * elgg_register_menu_item()). The combined set of menu items will be passed
711
 * to 'register', 'menu:<menu_name>' hook.
712
 *
713
 * Plugins that pass preset menu items to this function and do not wish to be
714
 * affected by plugin hooks (e.g. if you are displaying multiple menus with
715
 * the same name on the page) should instead choose a unqie menu name
716
 * and define a menu_view argument to render menus consistently.
717
 * For example, if you have multiple 'filter' menus on the page:
718
 * <code>
719
 *    elgg_view_menu("filter:$uid", [
720
 *        'items' => $items,
721
 *        'menu_view' => 'navigation/menu/filter',
722
 *    ]);
723
 * </code>
724
 *
725
 * elgg_view_menu() uses views in navigation/menu
726
 *
727
 * @param string|Menu|UnpreparedMenu $menu Menu name (or object)
728
 * @param array                      $vars An associative array of display options for the menu.
729
 *
730
 *                          Options include:
731
 *                              items => an array of unprepared menu items
732
 *                                       as ElggMenuItem or menu item factory options
733
 *                              sort_by => string or php callback
734
 *                                  string options: 'name', 'priority', 'title' (default),
735
 *                                  'register' (registration order) or a
736
 *                                  php callback (a compare function for usort)
737
 *                              handler: string the page handler to build action URLs
738
 *                              entity: \ElggEntity to use to build action URLs
739
 *                              class: string the class for the entire menu.
740
 *                              menu_view: name of the view to be used to render the menu
741
 *                              show_section_headers: bool show headers before menu sections.
742
 *
743
 * @return string
744
 * @since 1.8.0
745
 */
746
function elgg_view_menu($menu, array $vars = []) {
747
748 33
	$menu_view = elgg_extract('menu_view', $vars);
749 33
	unset($vars['menu_view']);
750
751 33
	if (is_string($menu)) {
752 33
		$menu = _elgg_services()->menus->getMenu($menu, $vars);
753
	} elseif ($menu instanceof UnpreparedMenu) {
754
		$menu = _elgg_services()->menus->prepareMenu($menu);
755
	}
756
757 33
	if (!$menu instanceof Menu) {
758
		throw new \InvalidArgumentException('$menu must be a menu name, a Menu, or UnpreparedMenu');
759
	}
760
761 33
	$name = $menu->getName();
762 33
	$params = $menu->getParams();
763
764
	$views = [
765 33
		$menu_view,
766 33
		"navigation/menu/$name",
767 33
		'navigation/menu/default',
768
	];
769
770 33
	foreach ($views as $view) {
771 33
		if (elgg_view_exists($view)) {
772 33
			return elgg_view($view, $params);
773
		}
774
	}
775 18
}
776
777
/**
778
 * Render a menu item (usually as a link)
779
 *
780
 * @param \ElggMenuItem $item The menu item
781
 * @param array         $vars Options to pass to output/url if a link
782
 * @return string
783
 * @since 1.9.0
784
 */
785
function elgg_view_menu_item(\ElggMenuItem $item, array $vars = []) {
786
787 13
	$vars = array_merge($item->getValues(), $vars);
788 13
	$vars['class'] = elgg_extract_class($vars, ['elgg-menu-content']);
789
	
790 13
	if ($item->getLinkClass()) {
791 4
		$vars['class'][] = $item->getLinkClass();
792
	}
793
794 13
	if ($item->getHref() === false || $item->getHref() === null) {
795 2
		$vars['class'][] = 'elgg-non-link';
796
	}
797
798 13
	if (!isset($vars['rel']) && !isset($vars['is_trusted'])) {
799 13
		$vars['is_trusted'] = true;
800
	}
801
802 13
	if ($item->getConfirmText()) {
803
		$vars['confirm'] = $item->getConfirmText();
804
	}
805
806 13
	return elgg_view('output/url', $vars);
807
}
808
809
/**
810
 * Returns a string of a rendered entity.
811
 *
812
 * Entity views are either determined by setting the view property on the entity
813
 * or by having a view named after the entity $type/$subtype.  Entities that have
814
 * neither a view property nor a defined $type/$subtype view will fall back to
815
 * using the $type/default view.
816
 *
817
 * The entity view is called with the following in $vars:
818
 *  - \ElggEntity 'entity' The entity being viewed
819
 *
820
 * @tip This function can automatically appends annotations to entities if in full
821
 * view and a handler is registered for the entity:annotate.  See https://github.com/Elgg/Elgg/issues/964 and
822
 * {@link elgg_view_entity_annotations()}.
823
 *
824
 * @param \ElggEntity $entity The entity to display
825
 * @param array       $vars   Array of variables to pass to the entity view.
826
 *      'full_view'        Whether to show a full or condensed view. (Default: true)
827
 *      'item_view'        Alternative view used to render this entity
828
 *
829
 * @return string HTML to display or false
830
 * @todo The annotation hook might be better as a generic plugin hook to append content.
831
 */
832
function elgg_view_entity(\ElggEntity $entity, array $vars = []) {
833
834
	// No point continuing if entity is null
835 9
	if (!$entity || !($entity instanceof \ElggEntity)) {
836
		return false;
837
	}
838
839 9
	elgg_register_rss_link();
840
841
	$defaults = [
842 9
		'full_view' => true,
843
	];
844
845 9
	$vars = array_merge($defaults, $vars);
846
847 9
	$vars['entity'] = $entity;
848
849 9
	$entity_type = $entity->getType();
850 9
	$entity_subtype = $entity->getSubtype();
851
852
	$entity_views = [
853 9
		elgg_extract('item_view', $vars, ''),
854 9
		"$entity_type/$entity_subtype",
855 9
		"$entity_type/default",
856
	];
857
858 9
	$contents = '';
859 9
	foreach ($entity_views as $view) {
860 9
		if (elgg_view_exists($view)) {
861 9
			$contents = elgg_view($view, $vars);
862 9
			break;
863
		}
864
	}
865
866
	// Marcus Povey 20090616 : Speculative and low impact approach for fixing #964
867 9
	if ($vars['full_view']) {
868 7
		$annotations = elgg_view_entity_annotations($entity, $vars['full_view']);
869
870 7
		if ($annotations) {
871
			$contents .= $annotations;
872
		}
873
	}
874 9
	return $contents;
875
}
876
877
/**
878
 * View the icon of an entity
879
 *
880
 * Entity views are determined by having a view named after the entity $type/$subtype.
881
 * Entities that do not have a defined icon/$type/$subtype view will fall back to using
882
 * the icon/$type/default view.
883
 *
884
 * @param \ElggEntity $entity The entity to display
885
 * @param string      $size   The size: tiny, small, medium, large
886
 * @param array       $vars   An array of variables to pass to the view. Some possible
887
 *                            variables are img_class and link_class. See the
888
 *                            specific icon view for more parameters.
889
 *
890
 * @return string HTML to display or false
891
 */
892
function elgg_view_entity_icon(\ElggEntity $entity, $size = 'medium', $vars = []) {
893
894
	// No point continuing if entity is null
895 14
	if (!$entity || !($entity instanceof \ElggEntity)) {
896
		return false;
897
	}
898
899 14
	$vars['entity'] = $entity;
900 14
	$vars['size'] = $size;
901
902 14
	$entity_type = $entity->getType();
903
904 14
	$subtype = $entity->getSubtype();
905
906 14
	$contents = '';
907 14
	if (elgg_view_exists("icon/$entity_type/$subtype")) {
908
		$contents = elgg_view("icon/$entity_type/$subtype", $vars);
909
	}
910 14
	if (empty($contents)) {
911 14
		$contents = elgg_view("icon/$entity_type/default", $vars);
912
	}
913 14
	if (empty($contents)) {
914 13
		$contents = elgg_view("icon/default", $vars);
915
	}
916
917 14
	return $contents;
918
}
919
920
/**
921
 * Returns a string of a rendered annotation.
922
 *
923
 * Annotation views are expected to be in annotation/$annotation_name.
924
 * If a view is not found for $annotation_name, the default annotation/default
925
 * will be used.
926
 *
927
 * @warning annotation/default is not currently defined in core.
928
 *
929
 * The annotation view is called with the following in $vars:
930
 *  - \ElggEntity 'annotation' The annotation being viewed.
931
 *
932
 * @param \ElggAnnotation $annotation The annotation to display
933
 * @param array           $vars       Variable array for view.
934
 *      'item_view'  Alternative view used to render an annotation
935
 *
936
 * @return string/false Rendered annotation
937
 */
0 ignored issues
show
Documentation Bug introduced by Brett Profitt
The doc comment string/false at position 0 could not be parsed: Unknown type name 'string/false' at position 0 in string/false.
Loading history...
938
function elgg_view_annotation(\ElggAnnotation $annotation, array $vars = []) {
939
	elgg_register_rss_link();
940
941
	$defaults = [
942
		'full_view' => true,
943
	];
944
945
	$vars = array_merge($defaults, $vars);
946
	$vars['annotation'] = $annotation;
947
948
	$name = $annotation->name;
949
	if (empty($name)) {
950
		return false;
951
	}
952
953
	$annotation_views = [
954
		elgg_extract('item_view', $vars, ''),
955
		"annotation/$name",
956
		"annotation/default",
957
	];
958
959
	$contents = '';
960
	foreach ($annotation_views as $view) {
961
		if (elgg_view_exists($view)) {
962
			$contents = elgg_view($view, $vars);
963
			break;
964
		}
965
	}
966
967
	return $contents;
968
}
969
970
/**
971
 * Returns a rendered list of entities with pagination. This function should be
972
 * called by wrapper functions.
973
 *
974
 * @see elgg_list_entities()
975
 *
976
 * @param array $entities Array of entities
977
 * @param array $vars     Display variables
978
 *      'count'            The total number of entities across all pages
979
 *      'offset'           The current indexing offset
980
 *      'limit'            The number of entities to display per page (default from settings)
981
 *      'full_view'        Display the full view of the entities?
982
 *      'list_class'       CSS class applied to the list
983
 *      'item_class'       CSS class applied to the list items
984
 *      'item_view'        Alternative view to render list items
985
 *      'pagination'       Display pagination?
986
 *      'base_url'         Base URL of list (optional)
987
 *      'url_fragment'     URL fragment to add to links if not present in base_url (optional)
988
 *      'position'         Position of the pagination: before, after, or both
989
 *      'list_type'        List type: 'list' (default), 'gallery'
990
 *      'list_type_toggle' Display the list type toggle?
991
 *      'no_results'       Message to display if no results (string|Closure)
992
 *
993
 * @return string The rendered list of entities
994
 */
995
function elgg_view_entity_list($entities, array $vars = []) {
996 3
	$offset = (int) get_input('offset', 0);
997
998
	// list type can be passed as request parameter
999 3
	$list_type = get_input('list_type', 'list');
1000
1001
	$defaults = [
1002 3
		'items' => $entities,
1003 3
		'list_class' => 'elgg-list-entity',
1004
		'full_view' => true,
1005
		'pagination' => true,
1006 3
		'list_type' => $list_type,
1007
		'list_type_toggle' => false,
1008 3
		'offset' => $offset,
1009
		'limit' => null,
1010
	];
1011
1012 3
	$vars = array_merge($defaults, $vars);
1013
1014 3
	if (!$vars["limit"] && !$vars["offset"]) {
1015
		// no need for pagination if listing is unlimited
1016
		$vars["pagination"] = false;
1017
	}
1018
1019 3
	if ($vars['list_type'] == 'table') {
1020
		return elgg_view('page/components/table', $vars);
1021 3
	} elseif ($vars['list_type'] == 'list') {
1022 3
		return elgg_view('page/components/list', $vars);
1023
	} else {
1024
		return elgg_view('page/components/gallery', $vars);
1025
	}
1026
}
1027
1028
/**
1029
 * Returns a rendered list of annotations, plus pagination. This function
1030
 * should be called by wrapper functions.
1031
 *
1032
 * @param array $annotations Array of annotations
1033
 * @param array $vars        Display variables
1034
 *      'count'      The total number of annotations across all pages
1035
 *      'offset'     The current indexing offset
1036
 *      'limit'      The number of annotations to display per page
1037
 *      'full_view'  Display the full view of the annotation?
1038
 *      'list_class' CSS Class applied to the list
1039
 *      'item_view'  Alternative view to render list items
1040
 *      'offset_key' The url parameter key used for offset
1041
 *      'no_results' Message to display if no results (string|Closure)
1042
 *
1043
 * @return string The list of annotations
1044
 * @access private
1045
 */
1046
function elgg_view_annotation_list($annotations, array $vars = []) {
1047
	$defaults = [
1048 1
		'items' => $annotations,
1049
		'offset' => null,
1050
		'limit' => null,
1051 1
		'list_class' => 'elgg-list-annotation elgg-annotation-list', // @todo remove elgg-annotation-list in Elgg 1.9
1052
		'full_view' => true,
1053 1
		'offset_key' => 'annoff',
1054
	];
1055
1056 1
	$vars = array_merge($defaults, $vars);
1057
1058 1
	if (!$vars["limit"] && !$vars["offset"]) {
1059
		// no need for pagination if listing is unlimited
1060
		$vars["pagination"] = false;
1061
	}
1062
1063 1
	return elgg_view('page/components/list', $vars);
1064
}
1065
1066
/**
1067
 * Display a plugin-specified rendered list of annotations for an entity.
1068
 *
1069
 * This displays the output of functions registered to the entity:annotation,
1070
 * $entity_type plugin hook.
1071
 *
1072
 * This is called automatically by the framework from {@link elgg_view_entity()}
1073
 *
1074
 * @param \ElggEntity $entity    Entity
1075
 * @param bool        $full_view Display full view?
1076
 *
1077
 * @return mixed string or false on failure
1078
 * @todo Change the hook name.
1079
 */
1080
function elgg_view_entity_annotations(\ElggEntity $entity, $full_view = true) {
1081 7
	if (!($entity instanceof \ElggEntity)) {
1082
		return false;
1083
	}
1084
1085 7
	$entity_type = $entity->getType();
1086
1087 7
	$annotations = elgg_trigger_plugin_hook('entity:annotate', $entity_type,
1088
		[
1089 7
			'entity' => $entity,
1090 7
			'full_view' => $full_view,
1091
		]
1092
	);
1093
1094 7
	return $annotations;
1095
}
1096
1097
/**
1098
 * Renders a title.
1099
 *
1100
 * This is a shortcut for {@elgg_view page/elements/title}.
1101
 *
1102
 * @param string $title The page title
1103
 * @param array  $vars  View variables (was submenu be displayed? (deprecated))
1104
 *
1105
 * @return string The HTML (etc)
1106
 */
1107
function elgg_view_title($title, array $vars = []) {
1108
	$vars['title'] = $title;
1109
1110
	return elgg_view('page/elements/title', $vars);
1111
}
1112
1113
/**
1114
 * Displays a UNIX timestamp in a friendly way
1115
 *
1116
 * @see elgg_get_friendly_time()
1117
 *
1118
 * @param int $time A UNIX epoch timestamp
1119
 *
1120
 * @return string The friendly time HTML
1121
 * @since 1.7.2
1122
 */
1123
function elgg_view_friendly_time($time) {
1124 9
	$view = 'output/friendlytime';
1125 9
	$vars = ['time' => $time];
1126 9
	$viewtype = elgg_view_exists($view) ? '' : 'default';
1127
1128 9
	return _elgg_view_under_viewtype($view, $vars, $viewtype);
1129
}
1130
1131
/**
1132
 * Returns rendered comments and a comment form for an entity.
1133
 *
1134
 * @tip Plugins can override the output by registering a handler
1135
 * for the comments, $entity_type hook.  The handler is responsible
1136
 * for formatting the comments and the add comment form.
1137
 *
1138
 * @param \ElggEntity $entity      The entity to view comments of
1139
 * @param bool        $add_comment Include a form to add comments?
1140
 * @param array       $vars        Variables to pass to comment view
1141
 *
1142
 * @return string|false Rendered comments or false on failure
1143
 */
1144
function elgg_view_comments($entity, $add_comment = true, array $vars = []) {
1145 1
	if (!($entity instanceof \ElggEntity)) {
1146
		return false;
1147
	}
1148
1149 1
	$vars['entity'] = $entity;
1150 1
	$vars['show_add_form'] = $add_comment;
1151 1
	$vars['class'] = elgg_extract('class', $vars, "{$entity->getSubtype()}-comments");
1152
1153 1
	$output = elgg_trigger_plugin_hook('comments', $entity->getType(), $vars, false);
1154 1
	if ($output !== false) {
1155
		return $output;
1156
	} else {
1157 1
		return elgg_view('page/elements/comments', $vars);
1158
	}
1159
}
1160
1161
/**
1162
 * Wrapper function for the image block display pattern.
1163
 *
1164
 * Fixed width media on the side (image, icon, flash, etc.).
1165
 * Descriptive content filling the rest of the column.
1166
 *
1167
 * @note Use the $vars "image_alt" key to set an image on the right. If you do, you may pass
1168
 *       in an empty string for $image to have only the right image.
1169
 *
1170
 * This is a shortcut for {@elgg_view page/components/image_block}.
1171
 *
1172
 * @param string $image The icon and other information
1173
 * @param string $body  Description content
1174
 * @param array  $vars  Additional parameters for the view
1175
 *
1176
 * @return string
1177
 * @since 1.8.0
1178
 */
1179
function elgg_view_image_block($image, $body, $vars = []) {
1180 13
	$vars['image'] = $image;
1181 13
	$vars['body'] = $body;
1182 13
	return elgg_view('page/components/image_block', $vars);
1183
}
1184