Completed
Push — master ( a6c800...8f3ab7 )
by Jeroen
04:41
created

start.php ➔ groups_fields_setup()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 23
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 11
nc 3
nop 0
dl 0
loc 23
rs 9.0856
c 0
b 0
f 0
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 16 and the first side effect is on line 8.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/**
3
 * Elgg groups plugin
4
 *
5
 * @package ElggGroups
6
 */
7
8
elgg_register_event_handler('init', 'system', 'groups_init');
9
10
// Ensure this runs after other plugins
11
elgg_register_event_handler('init', 'system', 'groups_fields_setup', 10000);
12
13
/**
14
 * Initialize the groups plugin.
15
 */
16
function groups_init() {
17
18
	elgg_register_library('elgg:groups', __DIR__ . '/lib/groups.php');
19
	elgg_load_library('elgg:groups');
20
	
21
	// register group entities for search
22
	elgg_register_entity_type('group', '');
23
24
	// Set up the menu
25
	$item = new ElggMenuItem('groups', elgg_echo('groups'), 'groups/all');
26
	elgg_register_menu_item('site', $item);
27
28
	// Register a page handler, so we can have nice URLs
29
	elgg_register_page_handler('groups', 'groups_page_handler');
30
31
	// Register URL handlers for groups
32
	elgg_register_plugin_hook_handler('entity:url', 'group', 'groups_set_url');
33
	elgg_register_plugin_hook_handler('entity:icon:sizes', 'group', 'groups_set_icon_sizes');
34
35
	// add group activity tool option
36
	if (elgg_get_plugin_setting('allow_activity', 'groups') === 'yes') {
37
		add_group_tool_option('activity', elgg_echo('groups:enableactivity'), true);
38
		elgg_extend_view('groups/tool_latest', 'groups/profile/activity_module');
39
	}
40
41
	// add link to owner block
42
	elgg_register_plugin_hook_handler('register', 'menu:owner_block', 'groups_activity_owner_block_menu');
43
44
	// group entity menu
45
	elgg_register_plugin_hook_handler('register', 'menu:entity', 'groups_entity_menu_setup');
46
47
	// group user hover menu
48
	elgg_register_plugin_hook_handler('register', 'menu:user_hover', 'groups_user_entity_menu_setup');
49
50
	// invitation request actions
51
	elgg_register_plugin_hook_handler('register', 'menu:invitationrequest', 'groups_invitationrequest_menu_setup');
52
53
	// group members tabs
54
	elgg_register_plugin_hook_handler('register', 'menu:groups_members', 'groups_members_menu_setup');
55
56
	//extend some views
57
	elgg_extend_view('elgg.css', 'groups/css');
58
	if (_elgg_view_may_be_altered('groups/js', __DIR__ . '/views/default/groups/js.php')) {
59
		elgg_deprecated_notice('groups/js view has been deprecated. Use AMD modules instead', '2.2');
60
		elgg_extend_view('elgg.js', 'groups/js');
61
	}
62
63
	// Access permissions
64
	elgg_register_plugin_hook_handler('access:collections:write', 'all', 'groups_write_acl_plugin_hook', 600);
65
	elgg_register_plugin_hook_handler('default', 'access', 'groups_access_default_override');
66
67
	// Register profile menu hook
68
	elgg_register_plugin_hook_handler('profile_menu', 'profile', 'activity_profile_menu');
69
70
	// allow ecml in profiles
71
	elgg_register_plugin_hook_handler('get_views', 'ecml', 'groupprofile_ecml_views_hook');
72
73
	// Register a handler for create groups
74
	elgg_register_event_handler('create', 'group', 'groups_create_event_listener');
75
	elgg_register_event_handler('update:after', 'group', 'groups_update_event_listener');
76
77
	elgg_register_event_handler('join', 'group', 'groups_user_join_event_listener');
78
	elgg_register_event_handler('leave', 'group', 'groups_user_leave_event_listener');
79
80
	elgg_register_plugin_hook_handler('access:collections:add_user', 'collection', 'groups_access_collection_override');
81
82
	elgg_register_event_handler('upgrade', 'system', 'groups_run_upgrades');
83
84
	// Add tests
85
	elgg_register_plugin_hook_handler('unit_test', 'system', 'groups_test');
86
87
	// allow to be liked
88
	elgg_register_plugin_hook_handler('likes:is_likable', 'group:', 'Elgg\Values::getTrue');
89
90
	// prepare profile buttons to be registered in the title menu
91
	elgg_register_plugin_hook_handler('profile_buttons', 'group', 'groups_prepare_profile_buttons');
92
93
	// Help core resolve page owner guids from group routes
94
	// Registered with an earlier priority to be called before default_page_owner_handler()
95
	elgg_register_plugin_hook_handler('page_owner', 'system', 'groups_default_page_owner_handler', 400);
96
97
	// Setup filter tabs on /groups/all page
98
	elgg_register_plugin_hook_handler('register', 'menu:filter:groups/all', 'groups_setup_filter_tabs');
99
100
	elgg_register_plugin_hook_handler('register', 'menu:page', '_groups_page_menu_group_profile');
101
	elgg_register_plugin_hook_handler('register', 'menu:page', '_groups_page_menu');
102
}
103
104
/**
105
 * This function loads a set of default fields into the profile, then triggers
106
 * a hook letting other plugins to edit add and delete fields.
107
 *
108
 * Note: This is a system:init event triggered function and is run at a super
109
 * low priority to guarantee that it is called after all other plugins have
110
 * initialized.
111
 */
