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 Juho Jaakkola
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 Juho Jaakkola
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 Juho Jaakkola
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 Ismayil Khayredinov
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 Ismayil Khayredinov
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 Ismayil Khayredinov
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 Cash Costello
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 Cash Costello
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 Ismayil Khayredinov
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 Matt Beckett
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 Matt Beckett
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 Matt Beckett
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 Matt Beckett
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 Steve Clay
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