Passed
Push — master ( f13f78...5c1b24 )
by Ismayil
04:22
created

engine/lib/metastrings.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * Elgg metastrngs
4
 * Functions to manage object metastrings.
5
 *
6
 * @package Elgg.Core
7
 * @subpackage DataModel.MetaStrings
8
 */
9
10
use Elgg\Project\Paths;
11
12
/**
13
 * Returns an array of either \ElggAnnotation or \ElggMetadata objects.
14
 * Accepts all elgg_get_entities() options for entity restraints.
15
 *
16
 * @see elgg_get_entities
17
 *
18
 * @param array $options Array in format:
19
 *
20
 * 	metastring_names              => null|ARR metastring names
21
 *
22
 * 	metastring_values             => null|ARR metastring values
23
 *
24
 * 	metastring_ids                => null|ARR metastring ids
25
 *
26
 * 	metastring_case_sensitive     => BOOL     Overall Case sensitive
27
 *
28
 *  metastring_owner_guids        => null|ARR Guids for metadata owners
29
 *
30
 *  metastring_created_time_lower => INT      Lower limit for created time.
31
 *
32
 *  metastring_created_time_upper => INT      Upper limit for created time.
33
 *
34
 *  metastring_calculation        => STR      Perform the MySQL function on the metastring values
35
 *                                            returned.
36
 *                                            This differs from egef_annotation_calculation in that
37
 *                                            it returns only the calculation of all annotation values.
38
 *                                            You can sum, avg, count, etc. egef_annotation_calculation()
39
 *                                            returns \ElggEntities ordered by a calculation on their
40
 *                                            annotation values.
41
 *
42
 *  metastring_type               => STR      metadata or annotation(s)
43
 *
44
 * @return \ElggExtender[]|int An array or count of metastring based objects
45
 * @access private
46
 */
