comments.php ➔ _elgg_comment_setup_entity_menu()   A
last analyzed

Complexity

Conditions 5
Paths 5

Size

Total Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
cc 5
nc 5
nop 4
dl 0
loc 19
ccs 0
cts 11
cp 0
crap 30
rs 9.3222
c 0
b 0
f 0
1
<?php
2
/**
3
 * Elgg comments library
4
 *
5
 * @package    Elgg.Core
6
 * @subpackage Comments
7
 * @since 1.9
8
 */
9
10
/**
11
 * Comments initialization function
12
 *
13
 * @return void
14
 * @access private
15
 */
16
function _elgg_comments_init() {
17
	elgg_register_entity_type('object', 'comment');
18
	elgg_register_plugin_hook_handler('register', 'menu:entity', '_elgg_comment_setup_entity_menu', 900);
19
	elgg_register_plugin_hook_handler('entity:url', 'object', '_elgg_comment_url_handler');
20
	elgg_register_plugin_hook_handler('container_permissions_check', 'object', '_elgg_comments_container_permissions_override');
21
	elgg_register_plugin_hook_handler('permissions_check', 'object', '_elgg_comments_permissions_override');
22
	elgg_register_plugin_hook_handler('email', 'system', '_elgg_comments_notification_email_subject');
23
	
24
	elgg_register_event_handler('update:after', 'all', '_elgg_comments_access_sync');
25
26
	elgg_register_page_handler('comment', '_elgg_comments_page_handler');
27
28
	elgg_register_ajax_view('core/ajax/edit_comment');
29
}
30
31
/**
32
 * Page handler for generic comments manipulation.
33
 *
34
 * @param array $page
35
 * @return bool
36
 * @access private
37
 */
38
function _elgg_comments_page_handler($page) {
39
40
	switch ($page[0]) {
41
42
		case 'edit':
43
			elgg_gatekeeper();
44
45
			if (empty($page[1])) {
46
				register_error(elgg_echo('generic_comment:notfound'));
47
				forward(REFERER);
48
			}
49
			$comment = get_entity($page[1]);
50
			if (!($comment instanceof \ElggComment) || !$comment->canEdit()) {
51
				register_error(elgg_echo('generic_comment:notfound'));
52
				forward(REFERER);
53
			}
54
55
			$target = $comment->getContainerEntity();
56
			if (!($target instanceof \ElggEntity)) {
57
				register_error(elgg_echo('generic_comment:notfound'));
58
				forward(REFERER);
59
			}
60
61
			$title = elgg_echo('generic_comments:edit');
62
			elgg_push_breadcrumb($target->getDisplayName(), $target->getURL());
63
			elgg_push_breadcrumb($title);
64
65
			$params = array(
66
				'entity' => $target,
67
				'comment' => $comment,
68
				'is_edit_page' => true,
69
			);
70
			$content = elgg_view_form('comment/save', null, $params);
0 ignored issues
show
Documentation introduced by
null is of type null, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
71
72
			$params = array(
73
				'content' => $content,
74
				'title' => $title,
75
				'filter' => '',
76
			);
77
			$body = elgg_view_layout('content', $params);
78
			echo elgg_view_page($title, $body);
79
80
			return true;
81
			break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
82
83
		case 'view':
84
			_elgg_comment_redirect(elgg_extract(1, $page), elgg_extract(2, $page));
85
			break;
86
87
		default:
88
			return false;
89
			break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
90
	}
91
}
92
93
/**
94
 * Redirect to the comment in context of the containing page
95
 *
96
 * @param int $comment_guid  GUID of the comment
97
 * @param int $fallback_guid GUID of the containing entity
98
 *
99
 * @return void
100
 * @access private
101
 */
