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

update_river_access_by_object()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 15
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 7
nc 1
nop 2
dl 0
loc 15
rs 9.4285
c 0
b 0
f 0
ccs 5
cts 5
cp 1
crap 1
1
<?php
2
/**
3
 * Elgg river.
4
 * Activity stream functions.
5
 *
6
 * @package    Elgg.Core
7
 * @subpackage River
8
 */
9
10
/**
11
 * Adds an item to the river.
12
 *
13
 * @tip    Read the item like "Lisa (subject) posted (action)
14
 * a comment (object) on John's blog (target)".
15
 *
16
 * @param array $options Array in format:
17
 *
18
 * @option string $view The view that will handle the river item
19
 * @option string $action_type   An arbitrary string to define the action (eg 'comment', 'create')
20
 * @option int    $subject_guid  The GUID of the entity doing the action (default: current logged in user guid)
21
 * @option int    $object_guid   The GUID of the entity being acted upon
22
 * @option int    $target_guid   The GUID of the the object entity's container
23
 * @option int    $posted        The UNIX epoch timestamp of the river item (default: now)
24
 * @option int    $annotation_id The annotation ID associated with this river entry
25
 * @option bool   $return_item   set to true to return the ElggRiverItem created
26
 *
27
 * @return int|ElggRiverItem|bool River ID/item or false on failure
28
 * @since  1.9
29
 * @throws DatabaseException
30
 */