47
function _elgg_get_metastring_based_objects($options) {
48 98
	$options = _elgg_normalize_metastrings_options($options);
49
50 98
	switch ($options['metastring_type']) {
51 98
		case 'metadata':
52 97
			$type = 'metadata';
53 97
			$callback = 'row_to_elggmetadata';
54 97
			break;
55
56 2
		case 'annotations':
57
		case 'annotation':
58 2
			$type = 'annotations';
59 2
			$callback = 'row_to_elggannotation';
60 2
			break;
61
62
		default:
63
			return false;
64
	}
65
66
	$defaults = [
67
		// entities
68 98
		'types' => ELGG_ENTITIES_ANY_VALUE,
69
		'subtypes' => ELGG_ENTITIES_ANY_VALUE,
70
		'type_subtype_pairs' => ELGG_ENTITIES_ANY_VALUE,
71
72
		'guids' => ELGG_ENTITIES_ANY_VALUE,
73
		'owner_guids' => ELGG_ENTITIES_ANY_VALUE,
74
		'container_guids' => ELGG_ENTITIES_ANY_VALUE,
75
76
		'modified_time_lower' => ELGG_ENTITIES_ANY_VALUE,
77
		'modified_time_upper' => ELGG_ENTITIES_ANY_VALUE,
78
		'created_time_lower' => ELGG_ENTITIES_ANY_VALUE,
79
		'created_time_upper' => ELGG_ENTITIES_ANY_VALUE,
80
81
		// options are normalized to the plural in case we ever add support for them.
82
		'metastring_names' => ELGG_ENTITIES_ANY_VALUE,
83
		'metastring_values' => ELGG_ENTITIES_ANY_VALUE,
84
85
		'metastring_case_sensitive' => true,
86
		'metastring_calculation' => ELGG_ENTITIES_NO_VALUE,
87
88
		'metastring_created_time_lower' => ELGG_ENTITIES_ANY_VALUE,
89
		'metastring_created_time_upper' => ELGG_ENTITIES_ANY_VALUE,
90
91
		'metastring_owner_guids' => ELGG_ENTITIES_ANY_VALUE,
92
		
93
		'metastring_ids' => ELGG_ENTITIES_ANY_VALUE,
94
95
		// sql
96 98
		'order_by' => 'n_table.time_created ASC, n_table.id ASC',
97 98
		'limit' => _elgg_config()->default_limit,
98 98
		'offset' => 0,
99
		'count' => false,
100
		'selects' => [],
101
		'wheres' => [],
102
		'joins' => [],
103
104
		'distinct' => true,
105
		'preload_owners' => false,
106 98
		'callback' => $callback,
107
108
		'batch' => false,
109
		'batch_inc_offset' => true,
110 98
		'batch_size' => 25,
111
	];
112
113 98
	$options = array_merge($defaults, $options);
114
115 98 View Code Duplication
	if ($options['batch'] && !$options['count']) {
1 ignored issue
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
116
		$batch_size = $options['batch_size'];
117
		$batch_inc_offset = $options['batch_inc_offset'];
118
119
		// clean batch keys from $options.
120
		unset($options['batch'], $options['batch_size'], $options['batch_inc_offset']);
121
122
		return new \ElggBatch('_elgg_get_metastring_based_objects', $options, null, $batch_size, $batch_inc_offset);
123
	}
124
125
	// can't use helper function with type_subtype_pair because
126
	// it's already an array...just need to merge it
127 98 View Code Duplication
	if (isset($options['type_subtype_pair'])) {
128
		if (isset($options['type_subtype_pairs'])) {
129
			$options['type_subtype_pairs'] = array_merge($options['type_subtype_pairs'],
130
				$options['type_subtype_pair']);
131
		} else {
132
			$options['type_subtype_pairs'] = $options['type_subtype_pair'];
133
		}
134
	}
135
136
	$singulars = [
137 98
		'type', 'subtype', 'type_subtype_pair',
138
		'guid', 'owner_guid', 'container_guid',
139
		'metastring_name', 'metastring_value',
140
		'metastring_owner_guid', 'metastring_id',
141
		'select', 'where', 'join'
142
	];
143
144 98
	$options = _elgg_normalize_plural_options_array($options, $singulars);
145
146 98
	if (!$options) {
147
		return false;
148
	}
149
150 98
	$db_prefix = _elgg_config()->dbprefix;
151
152
	// evaluate where clauses
153 98
	if (!is_array($options['wheres'])) {
154
		$options['wheres'] = [$options['wheres']];
155
	}
156
157 98
	$wheres = $options['wheres'];
158
159
	// entities
160 98
	$wheres[] = _elgg_services()->entityTable->getEntityTypeSubtypeWhereSql('e', $options['types'],
161 98
		$options['subtypes'], $options['type_subtype_pairs']);
162
163 98
	$wheres[] = _elgg_get_guid_based_where_sql('e.guid', $options['guids']);
164 98
	$wheres[] = _elgg_get_guid_based_where_sql('e.owner_guid', $options['owner_guids']);
165 98
	$wheres[] = _elgg_get_guid_based_where_sql('e.container_guid', $options['container_guids']);
166
167 98
	$wheres[] = _elgg_get_entity_time_where_sql('e', $options['created_time_upper'],
168 98
		$options['created_time_lower'], $options['modified_time_upper'], $options['modified_time_lower']);
169
170
171 98
	$wheres[] = _elgg_get_entity_time_where_sql('n_table', $options['metastring_created_time_upper'],
172 98
		$options['metastring_created_time_lower'], null, null);
173
174 98
	$wheres[] = _elgg_get_guid_based_where_sql('n_table.owner_guid',
175 98
		$options['metastring_owner_guids']);
176
177
	// see if any functions failed
178
	// remove empty strings on successful functions
179 98 View Code Duplication
	foreach ($wheres as $i => $where) {
180 98
		if ($where === false) {
181
			return false;
182
		} elseif (empty($where)) {
183 98
			unset($wheres[$i]);
184
		}
185
	}
186
187
	// remove identical where clauses
188 98
	$wheres = array_unique($wheres);
189
190
	// evaluate join clauses
191 98 View Code Duplication
	if (!is_array($options['joins'])) {
192
		$options['joins'] = [$options['joins']];
193
	}
194
195 98
	$joins = [];
196 98
	$joins[] = "JOIN {$db_prefix}entities e ON n_table.entity_guid = e.guid";
197
198
	// evaluate selects
199 98
	if (!is_array($options['selects'])) {
200
		$options['selects'] = [$options['selects']];
201
	}
202
203 98
	$selects = $options['selects'];
204
205
	// add optional joins
206 98
	$joins = array_merge($joins, $options['joins']);
207
208
	// metastrings
209 98
	$metastring_clauses = _elgg_get_metastring_sql('n_table', $options['metastring_names'],
210 98
		$options['metastring_values'], null, $options['metastring_ids'],
211 98
		$options['metastring_case_sensitive'], $type);
212
213 98
	if ($metastring_clauses) {
214 96
		$wheres = array_merge($wheres, $metastring_clauses['wheres']);
215 96
		$joins = array_merge($joins, $metastring_clauses['joins']);
216 View Code Duplication
	} else {
217 2
		if ($type === 'annotations') {
218 2
			$wheres[] = _elgg_get_access_where_sql([
219 2
				'table_alias' => 'n_table',
220
				'guid_column' => 'entity_guid',
221
			]);
222
		}
223
	}
224
225 98
	$distinct = $options['distinct'] ? "DISTINCT " : "";
226
227 98
	if ($options['metastring_calculation'] === ELGG_ENTITIES_NO_VALUE && !$options['count']) {
228 98
		$selects = array_unique($selects);
229
		// evalutate selects
230 98
		$select_str = '';
231 98
		if ($selects) {
232
			foreach ($selects as $select) {
233
				$select_str .= ", $select";
234
			}
235
		}
236
237 98
		$query = "SELECT $distinct n_table.*{$select_str} FROM {$db_prefix}$type n_table";
238
	} elseif ($options['count']) {
239
		// count is over the entities
240
		$query = "SELECT count($distinct e.guid) as calculation FROM {$db_prefix}$type n_table";
241
	} else {
242
		$query = "SELECT {$options['metastring_calculation']}(n_table.value) as calculation FROM {$db_prefix}$type n_table";
243
	}
244
245 98 View Code Duplication
	foreach ($joins as $i => $join) {
246 98
		if ($join === false) {
247
			return false;
248
		} elseif (empty($join)) {
249 98
			unset($joins[$i]);
250
		}
251
	}
252
253
	// remove identical join clauses
254 98
	$joins = array_unique($joins);
255
256
	// add joins
257 98
	foreach ($joins as $j) {
258 98
		$query .= " $j ";
259
	}
260
261
	// add wheres
262 98
	$query .= ' WHERE ';
263
264 98
	foreach ($wheres as $w) {
265 98
		$query .= " $w AND ";
266
	}
267
268
	// Add access controls
269 98
	$query .= _elgg_get_access_where_sql(['table_alias' => 'e']);
270
271
	// reverse order by
272 98
	if (isset($options['reverse_order_by']) && $options['reverse_order_by']) {
273
		$options['order_by'] = _elgg_sql_reverse_order_by_clause($options['order_by']);
274
	}
275
276 98
	if ($options['metastring_calculation'] === ELGG_ENTITIES_NO_VALUE && !$options['count']) {
277 98
		if (isset($options['group_by'])) {
278
			$options['group_by'] = sanitise_string($options['group_by']);
279
			$query .= " GROUP BY {$options['group_by']}";
280
		}
281
282 98 View Code Duplication
		if (isset($options['order_by']) && $options['order_by']) {
283 98
			$options['order_by'] = sanitise_string($options['order_by']);
284 98
			$query .= " ORDER BY {$options['order_by']}, n_table.id";
285
		}
286
287 98 View Code Duplication
		if ($options['limit']) {
288 98
			$limit = sanitise_int($options['limit']);
289 98
			$offset = sanitise_int($options['offset'], false);
290 98
			$query .= " LIMIT $offset, $limit";
291
		}
292
293 98
		$dt = get_data($query, $options['callback']);
294
295 98
		if ($options['preload_owners'] && is_array($dt) && count($dt) > 1) {
296
			_elgg_services()->entityPreloader->preload($dt, ['owner_guid']);
297
		}
298
299 98
		return $dt;
300
	} else {
301
		$result = get_data_row($query);
302
		return $result->calculation;
303
	}
304
}
305
306
/**
307
 * Returns an array of joins and wheres for use in metastrings.
308
 *
309
 * @note The $pairs is reserved for name/value pairs if we want to implement those.
310
 *
311
 * @param string $table          The annotation or metadata table name or alias
312
 * @param array  $names          An array of names
313
 * @param array  $values         An array of values
314
 * @param array  $pairs          Name / value pairs. Not currently used.
315
 * @param array  $ids            Metastring IDs
316
 * @param bool   $case_sensitive Should name and values be case sensitive?
317
 * @param string $type           "metadata" or "annotations"
318
 *
319
 * @return array
320
 * @access private
321
 */