102
function _elgg_comment_redirect($comment_guid, $fallback_guid) {
103
	$fail = function () {
104
		register_error(elgg_echo('generic_comment:notfound'));
105
		forward(REFERER);
106
	};
107
108
	$comment = get_entity($comment_guid);
109 View Code Duplication
	if (!$comment) {
110
		// try fallback if given
111
		$fallback = get_entity($fallback_guid);
112
		if (!$fallback) {
113
			$fail();
114
		}
115
116
		register_error(elgg_echo('generic_comment:notfound_fallback'));
117
		forward($fallback->getURL());
118
	}
119
120
	if (!elgg_instanceof($comment, 'object', 'comment')) {
121
		$fail();
122
	}
123
124
	$container = $comment->getContainerEntity();
125
	if (!$container) {
126
		$fail();
127
	}
128
129
	// this won't work with threaded comments, but core doesn't support that yet
130
	$count = elgg_get_entities([
131
		'type' => 'object',
132
		'subtype' => 'comment',
133
		'container_guid' => $container->guid,
134
		'count' => true,
135
		'wheres' => ["e.guid < " . (int)$comment->guid],
136
	]);
137
	$limit = (int)get_input('limit');
138
	if (!$limit) {
139
		$limit = elgg_trigger_plugin_hook('config', 'comments_per_page', [], 25);
140
	}
141
	$offset = floor($count / $limit) * $limit;
142
	if (!$offset) {
143
		$offset = null;
144
	}
145
146
	$url = elgg_http_add_url_query_elements($container->getURL(), [
147
			'offset' => $offset,
148
		]) . "#elgg-object-{$comment->guid}";
149
150
	forward($url);
151
}
152
153
/**
154
 * Setup the menu shown with a comment
155
 *
156
 * @param string         $hook   'register'
157
 * @param string         $type   'menu:entity'
158
 * @param \ElggMenuItem[] $return Array of \ElggMenuItem objects
159
 * @param array          $params Array of view vars
160
 *
161
 * @return array
162
 * @access private
163
 */
164
function _elgg_comment_setup_entity_menu($hook, $type, $return, $params) {
165
	if (elgg_in_context('widgets')) {
166
		return $return;
167
	}
168
169
	$entity = $params['entity'];
170
	if (!elgg_instanceof($entity, 'object', 'comment')) {
171
		return $return;
172
	}
173
174
	// Remove edit link and access level from the menu
175
	foreach ($return as $key => $item) {
176
		if ($item->getName() === 'access') {
177
			unset($return[$key]);
178
		}
179
	}
180
181
	return $return;
182
}
183
184
/**
185
 * Format and return the URL for a comment.
186
 *
187
 * This is the container's URL because comments don't have their own page.
188
 *
189
 * @param string $hook   'entity:url'
190
 * @param string $type   'object'
191
 * @param string $return URL for entity
192
 * @param array  $params Array with the elgg entity passed in as 'entity'
193
 *
194
 * @return string
195
 * @access private
196
 */
197
function _elgg_comment_url_handler($hook, $type, $return, $params) {
198
	$entity = $params['entity'];
199
	/* @var \ElggObject $entity */
200
201
	if (!elgg_instanceof($entity, 'object', 'comment') || !$entity->getOwnerEntity()) {
202
		// not a comment or has no owner
203
204
		// @todo handle anonymous comments
205
		return $return;
206
	}
207
208
	$container = $entity->getContainerEntity();
209
	if (!$container) {
210
		return $return;
211
	}
212
213
	return "comment/view/{$entity->guid}/{$container->guid}";
214
}
215
216
/**
217
 * Allow users to comment on entities not owned by them.
218
 *
219
 * Object being commented on is used as the container of the comment so
220
 * permission check must be overridden if user isn't the owner of the object.
221
 *
222
 * @param string  $hook   'container_permissions_check'
223
 * @param string  $type   'object'
224
 * @param boolean $return Can the current user write to this container?
225
 * @param array   $params Array of parameters (container, user, subtype)
226
 *
227
 * @return array
228
 * @access private
229
 * @todo this doesn't seem to make a difference if a user can comment or not
230
 */
231
function _elgg_comments_container_permissions_override($hook, $type, $return, $params) {
232
233
	// is someone trying to comment, if so override permissions check
234
	if ($params['subtype'] === 'comment') {
235
		return true;
236
	}
237
238
	return $return;
239
}
240
241
/**
242
 * By default, only authors can edit their comments.
243
 * 
244
 * @param string  $hook   'permissions_check'
245
 * @param string  $type   'object'
246
 * @param boolean $return Can the given user edit the given entity?
247
 * @param array   $params Array of parameters (entity, user)
248
 *
249
 * @return boolean Whether the given user is allowed to edit the given comment.
250
 */
