Passed
Push — master ( c2d8e3...289151 )
by Jeroen
06:06
created

_elgg_comments_init()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 23
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 15
nc 1
nop 0
dl 0
loc 23
ccs 15
cts 15
cp 1
crap 1
rs 9.0856
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
use Elgg\Database\QueryBuilder;
11
12
/**
13
 * Comments initialization function
14
 *
15
 * @return void
16
 * @access private
17 31
 */
18
function _elgg_comments_init() {
19 31
	elgg_register_entity_type('object', 'comment');
20 31
	
21
	elgg_register_action('comment/save');
22 31
23 31
	elgg_register_plugin_hook_handler('container_permissions_check', 'object', '_elgg_comments_container_permissions_override');
24 31
	elgg_register_plugin_hook_handler('permissions_check', 'object', '_elgg_comments_permissions_override');
25 31
	elgg_register_plugin_hook_handler('email', 'system', '_elgg_comments_notification_email_subject');
26
	
27 31
	elgg_register_plugin_hook_handler('register', 'menu:social', '_elgg_comments_social_menu_setup');
28
	
29 31
	elgg_register_event_handler('update:after', 'all', '_elgg_comments_access_sync', 600);
30
31 31
	elgg_register_ajax_view('core/ajax/edit_comment');
32
	elgg_register_ajax_view('page/elements/comments');
33 31
	elgg_register_ajax_view('river/elements/responses');
34 31
35 31
	elgg_register_plugin_hook_handler('likes:is_likable', 'object:comment', 'Elgg\Values::getTrue');
36
	
37 31
	elgg_register_notification_event('object', 'comment', ['create']);
38
	elgg_register_plugin_hook_handler('get', 'subscriptions', '_elgg_comments_add_content_owner_to_subscriptions');
39 31
	elgg_register_plugin_hook_handler('prepare', 'notification:create:object:comment', '_elgg_comments_prepare_content_owner_notification');
40 31
	elgg_register_plugin_hook_handler('prepare', 'notification:create:object:comment', '_elgg_comments_prepare_notification');
41 31
}
42 31
43 31
/**
44
 * Are comments displayed with latest first?
45
 *
46
 * @param ElggEntity $container Entity containing comments
47
 * @return bool False means oldest first.
48
 * @since 3.0
49
 */
50
function elgg_comments_are_latest_first(ElggEntity $container = null) {
51
	$params = [
52
		'entity' => $container,
53
	];
54
	return (bool) elgg_trigger_plugin_hook('config', 'comments_latest_first', $params, true);
55
}
56
57
/**
58
 * How many comments appear per page.
59
 *
60
 * @param ElggEntity $container Entity containing comments
61
 * @return int
62
 * @since 3.0
63
 */
64
function elgg_comments_per_page(ElggEntity $container = null) {
65
	$params = [
66
		'entity' => $container,
67
	];
68
	return (int) elgg_trigger_plugin_hook('config', 'comments_per_page', $params, 25);
69
}
70
71
/**
72
 * Redirect to the comment in context of the containing page
73
 *
74
 * @param int $comment_guid  GUID of the comment
75
 * @param int $fallback_guid GUID of the containing entity
76
 *
77
 * @return void
78
 * @access private
79
 */