322
function _elgg_get_metastring_sql($table, $names = null, $values = null,
323
	$pairs = null, $ids = null, $case_sensitive = false, $type = null) {
324
325 98
	if ($type !== 'metadata' && $type !== 'annotations') {
326
		throw new \InvalidArgumentException('$type must be "metadata" or "annotations"');
327
	}
328
329 98
	if ((!$names && $names !== 0)
330 98
		&& (!$values && $values !== 0)
331 98
		&& !$ids
332 98
		&& (!$pairs && $pairs !== 0)) {
333 2
		return [];
334
	}
335
336 96
	$db_prefix = _elgg_config()->dbprefix;
337
338
	// binary forces byte-to-byte comparision of strings, making
339
	// it case- and diacritical-mark- sensitive.
340
	// only supported on values.
341 96
	$binary = ($case_sensitive) ? ' BINARY ' : '';
342
343
	$return =  [
344 96
		'joins' =>  [],
345
		'wheres' => []
346
	];
347
348 96
	$wheres = [];
349
350
	// get names wheres and joins
351 96
	$names_where = '';
352 96
	if ($names !== null) {
353
		if (!is_array($names)) {
354
			$names = [$names];
355
		}
356
357
		$sanitised_names = [];
358
		foreach ($names as $name) {
359
			// normalise to 0.
360
			if (!$name) {
361
				$name = '0';
362
			}
363
			$sanitised_names[] = '\'' . sanitise_string($name) . '\'';
364
		}
365
366
		if ($names_str = implode(',', $sanitised_names)) {
367
			$names_where = "($table.name IN ($names_str))";
368
		}
369
	}
370
371
	// get values wheres and joins
372 96
	$values_where = '';
373 96
	if ($values !== null) {
374
		if (!is_array($values)) {
375
			$values = [$values];
376
		}
377
378
		$sanitised_values = [];
379
		foreach ($values as $value) {
380
			// normalize to 0
381
			if (!$value) {
382
				$value = 0;
383
			}
384
			$sanitised_values[] = '\'' . sanitise_string($value) . '\'';
385
		}
386
387
		if ($values_str = implode(',', $sanitised_values)) {
388
			$values_where = "({$binary}$table.value IN ($values_str))";
389
		}
390
	}
391
	
392 96
	if ($ids !== null) {
393 96
		if (!is_array($ids)) {
394
			$ids = [$ids];
395
		}
396 96
		$ids_str = implode(',', $ids);
397 96
		if ($ids_str) {
398 96
			$wheres[] = "n_table.id IN ($ids_str)";
399
		}
400
	}
401
402 96 View Code Duplication
	if ($names_where && $values_where) {
403
		$wheres[] = "($names_where AND $values_where)";
404 96
	} elseif ($names_where) {
405
		$wheres[] = $names_where;
406 96
	} elseif ($values_where) {
407
		$wheres[] = $values_where;
408
	}
409
410 96 View Code Duplication
	if ($type === 'annotations') {
411
		$wheres[] = _elgg_get_access_where_sql([
412
			'table_alias' => $table,
413
			'guid_column' => 'entity_guid',
414
		]);
415
	}
416
417 96
	if ($where = implode(' AND ', $wheres)) {
418 96
		$return['wheres'][] = "($where)";
419
	}
420
421 96
	return $return;
422
}
423
424
/**
425
 * Normalizes metadata / annotation option names to their corresponding metastrings name.
426
 *
427
 * @param array $options An options array
428
 * @return array
429
 * @access private
430
 */