112
function groups_fields_setup() {
113
114
	$profile_defaults = array(
115
		'description' => 'longtext',
116
		'briefdescription' => 'text',
117
		'interests' => 'tags',
118
	);
119
120
	$profile_defaults = elgg_trigger_plugin_hook('profile:fields', 'group', null, $profile_defaults);
121
122
	elgg_set_config('group', $profile_defaults);
123
124
	// register any tag metadata names
125
	foreach ($profile_defaults as $name => $type) {
126
		if ($type == 'tags') {
127
			elgg_register_tag_metadata_name($name);
128
129
			// only shows up in search but why not just set this in en.php as doing it here
130
			// means you cannot override it in a plugin
131
			add_translation(get_current_language(), array("tag_names:$name" => elgg_echo("groups:$name")));
132
		}
133
	}
134
}
135
136
/**
137
 * Register menu items for the page menu
138
 *
139
 * @param string $hook
140
 * @param string $type
141
 * @param array  $return
142
 * @param array  $params
143
 * @return array
144
 *
145
 * @access private
146
 *
147
 * @since 3.0
148
 */
149
function _groups_page_menu_group_profile($hook, $type, $return, $params) {
0 ignored issues
show
Unused Code introduced by
The parameter $hook is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $type is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $params is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
150
	
151
	if (!elgg_in_context('group_profile') || !elgg_is_logged_in()) {
152
		return;
153
	}
154
	
155
	// Get the page owner entity
156
	$page_owner = elgg_get_page_owner_entity();
157
	if (!($page_owner instanceof ElggGroup)) {
158
		return;
159
	}
160
	
161
	if (!$page_owner->canEdit() || $page_owner->isPublicMembership()) {
162
		return;
163
	}
164
	
165
	$count = elgg_get_entities_from_relationship(array(
166
		'type' => 'user',
167
		'relationship' => 'membership_request',
168
		'relationship_guid' => $page_owner->guid,
169
		'inverse_relationship' => true,
170
		'count' => true,
171
	));
172
173
	$text = elgg_echo('groups:membershiprequests');
174
	$title = $text;
175
	if ($count) {
176
		$title = elgg_echo('groups:membershiprequests:pending', array($count));
177
	}
178
	
179
	$return[] = \ElggMenuItem::factory([
180
		'name' => 'membership_requests',
181
		'text' => $text,
182
		'badge' => $count ? $count : null,
183
		'title' => $title,
184
		'href' => "groups/requests/{$page_owner->guid}",
185
	]);
186
	
187
	return $return;
188
}
189
190
/**
191
 * Register menu items for the page menu
192
 *
193
 * @param string $hook
194
 * @param string $type
195
 * @param array  $return
196
 * @param array  $params
197
 * @return array
198
 *
199
 * @access private
200
 *
201
 * @since 3.0
202
 */