31
function elgg_create_river_item(array $options = []) {
32
33
	$view = elgg_extract('view', $options, '');
34
	// use default viewtype for when called from web services api
35
	if (!empty($view) && !elgg_view_exists($view, 'default')) {
36
		return false;
37
	}
38
39
	$action_type = elgg_extract('action_type', $options);
40
	if (empty($action_type)) {
41 85
		return false;
42
	}
43 85
44 1
	$subject_guid = elgg_extract('subject_guid', $options, elgg_get_logged_in_user_guid());
45
	if (!($subject = get_entity($subject_guid))) {
0 ignored issues
show
Unused Code introduced by
The assignment to $subject is dead and can be removed.
Loading history...
46
		return false;
47 84
	}
48 84
49 1
	$object_guid = elgg_extract('object_guid', $options, 0);
50
	if (!($object = get_entity($object_guid))) {
0 ignored issues
show
Unused Code introduced by
The assignment to $object is dead and can be removed.
Loading history...
51
		return false;
52 84
	}
53 84
54 2
	$target_guid = elgg_extract('target_guid', $options, 0);
55
	if ($target_guid) {
56
		// target_guid is not a required parameter so check
57 84
		// it only if it is included in the parameters
58 84
		if (!($target = get_entity($target_guid))) {
0 ignored issues
show
Unused Code introduced by
The assignment to $target is dead and can be removed.
Loading history...
59 2
			return false;
60
		}
61
	}
62 83
63 83
	$posted = elgg_extract('posted', $options, time());
64
65
	$annotation_id = elgg_extract('annotation_id', $options, 0);
66 74
	if ($annotation_id) {
67 1
		if (!elgg_get_annotation_from_id($annotation_id)) {
68
			return false;
69
		}
70
	}
71 82
72
	$return_item = elgg_extract('return_item', $options, false);
73 82
74
	$values = [
75 82
		'action_type' => $action_type,
76 82
		'view' => $view,
77
		'subject_guid' => $subject_guid,
78
		'object_guid' => $object_guid,
79
		'target_guid' => $target_guid,
80
		'annotation_id' => $annotation_id,
81
		'posted' => $posted,
82 82
	];
83
	$col_types = [
84
		'action_type' => ELGG_VALUE_STRING,
85 82
		'view' => ELGG_VALUE_STRING,
86 82
		'subject_guid' => ELGG_VALUE_INTEGER,
87 82
		'object_guid' => ELGG_VALUE_INTEGER,
88 82
		'target_guid' => ELGG_VALUE_INTEGER,
89 82
		'annotation_id' => ELGG_VALUE_INTEGER,
90 82
		'posted' => ELGG_VALUE_INTEGER,
91 82
	];
92 82
93 82
	// return false to stop insert
94 82
	$values = elgg_trigger_plugin_hook('creating', 'river', null, $values);
95
	if ($values == false) {
96
		// inserting did not fail - it was just prevented
97 82
		return true;
98
	}
99
100
	$qb = \Elgg\Database\Insert::intoTable('river');
101
	foreach ($values as $name => $value) {
102
		$query_params[$name] = $qb->param($value, $col_types[$name]);
103
	}
104
	$qb->values($query_params);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $query_params seems to be defined by a foreach iteration on line 101. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
105
106
	$id = _elgg_services()->db->insertData($qb);
107
	if (!$id) {
108
		return false;
109
	}
110 82
111 82
	if (!$return_item) {
112
		return $id;
113 1
	}
114
115
	$ia = elgg_set_ignore_access(true);
116 81
	$item = elgg_get_river_item_from_id($id);
117 81
	elgg_set_ignore_access($ia);
118 81
119
	if (!$item) {
120 81
		return false;
121
	}
122 81
123 81
	elgg_trigger_event('created', 'river', $item);
124
125
	return $item;
126
}
127 81
128 77
/**
129
 * Get river items
130
 *
131 5
 * @note If using types and subtypes in a query, they are joined with an AND.
132 5
 *
133 5
 * @param array $options Parameters:
134
 *   ids                  => INT|ARR River item id(s)
135 5
 *   subject_guids        => INT|ARR Subject guid(s)
136
 *   object_guids         => INT|ARR Object guid(s)
137
 *   target_guids         => INT|ARR Target guid(s)
138
 *   action_types         => STR|ARR The river action type(s) identifier
139 5
 *   posted_time_lower    => INT     The lower bound on the time posted
140
 *   posted_time_upper    => INT     The upper bound on the time posted
141 5
 *
142
 *   Additionally accepts all "annotation_*" options supported by {@link elgg_get_entities()}
143
 *   annotation_ids       => INT|ARR The identifier of the annotation(s)
144
 *
145
 *   types                => STR|ARR Entity type string(s)
146
 *   subtypes             => STR|ARR Entity subtype string(s)
147
 *   type_subtype_pairs   => ARR     Array of type => subtype pairs where subtype
148
 *                                   can be an array of subtype strings
149
 *
150
 *   Additionally accepts all "relationship_*" options supported by {@link elgg_get_entities()}
151
 *   relationship         => STR     Relationship identifier
152
 *   relationship_guid    => INT|ARR Entity guid(s)
153
 *   inverse_relationship => BOOL    Subject or object of the relationship (false)
154
 *   relationship_join_on => STR     subject_guid|object_guid|target_guid (defaults to subject_guid)
155
 *
156
 *   limit                => INT     Number to show per page (20)
157
 *   offset               => INT     Offset in list (0)
158
 *   count                => BOOL    Count the river items? (false)
159
 *   order_by             => STR     Order by clause (rv.posted desc)
160
 *   group_by             => STR     Group by clause
161
 *
162
 *   distinct             => BOOL    If set to false, Elgg will drop the DISTINCT
163
 *                                   clause from the MySQL query, which will improve
164
 *                                   performance in some situations. Avoid setting this
165
 *                                   option without a full understanding of the
166
 *                                   underlying SQL query Elgg creates. (true)
167
 *
168
 *   batch                => BOOL    If set to true, an Elgg\BatchResult object will be returned
169
 *                                   instead of an array. (false) Since 2.3.
170
 *
171
 *   batch_inc_offset     => BOOL    If "batch" is used, this tells the batch to increment the offset
172
 *                                   on each fetch. This must be set to false if you delete the batched
173
 *                                   results. (true)
174
 *
175
 *   batch_size           => INT     If "batch" is used, this is the number of entities/rows to pull
176
 *                                   in before requesting more. (25)
177
 *
178
 * @return \ElggRiverItem[]|\Elgg\BatchResult|array|int
179
 * @since 1.8.0
180
 */
181
function elgg_get_river(array $options = []) {
182
	return \Elgg\Database\River::find($options);
183
}
184
185
/**
186
 * Get river item from its ID
187
 *
188
 * @param int $id ID
189
 * @return ElggRiverItem|false
190
 */