431
function _elgg_normalize_metastrings_options(array $options = []) {
432
433
	// support either metastrings_type or metastring_type
434
	// because I've made this mistake many times and hunting it down is a pain...
435 98
	$type = elgg_extract('metastring_type', $options, null);
436 98
	$type = elgg_extract('metastrings_type', $options, $type);
437
438 98
	$options['metastring_type'] = $type;
439
440
	// support annotation_ and annotations_ because they're way too easy to confuse
441 98
	$prefixes = ['metadata_', 'annotation_', 'annotations_'];
442
443
	// map the metadata_* options to metastring_* options
444
	$map = [
445 98
		'names'                 => 'metastring_names',
446
		'values'                => 'metastring_values',
447
		'case_sensitive'        => 'metastring_case_sensitive',
448
		'owner_guids'           => 'metastring_owner_guids',
449
		'created_time_lower'    => 'metastring_created_time_lower',
450
		'created_time_upper'    => 'metastring_created_time_upper',
451
		'calculation'           => 'metastring_calculation',
452
		'ids'                   => 'metastring_ids',
453
	];
454
455 98
	foreach ($prefixes as $prefix) {
456 98
		$singulars = ["{$prefix}name", "{$prefix}value", "{$prefix}owner_guid", "{$prefix}id"];
457 98
		$options = _elgg_normalize_plural_options_array($options, $singulars);
458
459 98
		foreach ($map as $specific => $normalized) {
460 98
			$key = $prefix . $specific;
461 98
			if (isset($options[$key])) {
462 98
				$options[$normalized] = $options[$key];
463
			}
464
		}
465
	}
466
467 98
	return $options;
468
}
469
470
/**
471
 * Enables or disables a metastrings-based object by its id.
472
 *
473
 * @warning To enable disabled metastrings you must first use
474
 * {@link access_show_hidden_entities()}.
475
 *
476
 * @param int    $id      The object's ID
477
 * @param string $enabled Value to set to: yes or no
478
 * @param string $type    Metastring type: metadata or annotation
479
 *
480
 * @return bool
481
 * @throws InvalidParameterException
482
 * @access private
483
 */