203
function _groups_page_menu($hook, $type, $return, $params) {
0 ignored issues
show
Unused Code introduced by
The parameter $hook is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $type is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $params is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
204
	
205
	if (elgg_get_context() !== 'groups') {
206
		return;
207
	}
208
	
209
	// Get the page owner entity
210
	$page_owner = elgg_get_page_owner_entity();
211
	if ($page_owner instanceof ElggGroup) {
212
		return;
213
	}
214
	
215
	$return[] = \ElggMenuItem::factory([
216
		'name' => 'groups:all',
217
		'text' => elgg_echo('groups:all'),
218
		'href' => 'groups/all',
219
	]);
220
221
	$user = elgg_get_logged_in_user_entity();
222
	if (!$user) {
223
		return $return;
224
	}
225
	
226
	$return[] = \ElggMenuItem::factory([
227
		'name' => 'groups:owned',
228
		'text' => elgg_echo('groups:owned'),
229
		'href' => "groups/owner/$user->username",
230
	]);
231
	
232
	$return[] = \ElggMenuItem::factory([
233
		'name' => 'groups:member',
234
		'text' => elgg_echo('groups:yours'),
235
		'href' => "groups/member/$user->username",
236
	]);
237
238
	$invitation_count = groups_get_invited_groups($user->guid, false, ['count' => true]);
239
240
	// Invitations
241
	$text = elgg_echo('groups:invitations');
242
	$title = $text;
243
	if ($invitation_count) {
244
		$title = elgg_echo('groups:invitations:pending', array($invitation_count));
245
	}
246
247
	$return[] = \ElggMenuItem::factory([
248
		'name' => 'groups:user:invites',
249
		'text' => $text,
250
		'badge' => $invitation_count ? $invitation_count : null,
251
		'title' => $title,
252
		'href' => "groups/invitations/$user->username",
253
	]);
254
255
	return $return;
256
}
257
258
/**
259
 * Groups page handler
260
 *
261
 * URLs take the form of
262
 *  All groups:           groups/all
263
 *  User's owned groups:  groups/owner/<username>
264
 *  User's member groups: groups/member/<username>
265
 *  Group profile:        groups/profile/<guid>/<title>
266
 *  New group:            groups/add/<guid>
267
 *  Edit group:           groups/edit/<guid>
268
 *  Group invitations:    groups/invitations/<username>
269
 *  Invite to group:      groups/invite/<guid>
270
 *  Membership requests:  groups/requests/<guid>
271
 *  Group activity:       groups/activity/<guid>
272
 *  Group members:        groups/members/<guid>
273
 *
274
 * @param array $page Array of url segments for routing
275
 * @return bool
276
 */
277
function groups_page_handler($page) {
278
279
	if (!isset($page[0])) {
280
		$page[0] = 'all';
281
	}
282
283
	elgg_push_breadcrumb(elgg_echo('groups'), "groups/all");
284
285
	$vars = [];
286
	switch ($page[0]) {
287
		case 'add':
288
		case 'all':
289
		case 'owner':
290
		case 'search':
291
			echo elgg_view_resource("groups/{$page[0]}");
292
			break;
293
		case 'invitations':
294
		case 'member':
295
			echo elgg_view_resource("groups/{$page[0]}", [
296
				'username' => $page[1],
297
			]);
298
			break;
299
		case 'members':
300
			$vars['sort'] = elgg_extract('2', $page, 'alpha');
301
			$vars['guid'] = elgg_extract('1', $page);
302
			if (elgg_view_exists("resources/groups/members/{$vars['sort']}")) {
303
				echo elgg_view_resource("groups/members/{$vars['sort']}", $vars);
304
			} else {
305
				echo elgg_view_resource('groups/members', $vars);
306
			}
307
			break;
308
		case 'profile':
309
		case 'activity':
310
		case 'edit':
311
		case 'invite':
312
		case 'requests':
313
			echo elgg_view_resource("groups/{$page[0]}", [
314
				'guid' => $page[1],
315
			]);
316
			break;
317
		default:
318
			return false;
319
	}
320
	return true;
321
}
322
323
/**
324
 * Populates the ->getUrl() method for group objects
325
 *
326
 * @param string $hook
327
 * @param string $type
328
 * @param string $url
329
 * @param array  $params
330
 * @return string
331
 */
332
function groups_set_url($hook, $type, $url, $params) {
0 ignored issues
show
Unused Code introduced by
The parameter $hook is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $type is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $url is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
333
	$entity = $params['entity'];
334
	$title = elgg_get_friendly_title($entity->name);
335
	return "groups/profile/{$entity->guid}/$title";
336
}
337
338
/**
339
 * Add owner block link
340
 */
341
function groups_activity_owner_block_menu($hook, $type, $return, $params) {
0 ignored issues
show
Unused Code introduced by
The parameter $hook is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $type is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
342
	if (elgg_instanceof($params['entity'], 'group')) {
343
		if ($params['entity']->activity_enable != "no") {
344
			$url = "groups/activity/{$params['entity']->guid}";
345
			$item = new ElggMenuItem('activity', elgg_echo('groups:activity'), $url);
346
			$return[] = $item;
347
		}
348
	}
349
350
	return $return;
351
}
352
353
/**
354
 * Add links/info to entity menu particular to group entities
355
 */