191
function elgg_get_river_item_from_id($id) {
192
	$items = elgg_get_river([
193
		'id' => $id,
194
	]);
195
196
	return $items ? $items[0] : false;
197
}
198 215
199
/**
200
 * Delete river items based on $options.
201
 *
202
 * @warning Unlike elgg_get_river() this will not accept an empty options array!
203
 *          This requires at least one constraint: id(s), annotation_id(s)
204
 *          subject_guid(s), object_guid(s), target_guid(s)
205
 *          or view(s) must be set.
206
 *
207
 * @param array $options An options array. {@link elgg_get_river()}
208 5
 *
209 5
 * @return bool|null true on success, false on failure, null if no metadata to delete.
210
 *
211
 * @since   1.8.0
212 5
 */
213
function elgg_delete_river(array $options = []) {
214
215
	if (!_elgg_is_valid_options_for_batch_operation($options, 'river')) {
216
		// requirements not met
217
		return false;
218
	}
219
220
	$options['batch'] = true;
221
	$options['batch_size'] = 25;
222
	$options['batch_inc_offset'] = false;
223
224
	$river = elgg_get_river($options);
225
	$count = $river->count();
0 ignored issues
show
Bug introduced by
The method count() does not exist on integer. ( Ignorable by Annotation )

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

225
	/** @scrutinizer ignore-call */ 
226
 $count = $river->count();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
226
227
	if (!$count) {
228
		return;
229
	}
230
231 215
	$success = 0;
232
	foreach ($river as $river_item) {
0 ignored issues
show
Bug introduced by
The expression $river of type integer is not traversable.
Loading history...
233
		if ($river_item->delete()) {
234
			$success++;
235
		}
236 215
	}
237 215
238 215
	return $success == $count;
239
}
240 215
241 215
/**
242
 * List river items
243 215
 *
244 215
 * @param array $options Any options from elgg_get_river() plus:
245
 *   item_view  => STR         Alternative view to render list items
246
 *   pagination => BOOL        Display pagination links (true)
247 7
 *   no_results => STR|Closure Message to display if no items
248 7
 *
249 7
 * @return string
250 7
 * @since 1.8.0
251
 */
252
function elgg_list_river(array $options = []) {
253
	elgg_register_rss_link();
254 7
255
	$defaults = [
256
		'offset'     => (int) max(get_input('offset', 0), 0),
257
		'limit'      => (int) max(get_input('limit', max(20, _elgg_config()->default_limit)), 0),
258
		'pagination' => true,
259
		'list_class' => 'elgg-list-river',
260
		'no_results' => '',
261
	];
262
263
	$options = array_merge($defaults, $options);
264
265
	if (!$options["limit"] && !$options["offset"]) {
266
		// no need for pagination if listing is unlimited
267
		$options["pagination"] = false;
268
	}
269
270
	$options['count'] = true;
271
	$count = elgg_get_river($options);
272
273
	if ($count > 0) {
274
		$options['count'] = false;
275
		$items = elgg_get_river($options);
276
	} else {
277
		$items = [];
278
	}
279
280
	$options['count'] = $count;
281
	$options['items'] = $items;
282
283
	return elgg_view('page/components/list', $options);
284
}
285
286
/**
287
 * Register river unit tests
288
 *
289
 * @param string $hook  'unit_test'
290
 * @param string $type  'system'
291
 * @param array  $value current return value
292
 *
293
 * @return array
294
 * @codeCoverageIgnore
295
 */