484
function _elgg_set_metastring_based_object_enabled_by_id($id, $enabled, $type) {
485 1
	$id = (int) $id;
486 1
	$db_prefix = _elgg_config()->dbprefix;
487
488 1
	$object = _elgg_get_metastring_based_object_from_id($id, $type);
489
490
	switch ($type) {
491 1
		case 'annotation':
492 1
		case 'annotations':
493
			$type = 'annotation';
494
			$table = "{$db_prefix}annotations";
495
			break;
496
497 1
		case 'metadata':
498 1
			$table = "{$db_prefix}metadata";
499 1
			break;
500
	}
501
502 1
	if ($enabled === 'yes' || $enabled === 1 || $enabled === true) {
503 1
		$enabled = 'yes';
504 1
		$event = 'enable';
505 1
	} elseif ($enabled === 'no' || $enabled === 0 || $enabled === false) {
506 1
		$enabled = 'no';
507 1
		$event = 'disable';
508
	} else {
509
		return false;
510
	}
511
512 1
	$return = false;
513
514 1
	if ($object) {
515
		// don't set it if it's already set.
516 1
		if ($object->enabled == $enabled) {
517
			$return = false;
518 1
		} elseif ($object->canEdit() && (elgg_trigger_event($event, $type, $object))) {
519 1
			$return = update_data("UPDATE $table SET enabled = :enabled where id = :id", [
520 1
				':enabled' => $enabled,
521 1
				':id' => $id,
522
			]);
523
		}
524
	}
525
526 1
	return $return;
527
}
528
529
/**
530
 * Runs metastrings-based objects found using $options through $callback
531
 *
532
 * @warning Unlike _elgg_get_metastring_based_objects() this will not accept an
533
 * empty options array!
534
 *
535
 * @warning This returns null on no ops.
536
 *
537
 * @param array  $options    An options array. {@link _elgg_get_metastring_based_objects()}
538
 * @param string $callback   The callback to pass each result through
539
 * @param bool   $inc_offset Increment the offset? Pass false for callbacks that delete / disable
540
 *
541
 * @return bool|null true on success, false on failure, null if no objects are found.
542
 * @access private
543
 */
544
function _elgg_batch_metastring_based_objects(array $options, $callback, $inc_offset = true) {
545 2
	if (!$options || !is_array($options)) {
546
		return false;
547
	}
548
549 2
	$batch = new \ElggBatch('_elgg_get_metastring_based_objects', $options, $callback, 50, $inc_offset);
550 2
	return $batch->callbackResult;
551
}
552
553
/**
554
 * Returns a singular metastring-based object by its ID.
555
 *
556
 * @param int    $id   The metastring-based object's ID
557
 * @param string $type The type: annotation or metadata
558
 * @return \ElggExtender
559
 * @access private
560
 */
561
function _elgg_get_metastring_based_object_from_id($id, $type) {
562 96
	$id = (int) $id;
563 96
	if (!$id) {
564
		return false;
565
	}
566
567
	$options = [
568 96
		'metastring_type' => $type,
569 96
		'metastring_id' => $id,
570
	];
571
572 96
	$obj = _elgg_get_metastring_based_objects($options);
573
574 96
	if ($obj && count($obj) == 1) {
575 96
		return $obj[0];
576
	}
577
578
	return false;
579
}
580
581
/**
582
 * Deletes a metastring-based object by its id
583
 *
584
 * @param int    $id   The object's ID
585
 * @param string $type The object's metastring type: annotation or metadata
586
 * @return bool
587
 * @access private
588
 */
