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']) { |
|
|
|
|
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
|
|
|
|
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.