80
function _elgg_comment_redirect($comment_guid, $fallback_guid) {
81
	$fail = function () {
82
		register_error(elgg_echo('generic_comment:notfound'));
83
		forward(REFERER);
84
	};
85
86
	$comment = get_entity($comment_guid);
87
	if (!$comment) {
88
		// try fallback if given
89
		$fallback = get_entity($fallback_guid);
90
		if (!$fallback) {
91
			$fail();
92
		}
93
94
		register_error(elgg_echo('generic_comment:notfound_fallback'));
95
		forward($fallback->getURL());
96
	}
97
98
	if (!$comment instanceof ElggComment) {
99
		$fail();
100
	}
101
102
	$container = $comment->getContainerEntity();
103
	if (!$container) {
104
		$fail();
105
	}
106
107
	$operator = elgg_comments_are_latest_first($container) ? '>' : '<';
108
109
	// this won't work with threaded comments, but core doesn't support that yet
110
	$condition = function(QueryBuilder $qb) use ($comment, $operator) {
111
		return $qb->compare('e.guid', $operator, $comment->guid, ELGG_VALUE_INTEGER);
112
	};
113
	$count = elgg_get_entities([
114
		'type' => 'object',
115
		'subtype' => 'comment',
116
		'container_guid' => $container->guid,
117
		'count' => true,
118
		'wheres' => [$condition],
119
	]);
120
	$limit = (int) get_input('limit');
121
	if (!$limit) {
122
		$limit = elgg_comments_per_page($container);
123
	}
124
	$offset = floor($count / $limit) * $limit;
125
	if (!$offset) {
126
		$offset = null;
127
	}
128
129
	$url = elgg_http_add_url_query_elements($container->getURL(), [
130
		'offset' => $offset,
131
	]);
132
	
133
	// make sure there's only one fragment (#)
134
	$parts = parse_url($url);
135
	$parts['fragment'] = "elgg-object-{$comment->guid}";
136
	$url = elgg_http_build_url($parts, false);
137
	
138
	forward($url);
139
}
140
141
/**
142
 * Allow users to comment on entities not owned by them.
143
 *
144
 * Object being commented on is used as the container of the comment so
145
 * permission check must be overridden if user isn't the owner of the object.
146
 *
147
 * @param string  $hook   'container_permissions_check'
148
 * @param string  $type   'object'
149
 * @param boolean $return Can the current user write to this container?
150
 * @param array   $params Array of parameters (container, user, subtype)
151
 *
152
 * @return array
153
 * @access private
154 3
 * @todo this doesn't seem to make a difference if a user can comment or not
155
 */