589
function _elgg_delete_metastring_based_object_by_id($id, $type) {
590 1
	$id = (int) $id;
591 1
	$db_prefix = _elgg_config()->dbprefix;
592
593
	switch ($type) {
594 1
		case 'annotations':
595 1
		case 'annotation':
596
			$table = $db_prefix . 'annotations';
597
			$type = 'annotation';
598
			break;
599
600 1
		case 'metadata':
601 1
			$table = $db_prefix . 'metadata';
602 1
			$type = 'metadata';
603 1
			break;
604
605
		default:
606
			return false;
607
	}
608
609 1
	$obj = _elgg_get_metastring_based_object_from_id($id, $type);
610
611 1
	if ($obj) {
612 1
		if ($obj->canEdit()) {
613 1
			if (elgg_trigger_event('delete', $type, $obj)) {
614 1
				return (bool) delete_data("DELETE FROM $table WHERE id = :id", [
615 1
					':id' => $id,
616
				]);
617
			}
618
		}
619
	}
620
621
	return false;
622
}
623
624
/**
625
 * Returns options to pass to elgg_get_entities() for metastrings operations.
626
 *
627
 * @param string $type    Metastring type: annotation or metadata
628
 * @param array  $options Options
629
 *
630
 * @return array
631
 * @access private
632
 */
633
function _elgg_entities_get_metastrings_options($type, $options) {
634
	$valid_types = ['metadata', 'annotation'];
635
	if (!in_array($type, $valid_types)) {
636
		return false;
637
	}
638
639
	// the options for annotations are singular (annotation_name) but the table
640
	// is plural (elgg_annotations) so rewrite for the table name.
641
	$n_table = ($type == 'annotation') ? 'annotations' : $type;
642
643
	$singulars = ["{$type}_name", "{$type}_value",
644
		"{$type}_name_value_pair", "{$type}_owner_guid"];
645
	$options = _elgg_normalize_plural_options_array($options, $singulars);
646
647
	$clauses = _elgg_get_entity_metadata_where_sql('e', $n_table, $options["{$type}_names"],
648
		$options["{$type}_values"], $options["{$type}_name_value_pairs"],
649
		$options["{$type}_name_value_pairs_operator"], $options["{$type}_case_sensitive"],
650
		$options["order_by_{$type}"], $options["{$type}_owner_guids"]);
651
652
	if ($clauses) {
653
		// merge wheres to pass to elgg_get_entities()
654
		if (isset($options['wheres']) && !is_array($options['wheres'])) {
655
			$options['wheres'] = [$options['wheres']];
656
		} elseif (!isset($options['wheres'])) {
657
			$options['wheres'] = [];
658
		}
659
660
		$options['wheres'] = array_merge($options['wheres'], $clauses['wheres']);
661
662
		// merge joins to pass to elgg_get_entities()
663
		if (isset($options['joins']) && !is_array($options['joins'])) {
664
			$options['joins'] = [$options['joins']];
665
		} elseif (!isset($options['joins'])) {
666
			$options['joins'] = [];
667
		}
668
669
		$options['joins'] = array_merge($options['joins'], $clauses['joins']);
670
671
		if ($clauses['orders']) {
672
			$order_by_metadata = implode(", ", $clauses['orders']);
673 View Code Duplication
			if (isset($options['order_by']) && $options['order_by']) {
674
				$options['order_by'] = "$order_by_metadata, {$options['order_by']}";
675
			} else {
676
				$options['order_by'] = "$order_by_metadata, e.time_created DESC";
677
			}
678
		}
679
	}
680
681
	return $options;
682
}
683
684
/**
685
 * Metastring unit tests
686
 *
687
 * @param string $hook  unit_test
688
 * @param string $type  system
689
 * @param array  $value Array of other tests
690
 *
691
 * @return array
692
 * @access private
693
 */
694
function _elgg_metastrings_test($hook, $type, $value) {
695
	$value[] = Paths::elgg() . 'engine/tests/simpletest/ElggCoreMetastringsTest.php';
696
	return $value;
697
}
698
699
/**
700
 * @see \Elgg\Application::loadCore Do not do work here. Just register for events.
701
 */
702
return function(\Elgg\EventsService $events, \Elgg\HooksRegistrationService $hooks) {
703
	$hooks->registerHandler('unit_test', 'system', '_elgg_metastrings_test');
704
};
705