356
function groups_entity_menu_setup($hook, $type, $return, $params) {
0 ignored issues
show
Unused Code introduced by
The parameter $hook is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $type is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
357
	if (elgg_in_context('widgets')) {
358
		return $return;
359
	}
360
361
	/* @var ElggGroup $entity */
362
	$entity = $params['entity'];
363
	$handler = elgg_extract('handler', $params, false);
364
	if ($handler != 'groups') {
365
		return $return;
366
	}
367
368
	/* @var ElggMenuItem $item */
369
	foreach ($return as $index => $item) {
370
		if (in_array($item->getName(), array('access', 'likes', 'unlike', 'edit', 'delete'))) {
371
			unset($return[$index]);
372
		}
373
	}
374
375
	// membership type
376
	if ($entity->isPublicMembership()) {
377
		$mem = elgg_echo("groups:open");
378
	} else {
379
		$mem = elgg_echo("groups:closed");
380
	}
381
382
	$options = array(
383
		'name' => 'membership',
384
		'text' => $mem,
385
		'href' => false,
386
		'priority' => 100,
387
	);
388
	$return[] = ElggMenuItem::factory($options);
389
390
	// number of members
391
	$num_members = $entity->getMembers(array('count' => true));
392
	$members_string = elgg_echo('groups:member');
393
	$options = array(
394
		'name' => 'members',
395
		'text' => $num_members . ' ' . $members_string,
396
		'href' => false,
397
		'priority' => 200,
398
	);
399
	$return[] = ElggMenuItem::factory($options);
400
401
	// feature link
402
	if (elgg_is_admin_logged_in()) {
403
		$isFeatured = $entity->featured_group == "yes";
404
405
		$return[] = ElggMenuItem::factory(array(
406
			'name' => 'feature',
407
			'text' => elgg_echo("groups:makefeatured"),
408
			'href' => elgg_add_action_tokens_to_url("action/groups/featured?group_guid={$entity->guid}&action_type=feature"),
409
			'priority' => 300,
410
			'item_class' => $isFeatured ? 'hidden' : '',
411
			'deps' => 'groups/navigation',
412
		));
413
414
		$return[] = ElggMenuItem::factory(array(
415
			'name' => 'unfeature',
416
			'text' => elgg_echo("groups:makeunfeatured"),
417
			'href' => elgg_add_action_tokens_to_url("action/groups/featured?group_guid={$entity->guid}&action_type=unfeature"),
418
			'priority' => 300,
419
			'item_class' => $isFeatured ? '' : 'hidden',
420
			'deps' => 'groups/navigation',
421
		));
422
	}
423
424
	return $return;
425
}
426
427
/**
428
 * Add a remove user link to user hover menu when the page owner is a group
429
 */
430
function groups_user_entity_menu_setup($hook, $type, $return, $params) {
0 ignored issues
show
Unused Code introduced by
The parameter $hook is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $type is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
431
	if (elgg_is_logged_in()) {
432
		$group = elgg_get_page_owner_entity();
433
434
		// Check for valid group
435
		if (!elgg_instanceof($group, 'group')) {
436
			return $return;
437
		}
438
439
		$entity = $params['entity'];
440
441
		// Make sure we have a user and that user is a member of the group
442
		if (!elgg_instanceof($entity, 'user') || !$group->isMember($entity)) {
443
			return $return;
444
		}
445
446
		// Add remove link if we can edit the group, and if we're not trying to remove the group owner
447
		if ($group->canEdit() && $group->getOwnerGUID() != $entity->guid) {
448
			$return[] = ElggMenuItem::factory([
449
				'name' => 'removeuser',
450
				'href' => "action/groups/remove?user_guid={$entity->guid}&group_guid={$group->guid}",
451
				'text' => elgg_echo('groups:removeuser'),
452
				'confirm' => true,
453
				'priority' => 999,
454
			]);
455
		}
456
	}
457
458
	return $return;
459
}
460
461
/**
462
 * Groups created so create an access list for it
463
 */
464
function groups_create_event_listener($event, $object_type, $object) {
0 ignored issues
show
Unused Code introduced by
The parameter $event is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $object_type is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
465
	$ac_name = elgg_echo('groups:group') . ": " . $object->name;
466
	$ac_id = create_access_collection($ac_name, $object->guid);
467
	if ($ac_id) {
468
		$object->group_acl = $ac_id;
469
	} else {
470
		// delete group if access creation fails
471
		return false;
472
	}
473
474
	return true;
475
}
476
477
/**
478
 * Listen to group ownership changes and update group icon ownership
479
 * This will only move the source file, the actual icons are moved by
480
 * _elgg_filestore_move_icons()
481
 *
482
 * This operation is performed in an event listener to ensure that icons
483
 * are moved when ownership changes outside of the groups/edit action flow.
484
 *
485
 * @todo #4683 proposes that icons are owned by groups and not group owners
486
 * @see _elgg_filestore_move_icons()
487
 *
488
 * @param string    $event "update:after"
489
 * @param string    $type  "group"
490
 * @param ElggGroup $group Group entity
491
 * @return void
492
 */