251
function _elgg_comments_permissions_override($hook, $type, $return, $params) {
252
	$entity = $params['entity'];
253
	$user = $params['user'];
254
	
255
	if (elgg_instanceof($entity, 'object', 'comment') && $user) {
256
		return $entity->getOwnerGUID() == $user->getGUID();
257
	}
258
	
259
	return $return;
260
}
261
262
/**
263
 * Set subject for email notifications about new ElggComment objects
264
 *
265
 * The "Re: " part is required by some email clients in order to properly
266
 * group the notifications in threads.
267
 *
268
 * Group discussion replies extend ElggComment objects so this takes care
269
 * of their notifications also.
270
 *
271
 * @param string $hook        'email'
272
 * @param string $type        'system'
273
 * @param array  $returnvalue Current mail parameters
274
 * @param array  $params      Original mail parameters
275
 * @return array $returnvalue Modified mail parameters
276
 */
277
function _elgg_comments_notification_email_subject($hook, $type, $returnvalue, $params) {
278
	if (!is_array($returnvalue)) {
279
		// another hook handler returned a non-array, let's not override it
280
		return;
281
	}
282
283
	if (empty($returnvalue['params']['notification'])) {
284
		return;
285
	}
286
	
287
	/** @var Elgg\Notifications\Notification */
288
	$notification = $returnvalue['params']['notification'];
289
290
	if ($notification instanceof Elgg\Notifications\Notification) {
291
		$object = elgg_extract('object', $notification->params);
292
293
		if ($object instanceof ElggComment) {
294
			$container = $object->getContainerEntity();
295
296
			$returnvalue['subject'] = 'Re: ' . $container->getDisplayName();
297
		}
298
	}
299
300
	return $returnvalue;
301
}
302
303
/**
304
 * Update comment access to match that of the container
305
 * 
306
 * @param string     $event  'update:after'
307
 * @param string     $type   'all'
308
 * @param ElggEntity $entity The updated entity
309
 * @return bool
310
 * 
311
 * @access private
312
 */
313
function _elgg_comments_access_sync($event, $type, $entity) {
314
	if (!($entity instanceof \ElggEntity)) {
315
		return true;
316
	}
317
	
318
	// need to override access in case comments ended up with ACCESS_PRIVATE
319
	// and to ensure write permissions
320
	$ia = elgg_set_ignore_access(true);
321
	$options = array(
322
		'type' => 'object',
323
		'subtype' => 'comment',
324
		'container_guid' => $entity->getGUID(),
325
		'wheres' => array(
326
			"e.access_id != {$entity->access_id}"
327
		),
328
		'limit' => 0,
329
	);
330
331
	$batch = new \ElggBatch('elgg_get_entities', $options, null, 25, false);
332
	foreach ($batch as $comment) {
333
		// Update comment access_id
334
		$comment->access_id = $entity->access_id;
335
		$comment->save();
336
	}
337
		
338
	elgg_set_ignore_access($ia);
339
	
340
	return true;
341
}
342
343
/**
344
 * Runs unit tests for \ElggComment
345
 *
346
 * @param string $hook   unit_test
347
 * @param string $type   system
348
 * @param mixed  $value  Array of tests
349
 * @param mixed  $params Params
350
 *
351
 * @return array
352
 * @access private
353
 */
354
function _elgg_comments_test($hook, $type, $value, $params) {
355
	global $CONFIG;
356
	$value[] = "{$CONFIG->path}engine/tests/ElggCommentTest.php";
357
	return $value;
358
}
359
360
return function(\Elgg\EventsService $events, \Elgg\HooksRegistrationService $hooks) {
361
	$events->registerHandler('init', 'system', '_elgg_comments_init');
362
	$hooks->registerHandler('unit_test', 'system', '_elgg_comments_test');
363
};
364