156
function _elgg_comments_container_permissions_override($hook, $type, $return, $params) {
2 ignored issues
show
Unused Code introduced by
The parameter $type is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

156
function _elgg_comments_container_permissions_override($hook, /** @scrutinizer ignore-unused */ $type, $return, $params) {

This check looks for 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 $hook is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

156
function _elgg_comments_container_permissions_override(/** @scrutinizer ignore-unused */ $hook, $type, $return, $params) {

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

Loading history...
157 3
158
	// is someone trying to comment, if so override permissions check
159
	if ($params['subtype'] === 'comment') {
160
		return true;
0 ignored issues
show
Bug Best Practice introduced by
The expression return true returns the type true which is incompatible with the documented return type array.
Loading history...
161 3
	}
162
163
	return $return;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $return returns the type boolean which is incompatible with the documented return type array.
Loading history...
164
}
165
166
/**
167
 * By default, only authors can edit their comments.
168
 *
169
 * @param string  $hook   'permissions_check'
170
 * @param string  $type   'object'
171
 * @param boolean $return Can the given user edit the given entity?
172
 * @param array   $params Array of parameters (entity, user)
173
 *
174
 * @return boolean Whether the given user is allowed to edit the given comment.
175
 * @access private
176
 */
177
function _elgg_comments_permissions_override($hook, $type, $return, $params) {
2 ignored issues
show
Unused Code introduced by
The parameter $type is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

177
function _elgg_comments_permissions_override($hook, /** @scrutinizer ignore-unused */ $type, $return, $params) {

This check looks for 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 $hook is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

177
function _elgg_comments_permissions_override(/** @scrutinizer ignore-unused */ $hook, $type, $return, $params) {

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

Loading history...
178
	$entity = $params['entity'];
179
	$user = $params['user'];
180
	
181
	if ($entity instanceof ElggComment && $user) {
182
		return $entity->getOwnerGUID() == $user->getGUID();
183
	}
184
	
185
	return $return;
186
}
187
188
/**
189
 * Set subject for email notifications about new ElggComment objects
190 8
 *
191
 * The "Re: " part is required by some email clients in order to properly
192
 * group the notifications in threads.
193
 *
194 8
 * Group discussion replies extend ElggComment objects so this takes care
195
 * of their notifications also.
196
 *
197
 * @param string $hook        'email'
198
 * @param string $type        'system'
199
 * @param array  $returnvalue Current mail parameters
200
 * @param array  $params      Original mail parameters
201
 * @return array $returnvalue Modified mail parameters
202
 * @access private
203
 */
204
function _elgg_comments_notification_email_subject($hook, $type, $returnvalue, $params) {
3 ignored issues
show
Unused Code introduced by
The parameter $type is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

204
function _elgg_comments_notification_email_subject($hook, /** @scrutinizer ignore-unused */ $type, $returnvalue, $params) {

This check looks for 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. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

204
function _elgg_comments_notification_email_subject($hook, $type, $returnvalue, /** @scrutinizer ignore-unused */ $params) {

This check looks for 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 $hook is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

204
function _elgg_comments_notification_email_subject(/** @scrutinizer ignore-unused */ $hook, $type, $returnvalue, $params) {

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

Loading history...
205
	if (!is_array($returnvalue) || !is_array($returnvalue['params'])) {
206
		// another hook handler returned a non-array, let's not override it
207
		return;
208
	}
209 113
210 113
	if (empty($returnvalue['params']['notification'])) {
211
		return;
212 113
	}
213
	
214
	/** @var Elgg\Notifications\Notification */
215
	$notification = $returnvalue['params']['notification'];
216 113
217
	if ($notification instanceof Elgg\Notifications\Notification) {
218
		$object = elgg_extract('object', $notification->params);
219
220
		if ($object instanceof ElggComment) {
221
			$container = $object->getContainerEntity();
222
223
			$returnvalue['subject'] = 'Re: ' . $container->getDisplayName();
224
		}
225
	}
226
227
	return $returnvalue;
228
}
229
230
/**
231
 * Update comment access to match that of the container
232
 *
233
 * @param string     $event  'update:after'
234
 * @param string     $type   'all'
235
 * @param ElggEntity $entity The updated entity
236
 * @return bool
237
 *
238
 * @access private
239
 */
240
function _elgg_comments_access_sync($event, $type, $entity) {
2 ignored issues
show
Unused Code introduced by
The parameter $event is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

240
function _elgg_comments_access_sync(/** @scrutinizer ignore-unused */ $event, $type, $entity) {

This check looks for 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. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

240
function _elgg_comments_access_sync($event, /** @scrutinizer ignore-unused */ $type, $entity) {

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

Loading history...
241
	if (!($entity instanceof \ElggEntity)) {
242
		return true;
243
	}
244
	
245
	// need to override access in case comments ended up with ACCESS_PRIVATE
246
	// and to ensure write permissions
247
	$ia = elgg_set_ignore_access(true);
248
	$options = [
249
		'type' => 'object',
250
		'subtype' => 'comment',
251
		'container_guid' => $entity->getGUID(),
252
		'wheres' => [function(\Elgg\Database\QueryBuilder $qb) use ($entity) {
253
			return $qb->compare('e.access_id', '!=', $entity->access_id, 'integer');
254
		}],
255
		'limit' => 0,
256
	];
257
258
	$batch = new \ElggBatch('elgg_get_entities', $options, null, 25, false);
259
	foreach ($batch as $comment) {
260
		// Update comment access_id
261
		$comment->access_id = $entity->access_id;
262
		$comment->save();
263
	}
264
		
265
	elgg_set_ignore_access($ia);
266
	
267
	return true;
268
}
269
270
/**
271
 * Add the owner of the content being commented on to the subscribers
272 73
 *
273 63
 * @param string $hook        'get'
274
 * @param string $type        'subscribers'
275
 * @param array  $returnvalue current subscribers
276
 * @param array  $params      supplied params
277
 *
278 59
 * @return void|array
279
 *
280 59
 * @access private
281 59
 */
282 59
function _elgg_comments_add_content_owner_to_subscriptions($hook, $type, $returnvalue, $params) {
2 ignored issues
show
Unused Code introduced by
The parameter $hook is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

282
function _elgg_comments_add_content_owner_to_subscriptions(/** @scrutinizer ignore-unused */ $hook, $type, $returnvalue, $params) {

This check looks for 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. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

282
function _elgg_comments_add_content_owner_to_subscriptions($hook, /** @scrutinizer ignore-unused */ $type, $returnvalue, $params) {

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

Loading history...
283
	
284 59
	$event = elgg_extract('event', $params);
285 59
	if (!($event instanceof \Elgg\Notifications\NotificationEvent)) {
286 59
		return;
287
	}
288
	
289 59
	$object = $event->getObject();
290 59
	if (!$object instanceof ElggComment) {
291
		return;
292 1
	}
293 1
	
294
	$content_owner = $object->getContainerEntity()->getOwnerEntity();
295
	if (!($content_owner instanceof ElggUser)) {
296 59
		return;
297
	}
298 59
	
299
	$notification_settings = $content_owner->getNotificationSettings();
300
	if (empty($notification_settings)) {
301
		return;
302
	}
303
	
304
	$returnvalue[$content_owner->getGUID()] = [];
305
	foreach ($notification_settings as $method => $enabled) {
306
		if (empty($enabled)) {
307
			continue;
308
		}
309
		
310
		$returnvalue[$content_owner->getGUID()][] = $method;
311
	}
312
	
313
	return $returnvalue;
314
}
315 2
316 2
/**
317
 * Set the notification message for the owner of the content being commented on
318
 *
319
 * @param string                           $hook        'prepare'
320 2
 * @param string                           $type        'notification:create:object:comment'
321 2
 * @param \Elgg\Notifications\Notification $returnvalue current notification message
322 2
 * @param array                            $params      supplied params
323
 *
324
 * @return void|\Elgg\Notifications\Notification
325
 *
326
 * @access private
327
 */
328
function _elgg_comments_prepare_content_owner_notification($hook, $type, $returnvalue, $params) {
2 ignored issues
show
Unused Code introduced by
The parameter $hook is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

328
function _elgg_comments_prepare_content_owner_notification(/** @scrutinizer ignore-unused */ $hook, $type, $returnvalue, $params) {

This check looks for 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. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

328
function _elgg_comments_prepare_content_owner_notification($hook, /** @scrutinizer ignore-unused */ $type, $returnvalue, $params) {

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

Loading history...
329
	
330
	$comment = elgg_extract('object', $params);
331
	if (!$comment instanceof ElggComment) {
332
		return;
333
	}
334
	
335
	/* @var $content \ElggEntity */
336
	$content = $comment->getContainerEntity();
337
	$recipient = elgg_extract('recipient', $params);
338
	if ($content->owner_guid !== $recipient->guid) {
339
		// not the content owner
340
		return;
341
	}
342
	
343
	$language = elgg_extract('language', $params);
344
	/* @var $commenter \ElggUser */
345
	$commenter = $comment->getOwnerEntity();
346
	
347
	$returnvalue->subject = elgg_echo('generic_comment:notification:owner:subject', [], $language);
348
	$returnvalue->summary = elgg_echo('generic_comment:notification:owner:summary', [], $language);
349
	$returnvalue->body = elgg_echo('generic_comment:notification:owner:body', [
350
		$content->getDisplayName(),
351
		$commenter->getDisplayName(),
352
		$comment->description,
353
		$comment->getURL(),
354
		$commenter->getDisplayName(),
355
		$commenter->getURL(),
356
	], $language);
357
	
358
	return $returnvalue;
359
}
360
361
/**
362
 * Set the notification message for interested users
363
 *
364
 * @param string                           $hook        'prepare'
365
 * @param string                           $type        'notification:create:object:comment'
366
 * @param \Elgg\Notifications\Notification $returnvalue current notification message
367
 * @param array                            $params      supplied params
368
 *
369
 * @return void|\Elgg\Notifications\Notification
370
 *
371
 * @access private
372
 */
373
function _elgg_comments_prepare_notification($hook, $type, $returnvalue, $params) {
2 ignored issues
show
Unused Code introduced by
The parameter $hook is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

373
function _elgg_comments_prepare_notification(/** @scrutinizer ignore-unused */ $hook, $type, $returnvalue, $params) {

This check looks for 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. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

373
function _elgg_comments_prepare_notification($hook, /** @scrutinizer ignore-unused */ $type, $returnvalue, $params) {

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

Loading history...
374
	
375
	$comment = elgg_extract('object', $params);
376
	if (!$comment instanceof ElggComment) {
377
		return;
378
	}
379
	
380
	/* @var $content \ElggEntity */
381
	$content = $comment->getContainerEntity();
382
	$recipient = elgg_extract('recipient', $params);
383
	if ($content->getOwnerGUID() === $recipient->getGUID()) {
384
		// the content owner, this is handled in other hook
385
		return;
386
	}
387
	
388
	$language = elgg_extract('language', $params);
389
	/* @var $commenter \ElggUser */
390
	$commenter = $comment->getOwnerEntity();
391
	
392
	$returnvalue->subject = elgg_echo('generic_comment:notification:user:subject', [$content->getDisplayName()], $language);
393
	$returnvalue->summary = elgg_echo('generic_comment:notification:user:summary', [$content->getDisplayName()], $language);
394
	$returnvalue->body = elgg_echo('generic_comment:notification:user:body', [
395
		$content->getDisplayName(),
396
		$commenter->getDisplayName(),
397
		$comment->description,
398
		$comment->getURL(),
399
		$commenter->getDisplayName(),
400
		$commenter->getURL(),
401
	], $language);
402
403
	$returnvalue->url = $comment->getURL();
404
	
405
	return $returnvalue;
406
}
407
408
/**
409
 * Adds comment menu items to entity menu
410
 *
411
 * @param \Elgg\Hook $hook Hook information
412
 *
413
 * @return void|\ElggMenuItem[]
414
 *
415
 * @access private
416
 * @since 3.0
417
 */
418
function _elgg_comments_social_menu_setup(\Elgg\Hook $hook) {
419
	$entity = $hook->getEntityParam();
420
	if (!$entity) {
421
		return;
422
	}
423
	
424
	$return = $hook->getValue();
425
	
426
	$comment_count = $entity->countComments();
427
	$can_comment = $entity->canComment();
428
	if ($can_comment || $comment_count) {
429
		$text = $can_comment ? elgg_echo('comment:this') : elgg_echo('comments');
430
		
431
		$options = [
432
			'name' => 'comment',
433
			'icon' => 'speech-bubble',
434
			'badge' => $comment_count ?: null,
435
			'text' => $text,
436
			'title' => $text,
437
			'href' => $entity->getURL() . '#comments',
438
		];
439
				
440
		$item = $hook->getParam('item');
441
		if ($item && $can_comment) {
442
			$options['href'] = "#comments-add-{$entity->guid}-{$item->id}";
443
			$options['rel'] = 'toggle';
444
		}
445
		
446
		$return[] = \ElggMenuItem::factory($options);
447
	}
448
	
449
	return $return;
450 1
}
451 1
452
/**
453
 * Runs unit tests for \ElggComment
454
 *
455 1
 * @param string $hook   unit_test
456
 * @param string $type   system
457 1
 * @param mixed  $value  Array of tests
458 1
 * @param mixed  $params Params
459 1
 *
460
 * @return array
461
 * @access private
462
 * @codeCoverageIgnore
463
 */
464
function _elgg_comments_test($hook, $type, $value, $params) {
3 ignored issues
show
Unused Code introduced by
The parameter $hook is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

464
function _elgg_comments_test(/** @scrutinizer ignore-unused */ $hook, $type, $value, $params) {

This check looks for 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. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

464
function _elgg_comments_test($hook, $type, $value, /** @scrutinizer ignore-unused */ $params) {

This check looks for 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. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

464
function _elgg_comments_test($hook, /** @scrutinizer ignore-unused */ $type, $value, $params) {

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

Loading history...
465
	$value[] = ElggCoreCommentTest::class;
466
	return $value;
467
}
468
469
/**
470
 * @see \Elgg\Application::loadCore Do not do work here. Just register for events.
471
 */
472
return function(\Elgg\EventsService $events, \Elgg\HooksRegistrationService $hooks) {
473
	$events->registerHandler('init', 'system', '_elgg_comments_init');
474
	$hooks->registerHandler('unit_test', 'system', '_elgg_comments_test');
475
};
476