493
function groups_update_event_listener($event, $type, $group) {
0 ignored issues
show
Unused Code introduced by
The parameter $event is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $type is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
494
495
	/* @var $group \ElggGroup */
496
497
	$original_attributes = $group->getOriginalAttributes();
498
499
	if (!empty($original_attributes['owner_guid'])) {
500
		$previous_owner_guid = $original_attributes['owner_guid'];
501
502
		// Update owned metadata
503
		$metadata = elgg_get_metadata([
504
			'guid' => $group->guid,
505
			'metadata_owner_guids' => $previous_owner_guid,
506
			'limit' => 0,
507
		]);
508
509
		if ($metadata) {
510
			foreach ($metadata as $md) {
0 ignored issues
show
Bug introduced by
The expression $metadata of type array<integer,object<ElggExtender>>|integer is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
511
				$md->owner_guid = $group->owner_guid;
512
				$md->save();
513
			}
514
		}
515
	}
516
517
	if (!empty($original_attributes['name'])) {
518
		// update access collection name if group name changes
519
		$group_name = html_entity_decode($group->name, ENT_QUOTES, 'UTF-8');
520
		$ac_name = elgg_echo('groups:group') . ": " . $group_name;
521
		$acl = get_access_collection($group->group_acl);
522
		if ($acl) {
523
			$acl->name = $ac_name;
524
			$acl->save();
0 ignored issues
show
Bug introduced by
The method save cannot be called on $acl (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
525
		}
526
	}
527
}
528
529
/**
530
 * Return the write access for the current group if the user has write access to it.
531
 */
532
function groups_write_acl_plugin_hook($hook, $entity_type, $returnvalue, $params) {
0 ignored issues
show
Unused Code introduced by
The parameter $hook is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $entity_type is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
533
534
	$user_guid = sanitise_int(elgg_extract('user_id', $params), false);
0 ignored issues
show
Deprecated Code introduced by
The function sanitise_int() has been deprecated with message: Use query parameters where possible

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
535
	$user = get_user($user_guid);
536
	if (empty($user)) {
537
		return $returnvalue;
538
	}
539
540
	$page_owner = elgg_get_page_owner_entity();
541
	if (!($page_owner instanceof ElggGroup)) {
542
		return $returnvalue;
543
	}
544
545
	if (!$page_owner->canWriteToContainer($user_guid)) {
546
		return $returnvalue;
547
	}
548
549
	// check group content access rules
550
	$allowed_access = array(
551
		ACCESS_PRIVATE
552
	);
553
554
	if ($page_owner->getContentAccessMode() !== ElggGroup::CONTENT_ACCESS_MODE_MEMBERS_ONLY) {
555
		$allowed_access[] = ACCESS_LOGGED_IN;
556
		$allowed_access[] = ACCESS_PUBLIC;
557
	}
558
559
	foreach ($returnvalue as $access_id => $access_string) {
560
		if (!in_array($access_id, $allowed_access)) {
561
			unset($returnvalue[$access_id]);
562
		}
563
	}
564
565
	// add write access to the group
566
	$returnvalue[$page_owner->group_acl] = elgg_echo('groups:acl', array($page_owner->name));
567
568
	return $returnvalue;
569
}
570
571
/**
572
 * Listens to a group join event and adds a user to the group's access control
573
 *
574
 */
575
function groups_user_join_event_listener($event, $object_type, $object) {
0 ignored issues
show
Unused Code introduced by
The parameter $event is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $object_type is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
576
577
	$group = $object['group'];
578
	$user = $object['user'];
579
	$acl = $group->group_acl;
580
581
	add_user_to_access_collection($user->guid, $acl);
582
583
	return true;
584
}
585
586
/**
587
 * Make sure users are added to the access collection
588
 */
589
function groups_access_collection_override($hook, $entity_type, $returnvalue, $params) {
0 ignored issues
show
Unused Code introduced by
The parameter $hook is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $entity_type is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $returnvalue is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
590
	if (isset($params['collection'])) {
591
		if (elgg_instanceof(get_entity($params['collection']->owner_guid), 'group')) {
592
			return true;
593
		}
594
	}
595
}
596
597
/**
598
 * Listens to a group leave event and removes a user from the group's access control
599
 *
600
 */
601
function groups_user_leave_event_listener($event, $object_type, $object) {
0 ignored issues
show
Unused Code introduced by
The parameter $event is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $object_type is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
602
603
	$group = $object['group'];
604
	$user = $object['user'];
605
	$acl = $group->group_acl;
606
607
	remove_user_from_access_collection($user->guid, $acl);
608
609
	return true;
610
}
611
612
/**
613
 * The default access for members only content is this group only. This makes
614
 * for better display of access (can tell it is group only), but does not change
615
 * access to the content.
616
 *
617
 * @param string $hook   Hook name
618
 * @param string $type   Hook type
619
 * @param int    $access Current default access
620
 * @return int
621
 */
622
function groups_access_default_override($hook, $type, $access) {
0 ignored issues
show
Unused Code introduced by
The parameter $hook is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $type is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
623
	$page_owner = elgg_get_page_owner_entity();
624
625
	if ($page_owner instanceof ElggGroup) {
626
		if ($page_owner->getContentAccessMode() == ElggGroup::CONTENT_ACCESS_MODE_MEMBERS_ONLY) {
627
			$access = $page_owner->group_acl;
1 ignored issue
show
Documentation introduced by
The property group_acl does not exist on object<ElggGroup>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
628
		}
629
	}
630
631
	return $access;
632
}
633
634
/**
635
 * Grabs groups by invitations
636
 * Have to override all access until there's a way override access to getter functions.
637
 *
638
 * @param int   $user_guid    The user's guid
639
 * @param bool  $return_guids Return guids rather than ElggGroup objects
640
 * @param array $options      Additional options
641
 *
642
 * @return mixed ElggGroups or guids depending on $return_guids, or count
643
 */
644
function groups_get_invited_groups($user_guid, $return_guids = false, $options = array()) {
645
646
	$ia = elgg_set_ignore_access(true);
647
648
	$defaults = array(
649
		'relationship' => 'invited',
650
		'relationship_guid' => (int) $user_guid,
651
		'inverse_relationship' => true,
652
		'limit' => 0,
653
	);
654
655
	$options = array_merge($defaults, $options);
656
	$groups = elgg_get_entities_from_relationship($options);
657
658
	elgg_set_ignore_access($ia);
659
660
	if ($return_guids) {
661
		$guids = array();
662
		foreach ($groups as $group) {
0 ignored issues
show
Bug introduced by
The expression $groups of type false|object<ElggBatch>|integer|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
663
			$guids[] = $group->getGUID();
664
		}
665
666
		return $guids;
667
	}
668
669
	return $groups;
670
}
671
672
/**
673
 * Join a user to a group, add river event, clean-up invitations
674
 *
675
 * @param ElggGroup $group
676
 * @param ElggUser  $user
677
 * @return bool
678
 */
679
function groups_join_group($group, $user) {
680
681
	// access ignore so user can be added to access collection of invisible group
682
	$ia = elgg_set_ignore_access(TRUE);
683
	$result = $group->join($user);
684
	elgg_set_ignore_access($ia);
685
686
	if ($result) {
687
		// flush user's access info so the collection is added
688
		get_access_list($user->guid, 0, true);
689
690
		// Remove any invite or join request flags
691
		remove_entity_relationship($group->guid, 'invited', $user->guid);
692
		remove_entity_relationship($user->guid, 'membership_request', $group->guid);
693
694
		elgg_create_river_item(array(
695
			'view' => 'river/relationship/member/create',
696
			'action_type' => 'join',
697
			'subject_guid' => $user->guid,
698
			'object_guid' => $group->guid,
699
		));
700
701
		return true;
702
	}
703
704
	return false;
705
}
706
707
/**
708
 * Function to use on groups for access. It will house private, loggedin, public,
709
 * and the group itself. This is when you don't want other groups or access lists
710
 * in the access options available.
711
 *
712
 * @return array
713
 */
714
function group_access_options($group) {
715
	$access_array = array(
716
		ACCESS_PRIVATE => 'private',
717
		ACCESS_LOGGED_IN => 'logged in users',
718
		ACCESS_PUBLIC => 'public',
719
		$group->group_acl => elgg_echo('groups:acl', array($group->name)),
720
	);
721
	return $access_array;
722
}
723
724
function activity_profile_menu($hook, $entity_type, $return_value, $params) {
0 ignored issues
show
Unused Code introduced by
The parameter $hook is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $entity_type is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
725
726
	if (!$params['owner'] instanceof ElggGroup
727
			|| elgg_get_plugin_setting('allow_activity', 'groups') === 'no') {
728
		return;
729
	}
730
731
	$return_value[] = array(
732
		'text' => elgg_echo('groups:activity'),
733
		'href' => "groups/activity/{$params['owner']->guid}"
734
	);
735
	return $return_value;
736
}
737
738
/**
739
 * Parse ECML on group profiles
740
 */
741
function groupprofile_ecml_views_hook($hook, $entity_type, $return_value, $params) {
0 ignored issues
show
Unused Code introduced by
The parameter $hook is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $entity_type is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $params is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
742
	$return_value['groups/groupprofile'] = elgg_echo('groups:ecml:groupprofile');
743
744
	return $return_value;
745
}
746
747
/**
748
 * Process upgrades for the groups plugin
749
 */
750
function groups_run_upgrades() {
751
	$path = __DIR__ . '/upgrades/';
752
	$files = elgg_get_upgrade_files($path);
753
	foreach ($files as $file) {
0 ignored issues
show
Bug introduced by
The expression $files of type false|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
754
		include "$path{$file}";
755
	}
756
}
757
758
/**
759
 * Runs unit tests for groups
760
 *
761
 * @return array
762
 */
763
function groups_test($hook, $type, $value, $params) {
0 ignored issues
show
Unused Code introduced by
The parameter $hook is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $type is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $params is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
764
	$value[] = elgg_get_plugins_path() . 'groups/tests/write_access.php';
765
	return $value;
766
}
767
768
/**
769
 * Setup invitation request actions
770
 *
771
 * @param string $hook   "register"
772
 * @param string $type   "menu:invitationrequest"
773
 * @param array  $menu   Menu items
774
 * @param array  $params Hook params
775
 * @return array
776
 */
777
function groups_invitationrequest_menu_setup($hook, $type, $menu, $params) {
0 ignored issues
show
Unused Code introduced by
The parameter $hook is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $type is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
778
779
	$group = elgg_extract('entity', $params);
780
	$user = elgg_extract('user', $params);
781
782
	if (!$group instanceof \ElggGroup) {
783
		return $menu;
784
	}
785
786
	if (!$user instanceof \ElggUser || !$user->canEdit()) {
787
		return $menu;
788
	}
789
790
	$accept_url = elgg_http_add_url_query_elements('action/groups/join', array(
791
		'user_guid' => $user->guid,
792
		'group_guid' => $group->guid,
793
	));
794
795
	$menu[] = \ElggMenuItem::factory(array(
796
		'name' => 'accept',
797
		'href' => $accept_url,
798
		'is_action' => true,
799
		'text' => elgg_echo('accept'),
800
		'link_class' => 'elgg-button elgg-button-submit',
801
		'is_trusted' => true,
802
	));
803
804
	$delete_url = elgg_http_add_url_query_elements('action/groups/killinvitation', array(
805
		'user_guid' => $user->guid,
806
		'group_guid' => $group->guid,
807
	));
808
809
	$menu[] = \ElggMenuItem::factory(array(
810
		'name' => 'delete',
811
		'href' => $delete_url,
812
		'is_action' => true,
813
		'confirm' => elgg_echo('groups:invite:remove:check'),
814
		'text' => elgg_echo('delete'),
815
		'link_class' => 'elgg-button elgg-button-delete mlm',
816
	));
817
818
	return $menu;
819
}
820
821
/**
822
 * Setup group members tabs
823
 *
824
 * @param string         $hook   "register"
825
 * @param string         $type   "menu:groups_members"
826
 * @param ElggMenuItem[] $menu   Menu items
827
 * @param array          $params Hook params
828
 *
829
 * @return void|ElggMenuItem[]
830
 */
831
function groups_members_menu_setup($hook, $type, $menu, $params) {
0 ignored issues
show
Unused Code introduced by
The parameter $hook is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $type is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
832
833
	$entity = elgg_extract('entity', $params);
834
	if (empty($entity) || !($entity instanceof ElggGroup)) {
835
		return;
836
	}
837
838
	$menu[] = ElggMenuItem::factory([
839
		'name' => 'alpha',
840
		'text' => elgg_echo('sort:alpha'),
841
		'href' => "groups/members/{$entity->getGUID()}",
842
		'priority' => 100
843
	]);
844
845
	$menu[] = ElggMenuItem::factory([
846
		'name' => 'newest',
847
		'text' => elgg_echo('sort:newest'),
848
		'href' => "groups/members/{$entity->getGUID()}/newest",
849
		'priority' => 200
850
	]);
851
852
	return $menu;
853
}
854
855
/**
856
 * Returns menu items to be registered in the title menu of the group profile
857
 *
858
 * @param string         $hook   "profile_buttons"
859
 * @param string         $type   "group"
860
 * @param ElggMenuItem[] $items  Buttons
861
 * @param array          $params Hook params
862
 * @return ElggMenuItem[]
863
 */
864
function groups_prepare_profile_buttons($hook, $type, $items, $params) {
0 ignored issues
show
Unused Code introduced by
The parameter $hook is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $type is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
865
866
	$group = elgg_extract('entity', $params);
867
	if (!$group instanceof ElggGroup) {
868
		return;
869
	}
870
871
	$actions = [];
872
873
	if ($group->canEdit()) {
874
		// group owners can edit the group and invite new members
875
		$actions['groups:edit'] = "groups/edit/{$group->guid}";
876
		$actions['groups:invite'] = "groups/invite/{$group->guid}";
877
	}
878
879
	$user = elgg_get_logged_in_user_entity();
880
	if ($user && $group->isMember($user)) {
881
		if ($group->owner_guid != $user->guid) {
882
			// a member can leave a group if he/she doesn't own it
883
			$actions['groups:leave'] = "action/groups/leave?group_guid={$group->guid}";
884
		}
885
	} else if ($user) {
886
		$url = "action/groups/join?group_guid={$group->guid}";
887
		if ($group->isPublicMembership() || $group->canEdit()) {
888
			// admins can always join
889
			// non-admins can join if membership is public
890
			$actions['groups:join'] = $url;
891
		} else {
892
			// request membership
893
			$actions['groups:joinrequest'] = $url;
894
		}
895
	}
896
897
	foreach ($actions as $action => $url) {
898
		$items[] = ElggMenuItem::factory(array(
899
			'name' => $action,
900
			'href' => elgg_normalize_url($url),
901
			'text' => elgg_echo($action),
902
			'is_action' => 0 === strpos($url, 'action'),
903
			'link_class' => 'elgg-button elgg-button-action',
904
		));
905
	}
906
907
	return $items;
908
}
909
910
/**
911
 * Helper handler to correctly resolve page owners on group routes
912
 *
913
 * @see default_page_owner_handler()
914
 *
915
 * @param string $hook   "page_owner"
916
 * @param string $type   "system"
917
 * @param int    $return Page owner guid
918
 * @param array  $params Hook params
919
 * @return int|void
920
 */
921
function groups_default_page_owner_handler($hook, $type, $return, $params) {
0 ignored issues
show
Unused Code introduced by
The parameter $hook is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $type is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $params is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
922
923
	if ($return) {
924
		return;
925
	}
926
927
	$segments = _elgg_services()->request->getUrlSegments();
928
	$identifier = array_shift($segments);
929
930
	if ($identifier !== 'groups') {
931
		return;
932
	}
933
934
	$page = array_shift($segments);
935
936
	switch ($page) {
937
938
		case 'add' :
939
			$guid = array_shift($segments);
940
			if (!$guid) {
941
				$guid = elgg_get_logged_in_user_guid();
942
			}
943
			return $guid;
944
945
		case 'edit':
946
		case 'profile' :
947
		case 'activity' :
948
		case 'invite' :
949
		case 'requests' :
950
		case 'members' :
951
		case 'profile' :
952
			$guid = array_shift($segments);
953
			if (!$guid) {
954
				return;
955
			}
956
			return $guid;
957
958
		case 'member' :
959
		case 'owner' :
960
		case 'invitations':
961
			$username = array_shift($segments);
962
			if ($username) {
963
				$user = get_user_by_username($username);
964
			} else {
965
				$user = elgg_get_logged_in_user_entity();
966
			}
967
			if (!$user) {
968
				return;
969
			}
970
			return $user->guid;
971
	}
972
}
973
974
/**
975
 * Setup filter tabs on /groups/all page
976
 *
977
 * @param string         $hook   "register"
978
 * @param string         $type   "menu:filter:groups/all"
979
 * @param ElggMenuItem[] $return Menu
980
 * @param array          $params Hook params
981
 * @return ElggMenuItem[]
982
 */
983
function groups_setup_filter_tabs($hook, $type, $return, $params) {
0 ignored issues
show
Unused Code introduced by
The parameter $hook is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $type is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
984
985
	$filter_value = elgg_extract('filter_value', $params);
986
987
	$return[] = ElggMenuItem::factory([
988
		'name' => 'newest',
989
		'text' => elgg_echo('sort:newest'),
990
		'href' => 'groups/all?filter=newest',
991
		'priority' => 200,
992
		'selected' => $filter_value == 'newest',
993
	]);
994
995
	$return[] = ElggMenuItem::factory([
996
		'name' => 'alpha',
997
		'text' => elgg_echo('sort:alpha'),
998
		'href' => 'groups/all?filter=alpha',
999
		'priority' => 250,
1000
		'selected' => $filter_value == 'alpha',
1001
	]);
1002
1003
	$return[] = ElggMenuItem::factory([
1004
		'name' => 'popular',
1005
		'text' => elgg_echo('sort:popular'),
1006
		'href' => 'groups/all?filter=popular',
1007
		'priority' => 300,
1008
		'selected' => $filter_value == 'popular',
1009
	]);
1010
1011
	$return[] = ElggMenuItem::factory([
1012
		'name' => 'featured',
1013
		'text' => elgg_echo('groups:featured'),
1014
		'href' => 'groups/all?filter=featured',
1015
		'priority' => 400,
1016
		'selected' => $filter_value == 'featured',
1017
	]);
1018
	
1019
	return $return;
1020
}
1021
1022
/**
1023
 * Add 'original' to group icon sizes
1024
 *
1025
 * @elgg_plugin_hook entity:icon:sizes group
1026
 *
1027
 * @param \Elgg\Hook $hook Hook
1028
 * @return array
1029
 */
1030
function groups_set_icon_sizes(\Elgg\Hook $hook) {
1031
1032
	$sizes = $hook->getValue();
1033
	$sizes['original'] = [];
1034
1035
	return $sizes;
1036
}
1037