296
function _elgg_river_test($hook, $type, $value) {
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

296
function _elgg_river_test($hook, /** @scrutinizer ignore-unused */ $type, $value) {

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

296
function _elgg_river_test(/** @scrutinizer ignore-unused */ $hook, $type, $value) {

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...
297
	$value[] = ElggCoreRiverAPITest::class;
0 ignored issues
show
Bug introduced by
The type ElggCoreRiverAPITest was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
298
	return $value;
299
}
300
301
/**
302
 * Disable river entries that reference a disabled entity as subject/object/target
303
 *
304
 * @param string     $event  'disable'
305
 * @param string     $type   'all'
306
 * @param ElggEntity $entity The entity being disabled
307
 *
308
 * @return void
309
 *
310
 * @access private
311
 */
312 5
function _elgg_river_disable($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

312
function _elgg_river_disable(/** @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

312
function _elgg_river_disable($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...
313
314 5
	if (!$entity instanceof ElggEntity) {
315
		return;
316
	}
317
318
	$dbprefix = _elgg_config()->dbprefix;
319
	$query = <<<QUERY
320 5
	UPDATE {$dbprefix}river AS rv
321 5
	SET rv.enabled = 'no'
322
	WHERE (rv.subject_guid = {$entity->guid} OR rv.object_guid = {$entity->guid} OR rv.target_guid = {$entity->guid});
323
QUERY;
324 5
325
	update_data($query);
326
	return;
327
}
328
329
330
/**
331
 * Enable river entries that reference a re-enabled entity as subject/object/target
332
 *
333
 * @param string     $event  'enable'
334
 * @param string     $type   'all'
335
 * @param ElggEntity $entity The entity being enabled
336
 *
337
 * @return void
338
 *
339
 * @access private
340
 */
341
function _elgg_river_enable($event, $type, $entity) {
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

341
function _elgg_river_enable($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...
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

341
function _elgg_river_enable(/** @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...
342
343
	if (!$entity instanceof ElggEntity) {
344
		return;
345
	}
346
347
	$dbprefix = _elgg_config()->dbprefix;
348
	$query = <<<QUERY
349
	UPDATE {$dbprefix}river AS rv
350
	LEFT JOIN {$dbprefix}entities AS se ON se.guid = rv.subject_guid
351
	LEFT JOIN {$dbprefix}entities AS oe ON oe.guid = rv.object_guid
352
	LEFT JOIN {$dbprefix}entities AS te ON te.guid = rv.target_guid
353
	SET rv.enabled = 'yes'
354
	WHERE (
355 4
			(se.enabled = 'yes' OR se.guid IS NULL) AND
356
			(oe.enabled = 'yes' OR oe.guid IS NULL) AND
357
			(te.enabled = 'yes' OR te.guid IS NULL)
358
		)
359 4
		AND (se.guid = {$entity->guid} OR oe.guid = {$entity->guid} OR te.guid = {$entity->guid});
360
QUERY;
361 4
362
	update_data($query);
363 4
	return;
364
}
365
366 4
/**
367 4
 * Add the delete to river actions menu
368
 *
369
 * @param \Elgg\Hook $hook 'register' 'menu:river'
370
 *
371
 * @return void|ElggMenuItem[]
372
 *
373
 * @access private
374
 */
375
function _elgg_river_menu_setup(\Elgg\Hook $hook) {
376
	if (!elgg_is_logged_in()) {
377
		return;
378
	}
379
380
	$item = $hook->getParam('item');
381
	if (!($item instanceof ElggRiverItem)) {
382
		return;
383
	}
384 3
385
	if (!$item->canDelete()) {
386
		return;
387
	}
388 3
389
	$return = $hook->getValue();
390 3
391 3
	$return[] = \ElggMenuItem::factory([
392 3
		'name' => 'delete',
393 3
		'href' => "action/river/delete?id={$item->id}",
394
		'is_action' => true,
395
		'icon' => 'delete',
396
		'text' => elgg_echo('river:delete'),
397
		'confirm' => elgg_echo('deleteconfirm'),
398
		'priority' => 999,
399
	]);
400 3
401
	return $return;
402
}
403 3
404 3
/**
405
 * Initialize river library
406
 *
407
 * @return void
408
 *
409
 * @access private
410
 */
411
function _elgg_river_init() {
412
413
	elgg_register_plugin_hook_handler('unit_test', 'system', '_elgg_river_test');
414
415
	elgg_register_plugin_hook_handler('register', 'menu:river', '_elgg_river_menu_setup');
416
}
417 1
418 1
/**
419
 * @see \Elgg\Application::loadCore Do not do work here. Just register for events.
420
 */
421
return function(\Elgg\EventsService $events, \Elgg\HooksRegistrationService $hooks) {
1 ignored issue
show
Unused Code introduced by
The parameter $hooks 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

421
return function(\Elgg\EventsService $events, /** @scrutinizer ignore-unused */ \Elgg\HooksRegistrationService $hooks) {

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...
422
	$events->registerHandler('init', 'system', '_elgg_river_init');
423
	$events->registerHandler('disable:after', 'all', '_elgg_river_disable', 600);
424
	$events->registerHandler('enable:after', 'all', '_elgg_river_enable', 600);
425
};
426