1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Elgg metastrngs |
4
|
|
|
* Functions to manage object metastrings. |
5
|
|
|
* |
6
|
|
|
* @package Elgg.Core |
7
|
|
|
* @subpackage DataModel.MetaStrings |
8
|
|
|
*/ |
9
|
|
|
|
10
|
|
|
/** |
11
|
|
|
* Gets the metastring identifier for a value. |
12
|
|
|
* |
13
|
|
|
* Elgg normalizes the names and values of annotations and metadata. This function |
14
|
|
|
* provides the identifier used as the index in the metastrings table. Plugin |
15
|
|
|
* developers should only use this if denormalizing names/values for performance |
16
|
|
|
* reasons (to avoid multiple joins on the metastrings table). |
17
|
|
|
* |
18
|
|
|
* @param string $string The value |
19
|
|
|
* @param bool $case_sensitive Should the retrieval be case sensitive? |
20
|
|
|
* If not, there may be more than one result |
21
|
|
|
* |
22
|
|
|
* @return int|array metastring id or array of ids |
23
|
|
|
* @since 1.9.0 |
24
|
|
|
*/ |
25
|
|
|
function elgg_get_metastring_id($string, $case_sensitive = true) { |
26
|
|
|
return _elgg_services()->metastringsTable->getId($string, $case_sensitive); |
27
|
|
|
} |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* Add a metastring. |
31
|
|
|
* |
32
|
|
|
* @warning You should not call this directly. Use elgg_get_metastring_id(). |
33
|
|
|
* |
34
|
|
|
* @param string $string The value to be normalized |
35
|
|
|
* @return int The identifier for this string |
36
|
|
|
*/ |
37
|
|
|
function _elgg_add_metastring($string) { |
38
|
|
|
return _elgg_services()->metastringsTable->add($string); |
39
|
|
|
} |
40
|
|
|
|
41
|
|
|
/** |
42
|
|
|
* Returns an array of either \ElggAnnotation or \ElggMetadata objects. |
43
|
|
|
* Accepts all elgg_get_entities() options for entity restraints. |
44
|
|
|
* |
45
|
|
|
* @see elgg_get_entities |
46
|
|
|
* |
47
|
|
|
* @param array $options Array in format: |
48
|
|
|
* |
49
|
|
|
* metastring_names => null|ARR metastring names |
50
|
|
|
* |
51
|
|
|
* metastring_values => null|ARR metastring values |
52
|
|
|
* |
53
|
|
|
* metastring_ids => null|ARR metastring ids |
54
|
|
|
* |
55
|
|
|
* metastring_case_sensitive => BOOL Overall Case sensitive |
56
|
|
|
* |
57
|
|
|
* metastring_owner_guids => null|ARR Guids for metadata owners |
58
|
|
|
* |
59
|
|
|
* metastring_created_time_lower => INT Lower limit for created time. |
60
|
|
|
* |
61
|
|
|
* metastring_created_time_upper => INT Upper limit for created time. |
62
|
|
|
* |
63
|
|
|
* metastring_calculation => STR Perform the MySQL function on the metastring values |
64
|
|
|
* returned. |
65
|
|
|
* This differs from egef_annotation_calculation in that |
66
|
|
|
* it returns only the calculation of all annotation values. |
67
|
|
|
* You can sum, avg, count, etc. egef_annotation_calculation() |
68
|
|
|
* returns \ElggEntities ordered by a calculation on their |
69
|
|
|
* annotation values. |
70
|
|
|
* |
71
|
|
|
* metastring_type => STR metadata or annotation(s) |
72
|
|
|
* |
73
|
|
|
* @return \ElggExtender[]|int An array or count of metastring based objects |
74
|
|
|
* @access private |
75
|
|
|
*/ |
76
|
|
|
function _elgg_get_metastring_based_objects($options) { |
77
|
|
|
$options = _elgg_normalize_metastrings_options($options); |
78
|
|
|
|
79
|
|
|
switch ($options['metastring_type']) { |
80
|
|
|
case 'metadata': |
81
|
|
|
$type = 'metadata'; |
82
|
|
|
$callback = 'row_to_elggmetadata'; |
83
|
|
|
break; |
84
|
|
|
|
85
|
|
|
case 'annotations': |
86
|
|
|
case 'annotation': |
87
|
|
|
$type = 'annotations'; |
88
|
|
|
$callback = 'row_to_elggannotation'; |
89
|
|
|
break; |
90
|
|
|
|
91
|
|
|
default: |
92
|
|
|
return false; |
93
|
|
|
} |
94
|
|
|
|
95
|
|
|
$defaults = array( |
96
|
|
|
// entities |
97
|
|
|
'types' => ELGG_ENTITIES_ANY_VALUE, |
98
|
|
|
'subtypes' => ELGG_ENTITIES_ANY_VALUE, |
99
|
|
|
'type_subtype_pairs' => ELGG_ENTITIES_ANY_VALUE, |
100
|
|
|
|
101
|
|
|
'guids' => ELGG_ENTITIES_ANY_VALUE, |
102
|
|
|
'owner_guids' => ELGG_ENTITIES_ANY_VALUE, |
103
|
|
|
'container_guids' => ELGG_ENTITIES_ANY_VALUE, |
104
|
|
|
'site_guids' => get_config('site_guid'), |
105
|
|
|
|
106
|
|
|
'modified_time_lower' => ELGG_ENTITIES_ANY_VALUE, |
107
|
|
|
'modified_time_upper' => ELGG_ENTITIES_ANY_VALUE, |
108
|
|
|
'created_time_lower' => ELGG_ENTITIES_ANY_VALUE, |
109
|
|
|
'created_time_upper' => ELGG_ENTITIES_ANY_VALUE, |
110
|
|
|
|
111
|
|
|
// options are normalized to the plural in case we ever add support for them. |
112
|
|
|
'metastring_names' => ELGG_ENTITIES_ANY_VALUE, |
113
|
|
|
'metastring_values' => ELGG_ENTITIES_ANY_VALUE, |
114
|
|
|
//'metastring_name_value_pairs' => ELGG_ENTITIES_ANY_VALUE, |
115
|
|
|
//'metastring_name_value_pairs_operator' => 'AND', |
116
|
|
|
|
117
|
|
|
'metastring_case_sensitive' => true, |
118
|
|
|
//'order_by_metastring' => array(), |
119
|
|
|
'metastring_calculation' => ELGG_ENTITIES_NO_VALUE, |
120
|
|
|
|
121
|
|
|
'metastring_created_time_lower' => ELGG_ENTITIES_ANY_VALUE, |
122
|
|
|
'metastring_created_time_upper' => ELGG_ENTITIES_ANY_VALUE, |
123
|
|
|
|
124
|
|
|
'metastring_owner_guids' => ELGG_ENTITIES_ANY_VALUE, |
125
|
|
|
|
126
|
|
|
'metastring_ids' => ELGG_ENTITIES_ANY_VALUE, |
127
|
|
|
|
128
|
|
|
// sql |
129
|
|
|
'order_by' => 'n_table.time_created ASC, n_table.id ASC', |
130
|
|
|
'limit' => elgg_get_config('default_limit'), |
131
|
|
|
'offset' => 0, |
132
|
|
|
'count' => false, |
133
|
|
|
'selects' => array(), |
134
|
|
|
'wheres' => array(), |
135
|
|
|
'joins' => array(), |
136
|
|
|
|
137
|
|
|
'distinct' => true, |
138
|
|
|
'preload_owners' => false, |
139
|
|
|
'callback' => $callback, |
140
|
|
|
); |
141
|
|
|
|
142
|
|
|
// @todo Ignore site_guid right now because of #2910 |
143
|
|
|
$options['site_guid'] = ELGG_ENTITIES_ANY_VALUE; |
144
|
|
|
|
145
|
|
|
$options = array_merge($defaults, $options); |
146
|
|
|
|
147
|
|
|
// can't use helper function with type_subtype_pair because |
148
|
|
|
// it's already an array...just need to merge it |
149
|
|
View Code Duplication |
if (isset($options['type_subtype_pair'])) { |
150
|
|
|
if (isset($options['type_subtype_pairs'])) { |
151
|
|
|
$options['type_subtype_pairs'] = array_merge($options['type_subtype_pairs'], |
152
|
|
|
$options['type_subtype_pair']); |
153
|
|
|
} else { |
154
|
|
|
$options['type_subtype_pairs'] = $options['type_subtype_pair']; |
155
|
|
|
} |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
$singulars = array( |
159
|
|
|
'type', 'subtype', 'type_subtype_pair', |
160
|
|
|
'guid', 'owner_guid', 'container_guid', 'site_guid', |
161
|
|
|
'metastring_name', 'metastring_value', |
162
|
|
|
'metastring_owner_guid', 'metastring_id', |
163
|
|
|
'select', 'where', 'join' |
164
|
|
|
); |
165
|
|
|
|
166
|
|
|
$options = _elgg_normalize_plural_options_array($options, $singulars); |
167
|
|
|
|
168
|
|
|
if (!$options) { |
|
|
|
|
169
|
|
|
return false; |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
$db_prefix = elgg_get_config('dbprefix'); |
173
|
|
|
|
174
|
|
|
// evaluate where clauses |
175
|
|
|
if (!is_array($options['wheres'])) { |
176
|
|
|
$options['wheres'] = array($options['wheres']); |
177
|
|
|
} |
178
|
|
|
|
179
|
|
|
$wheres = $options['wheres']; |
180
|
|
|
|
181
|
|
|
// entities |
182
|
|
|
$wheres[] = _elgg_get_entity_type_subtype_where_sql('e', $options['types'], |
183
|
|
|
$options['subtypes'], $options['type_subtype_pairs']); |
184
|
|
|
|
185
|
|
|
$wheres[] = _elgg_get_guid_based_where_sql('e.guid', $options['guids']); |
186
|
|
|
$wheres[] = _elgg_get_guid_based_where_sql('e.owner_guid', $options['owner_guids']); |
187
|
|
|
$wheres[] = _elgg_get_guid_based_where_sql('e.container_guid', $options['container_guids']); |
188
|
|
|
$wheres[] = _elgg_get_guid_based_where_sql('e.site_guid', $options['site_guids']); |
189
|
|
|
|
190
|
|
|
$wheres[] = _elgg_get_entity_time_where_sql('e', $options['created_time_upper'], |
191
|
|
|
$options['created_time_lower'], $options['modified_time_upper'], $options['modified_time_lower']); |
192
|
|
|
|
193
|
|
|
|
194
|
|
|
$wheres[] = _elgg_get_entity_time_where_sql('n_table', $options['metastring_created_time_upper'], |
195
|
|
|
$options['metastring_created_time_lower'], null, null); |
196
|
|
|
|
197
|
|
|
$wheres[] = _elgg_get_guid_based_where_sql('n_table.owner_guid', |
198
|
|
|
$options['metastring_owner_guids']); |
199
|
|
|
|
200
|
|
|
// see if any functions failed |
201
|
|
|
// remove empty strings on successful functions |
202
|
|
View Code Duplication |
foreach ($wheres as $i => $where) { |
203
|
|
|
if ($where === false) { |
204
|
|
|
return false; |
205
|
|
|
} elseif (empty($where)) { |
206
|
|
|
unset($wheres[$i]); |
207
|
|
|
} |
208
|
|
|
} |
209
|
|
|
|
210
|
|
|
// remove identical where clauses |
211
|
|
|
$wheres = array_unique($wheres); |
212
|
|
|
|
213
|
|
|
// evaluate join clauses |
214
|
|
|
if (!is_array($options['joins'])) { |
215
|
|
|
$options['joins'] = array($options['joins']); |
216
|
|
|
} |
217
|
|
|
|
218
|
|
|
$joins = array(); |
219
|
|
|
$joins[] = "JOIN {$db_prefix}entities e ON n_table.entity_guid = e.guid"; |
220
|
|
|
|
221
|
|
|
// evaluate selects |
222
|
|
|
if (!is_array($options['selects'])) { |
223
|
|
|
$options['selects'] = array($options['selects']); |
224
|
|
|
} |
225
|
|
|
|
226
|
|
|
$selects = $options['selects']; |
227
|
|
|
|
228
|
|
|
// For performance reasons we don't want the joins required for metadata / annotations |
229
|
|
|
// unless we're going through one of their callbacks. |
230
|
|
|
// this means we expect the functions passing different callbacks to pass their required joins. |
231
|
|
|
// If we're doing a calculation |
232
|
|
|
$custom_callback = ($options['callback'] == 'row_to_elggmetadata' |
233
|
|
|
|| $options['callback'] == 'row_to_elggannotation'); |
234
|
|
|
$is_calculation = $options['metastring_calculation'] ? true : false; |
235
|
|
|
|
236
|
|
|
if ($custom_callback || $is_calculation) { |
237
|
|
|
$joins[] = "JOIN {$db_prefix}metastrings n on n_table.name_id = n.id"; |
238
|
|
|
$joins[] = "JOIN {$db_prefix}metastrings v on n_table.value_id = v.id"; |
239
|
|
|
|
240
|
|
|
$selects[] = 'n.string as name'; |
241
|
|
|
$selects[] = 'v.string as value'; |
242
|
|
|
} |
243
|
|
|
|
244
|
|
|
// add optional joins |
245
|
|
|
$joins = array_merge($joins, $options['joins']); |
246
|
|
|
|
247
|
|
|
// metastrings |
248
|
|
|
$metastring_clauses = _elgg_get_metastring_sql('n_table', $options['metastring_names'], |
249
|
|
|
$options['metastring_values'], null, $options['metastring_ids'], |
250
|
|
|
$options['metastring_case_sensitive']); |
251
|
|
|
|
252
|
|
|
if ($metastring_clauses) { |
|
|
|
|
253
|
|
|
$wheres = array_merge($wheres, $metastring_clauses['wheres']); |
254
|
|
|
$joins = array_merge($joins, $metastring_clauses['joins']); |
255
|
|
|
} else { |
256
|
|
|
$wheres[] = _elgg_get_access_where_sql(array( |
257
|
|
|
'table_alias' => 'n_table', |
258
|
|
|
'guid_column' => 'entity_guid', |
259
|
|
|
)); |
260
|
|
|
} |
261
|
|
|
|
262
|
|
|
$distinct = $options['distinct'] ? "DISTINCT " : ""; |
263
|
|
|
|
264
|
|
|
if ($options['metastring_calculation'] === ELGG_ENTITIES_NO_VALUE && !$options['count']) { |
265
|
|
|
$selects = array_unique($selects); |
266
|
|
|
// evalutate selects |
267
|
|
|
$select_str = ''; |
268
|
|
|
if ($selects) { |
|
|
|
|
269
|
|
|
foreach ($selects as $select) { |
270
|
|
|
$select_str .= ", $select"; |
271
|
|
|
} |
272
|
|
|
} |
273
|
|
|
|
274
|
|
|
$query = "SELECT $distinct n_table.*{$select_str} FROM {$db_prefix}$type n_table"; |
275
|
|
|
} elseif ($options['count']) { |
276
|
|
|
// count is over the entities |
277
|
|
|
$query = "SELECT count($distinct e.guid) as calculation FROM {$db_prefix}$type n_table"; |
278
|
|
|
} else { |
279
|
|
|
$query = "SELECT {$options['metastring_calculation']}(v.string) as calculation FROM {$db_prefix}$type n_table"; |
280
|
|
|
} |
281
|
|
|
|
282
|
|
View Code Duplication |
foreach ($joins as $i => $join) { |
283
|
|
|
if ($join === false) { |
284
|
|
|
return false; |
285
|
|
|
} elseif (empty($join)) { |
286
|
|
|
unset($joins[$i]); |
287
|
|
|
} |
288
|
|
|
} |
289
|
|
|
|
290
|
|
|
// remove identical join clauses |
291
|
|
|
$joins = array_unique($joins); |
292
|
|
|
|
293
|
|
|
// add joins |
294
|
|
|
foreach ($joins as $j) { |
295
|
|
|
$query .= " $j "; |
296
|
|
|
} |
297
|
|
|
|
298
|
|
|
// add wheres |
299
|
|
|
$query .= ' WHERE '; |
300
|
|
|
|
301
|
|
|
foreach ($wheres as $w) { |
302
|
|
|
$query .= " $w AND "; |
303
|
|
|
} |
304
|
|
|
|
305
|
|
|
// Add access controls |
306
|
|
|
$query .= _elgg_get_access_where_sql(array('table_alias' => 'e')); |
307
|
|
|
|
308
|
|
|
// reverse order by |
309
|
|
|
if (isset($options['reverse_order_by']) && $options['reverse_order_by']) { |
310
|
|
|
$options['order_by'] = _elgg_sql_reverse_order_by_clause($options['order_by']); |
311
|
|
|
} |
312
|
|
|
|
313
|
|
|
if ($options['metastring_calculation'] === ELGG_ENTITIES_NO_VALUE && !$options['count']) { |
314
|
|
|
if (isset($options['group_by'])) { |
315
|
|
|
$options['group_by'] = sanitise_string($options['group_by']); |
316
|
|
|
$query .= " GROUP BY {$options['group_by']}"; |
317
|
|
|
} |
318
|
|
|
|
319
|
|
View Code Duplication |
if (isset($options['order_by']) && $options['order_by']) { |
320
|
|
|
$options['order_by'] = sanitise_string($options['order_by']); |
321
|
|
|
$query .= " ORDER BY {$options['order_by']}, n_table.id"; |
322
|
|
|
} |
323
|
|
|
|
324
|
|
View Code Duplication |
if ($options['limit']) { |
325
|
|
|
$limit = sanitise_int($options['limit']); |
326
|
|
|
$offset = sanitise_int($options['offset'], false); |
327
|
|
|
$query .= " LIMIT $offset, $limit"; |
328
|
|
|
} |
329
|
|
|
|
330
|
|
|
$dt = get_data($query, $options['callback']); |
331
|
|
|
|
332
|
|
|
if ($options['preload_owners'] && is_array($dt) && count($dt) > 1) { |
333
|
|
|
_elgg_services()->entityPreloader->preload($dt, ['owner_guid']); |
334
|
|
|
} |
335
|
|
|
|
336
|
|
|
return $dt; |
337
|
|
|
} else { |
338
|
|
|
$result = get_data_row($query); |
339
|
|
|
return $result->calculation; |
340
|
|
|
} |
341
|
|
|
} |
342
|
|
|
|
343
|
|
|
/** |
344
|
|
|
* Returns an array of joins and wheres for use in metastrings. |
345
|
|
|
* |
346
|
|
|
* @note The $pairs is reserved for name/value pairs if we want to implement those. |
347
|
|
|
* |
348
|
|
|
* @param string $table The annotation or metadata table name or alias |
349
|
|
|
* @param array $names An array of names |
350
|
|
|
* @param array $values An array of values |
351
|
|
|
* @param array $pairs Name / value pairs. Not currently used. |
352
|
|
|
* @param array $ids Metastring IDs |
353
|
|
|
* @param bool $case_sensitive Should name and values be case sensitive? |
354
|
|
|
* |
355
|
|
|
* @return array |
356
|
|
|
* @access private |
357
|
|
|
*/ |
358
|
|
|
function _elgg_get_metastring_sql($table, $names = null, $values = null, |
359
|
|
|
$pairs = null, $ids = null, $case_sensitive = false) { |
360
|
|
|
|
361
|
|
|
if ((!$names && $names !== 0) |
362
|
|
|
&& (!$values && $values !== 0) |
363
|
|
|
&& !$ids |
364
|
|
|
&& (!$pairs && $pairs !== 0)) { |
365
|
|
|
|
366
|
|
|
return array(); |
367
|
|
|
} |
368
|
|
|
|
369
|
|
|
$db_prefix = elgg_get_config('dbprefix'); |
370
|
|
|
|
371
|
|
|
// binary forces byte-to-byte comparision of strings, making |
372
|
|
|
// it case- and diacritical-mark- sensitive. |
373
|
|
|
// only supported on values. |
374
|
|
|
$binary = ($case_sensitive) ? ' BINARY ' : ''; |
375
|
|
|
|
376
|
|
|
$return = array ( |
377
|
|
|
'joins' => array (), |
378
|
|
|
'wheres' => array() |
379
|
|
|
); |
380
|
|
|
|
381
|
|
|
$wheres = array(); |
382
|
|
|
|
383
|
|
|
// get names wheres and joins |
384
|
|
|
$names_where = ''; |
385
|
|
View Code Duplication |
if ($names !== null) { |
386
|
|
|
if (!is_array($names)) { |
387
|
|
|
$names = array($names); |
388
|
|
|
} |
389
|
|
|
|
390
|
|
|
$sanitised_names = array(); |
391
|
|
|
foreach ($names as $name) { |
392
|
|
|
// normalise to 0. |
393
|
|
|
if (!$name) { |
394
|
|
|
$name = '0'; |
395
|
|
|
} |
396
|
|
|
$sanitised_names[] = '\'' . sanitise_string($name) . '\''; |
397
|
|
|
} |
398
|
|
|
|
399
|
|
|
if ($names_str = implode(',', $sanitised_names)) { |
400
|
|
|
$return['joins'][] = "JOIN {$db_prefix}metastrings msn on $table.name_id = msn.id"; |
401
|
|
|
$names_where = "(msn.string IN ($names_str))"; |
402
|
|
|
} |
403
|
|
|
} |
404
|
|
|
|
405
|
|
|
// get values wheres and joins |
406
|
|
|
$values_where = ''; |
407
|
|
View Code Duplication |
if ($values !== null) { |
408
|
|
|
if (!is_array($values)) { |
409
|
|
|
$values = array($values); |
410
|
|
|
} |
411
|
|
|
|
412
|
|
|
$sanitised_values = array(); |
413
|
|
|
foreach ($values as $value) { |
414
|
|
|
// normalize to 0 |
415
|
|
|
if (!$value) { |
416
|
|
|
$value = 0; |
417
|
|
|
} |
418
|
|
|
$sanitised_values[] = '\'' . sanitise_string($value) . '\''; |
419
|
|
|
} |
420
|
|
|
|
421
|
|
|
if ($values_str = implode(',', $sanitised_values)) { |
422
|
|
|
$return['joins'][] = "JOIN {$db_prefix}metastrings msv on $table.value_id = msv.id"; |
423
|
|
|
$values_where = "({$binary}msv.string IN ($values_str))"; |
424
|
|
|
} |
425
|
|
|
} |
426
|
|
|
|
427
|
|
|
if ($ids !== null) { |
428
|
|
|
if (!is_array($ids)) { |
429
|
|
|
$ids = array($ids); |
430
|
|
|
} |
431
|
|
|
|
432
|
|
|
$ids_str = implode(',', $ids); |
433
|
|
|
|
434
|
|
|
if ($ids_str) { |
435
|
|
|
$wheres[] = "n_table.id IN ($ids_str)"; |
436
|
|
|
} |
437
|
|
|
} |
438
|
|
|
|
439
|
|
View Code Duplication |
if ($names_where && $values_where) { |
440
|
|
|
$wheres[] = "($names_where AND $values_where)"; |
441
|
|
|
} elseif ($names_where) { |
442
|
|
|
$wheres[] = $names_where; |
443
|
|
|
} elseif ($values_where) { |
444
|
|
|
$wheres[] = $values_where; |
445
|
|
|
} |
446
|
|
|
|
447
|
|
|
$wheres[] = _elgg_get_access_where_sql(array( |
448
|
|
|
'table_alias' => $table, |
449
|
|
|
'guid_column' => 'entity_guid', |
450
|
|
|
)); |
451
|
|
|
|
452
|
|
|
if ($where = implode(' AND ', $wheres)) { |
453
|
|
|
$return['wheres'][] = "($where)"; |
454
|
|
|
} |
455
|
|
|
|
456
|
|
|
return $return; |
457
|
|
|
} |
458
|
|
|
|
459
|
|
|
/** |
460
|
|
|
* Normalizes metadata / annotation option names to their corresponding metastrings name. |
461
|
|
|
* |
462
|
|
|
* @param array $options An options array |
463
|
|
|
* @return array |
464
|
|
|
* @access private |
465
|
|
|
*/ |
466
|
|
|
function _elgg_normalize_metastrings_options(array $options = array()) { |
467
|
|
|
|
468
|
|
|
// support either metastrings_type or metastring_type |
469
|
|
|
// because I've made this mistake many times and hunting it down is a pain... |
470
|
|
|
$type = elgg_extract('metastring_type', $options, null); |
471
|
|
|
$type = elgg_extract('metastrings_type', $options, $type); |
472
|
|
|
|
473
|
|
|
$options['metastring_type'] = $type; |
474
|
|
|
|
475
|
|
|
// support annotation_ and annotations_ because they're way too easy to confuse |
476
|
|
|
$prefixes = array('metadata_', 'annotation_', 'annotations_'); |
477
|
|
|
|
478
|
|
|
// map the metadata_* options to metastring_* options |
479
|
|
|
$map = array( |
480
|
|
|
'names' => 'metastring_names', |
481
|
|
|
'values' => 'metastring_values', |
482
|
|
|
'case_sensitive' => 'metastring_case_sensitive', |
483
|
|
|
'owner_guids' => 'metastring_owner_guids', |
484
|
|
|
'created_time_lower' => 'metastring_created_time_lower', |
485
|
|
|
'created_time_upper' => 'metastring_created_time_upper', |
486
|
|
|
'calculation' => 'metastring_calculation', |
487
|
|
|
'ids' => 'metastring_ids', |
488
|
|
|
); |
489
|
|
|
|
490
|
|
|
foreach ($prefixes as $prefix) { |
491
|
|
|
$singulars = array("{$prefix}name", "{$prefix}value", "{$prefix}owner_guid", "{$prefix}id"); |
492
|
|
|
$options = _elgg_normalize_plural_options_array($options, $singulars); |
493
|
|
|
|
494
|
|
|
foreach ($map as $specific => $normalized) { |
495
|
|
|
$key = $prefix . $specific; |
496
|
|
|
if (isset($options[$key])) { |
497
|
|
|
$options[$normalized] = $options[$key]; |
498
|
|
|
} |
499
|
|
|
} |
500
|
|
|
} |
501
|
|
|
|
502
|
|
|
return $options; |
503
|
|
|
} |
504
|
|
|
|
505
|
|
|
/** |
506
|
|
|
* Enables or disables a metastrings-based object by its id. |
507
|
|
|
* |
508
|
|
|
* @warning To enable disabled metastrings you must first use |
509
|
|
|
* {@link access_show_hidden_entities()}. |
510
|
|
|
* |
511
|
|
|
* @param int $id The object's ID |
512
|
|
|
* @param string $enabled Value to set to: yes or no |
513
|
|
|
* @param string $type Metastring type: metadata or annotation |
514
|
|
|
* |
515
|
|
|
* @return bool |
516
|
|
|
* @throws InvalidParameterException |
517
|
|
|
* @access private |
518
|
|
|
*/ |
519
|
|
|
function _elgg_set_metastring_based_object_enabled_by_id($id, $enabled, $type) { |
520
|
|
|
$id = (int)$id; |
521
|
|
|
$db_prefix = elgg_get_config('dbprefix'); |
522
|
|
|
|
523
|
|
|
$object = _elgg_get_metastring_based_object_from_id($id, $type); |
524
|
|
|
|
525
|
|
|
switch ($type) { |
526
|
|
|
case 'annotation': |
527
|
|
|
case 'annotations': |
528
|
|
|
$type = 'annotation'; |
529
|
|
|
$table = "{$db_prefix}annotations"; |
530
|
|
|
break; |
531
|
|
|
|
532
|
|
|
case 'metadata': |
533
|
|
|
$table = "{$db_prefix}metadata"; |
534
|
|
|
break; |
535
|
|
|
} |
536
|
|
|
|
537
|
|
|
if ($enabled === 'yes' || $enabled === 1 || $enabled === true) { |
|
|
|
|
538
|
|
|
$enabled = 'yes'; |
539
|
|
|
$event = 'enable'; |
540
|
|
|
} elseif ($enabled === 'no' || $enabled === 0 || $enabled === false) { |
|
|
|
|
541
|
|
|
$enabled = 'no'; |
542
|
|
|
$event = 'disable'; |
543
|
|
|
} else { |
544
|
|
|
return false; |
545
|
|
|
} |
546
|
|
|
|
547
|
|
|
$return = false; |
548
|
|
|
|
549
|
|
|
if ($object) { |
550
|
|
|
// don't set it if it's already set. |
551
|
|
|
if ($object->enabled == $enabled) { |
552
|
|
|
$return = false; |
553
|
|
|
} elseif ($object->canEdit() && (elgg_trigger_event($event, $type, $object))) { |
|
|
|
|
554
|
|
|
$return = update_data("UPDATE $table SET enabled = '$enabled' where id = $id"); |
|
|
|
|
555
|
|
|
} |
556
|
|
|
} |
557
|
|
|
|
558
|
|
|
return $return; |
559
|
|
|
} |
560
|
|
|
|
561
|
|
|
/** |
562
|
|
|
* Runs metastrings-based objects found using $options through $callback |
563
|
|
|
* |
564
|
|
|
* @warning Unlike _elgg_get_metastring_based_objects() this will not accept an |
565
|
|
|
* empty options array! |
566
|
|
|
* |
567
|
|
|
* @warning This returns null on no ops. |
568
|
|
|
* |
569
|
|
|
* @param array $options An options array. {@link _elgg_get_metastring_based_objects()} |
570
|
|
|
* @param string $callback The callback to pass each result through |
571
|
|
|
* @param bool $inc_offset Increment the offset? Pass false for callbacks that delete / disable |
572
|
|
|
* |
573
|
|
|
* @return bool|null true on success, false on failure, null if no objects are found. |
574
|
|
|
* @access private |
575
|
|
|
*/ |
576
|
|
|
function _elgg_batch_metastring_based_objects(array $options, $callback, $inc_offset = true) { |
577
|
|
|
if (!$options || !is_array($options)) { |
|
|
|
|
578
|
|
|
return false; |
579
|
|
|
} |
580
|
|
|
|
581
|
|
|
$batch = new \ElggBatch('_elgg_get_metastring_based_objects', $options, $callback, 50, $inc_offset); |
582
|
|
|
return $batch->callbackResult; |
583
|
|
|
} |
584
|
|
|
|
585
|
|
|
/** |
586
|
|
|
* Returns a singular metastring-based object by its ID. |
587
|
|
|
* |
588
|
|
|
* @param int $id The metastring-based object's ID |
589
|
|
|
* @param string $type The type: annotation or metadata |
590
|
|
|
* @return \ElggExtender |
591
|
|
|
* @access private |
592
|
|
|
*/ |
593
|
|
|
function _elgg_get_metastring_based_object_from_id($id, $type) { |
594
|
|
|
$id = (int)$id; |
595
|
|
|
if (!$id) { |
596
|
|
|
return false; |
597
|
|
|
} |
598
|
|
|
|
599
|
|
|
$options = array( |
600
|
|
|
'metastring_type' => $type, |
601
|
|
|
'metastring_id' => $id, |
602
|
|
|
); |
603
|
|
|
|
604
|
|
|
$obj = _elgg_get_metastring_based_objects($options); |
605
|
|
|
|
606
|
|
|
if ($obj && count($obj) == 1) { |
607
|
|
|
return $obj[0]; |
608
|
|
|
} |
609
|
|
|
|
610
|
|
|
return false; |
611
|
|
|
} |
612
|
|
|
|
613
|
|
|
/** |
614
|
|
|
* Deletes a metastring-based object by its id |
615
|
|
|
* |
616
|
|
|
* @param int $id The object's ID |
617
|
|
|
* @param string $type The object's metastring type: annotation or metadata |
618
|
|
|
* @return bool |
619
|
|
|
* @access private |
620
|
|
|
*/ |
621
|
|
|
function _elgg_delete_metastring_based_object_by_id($id, $type) { |
622
|
|
|
$id = (int)$id; |
623
|
|
|
$db_prefix = elgg_get_config('dbprefix'); |
624
|
|
|
|
625
|
|
|
switch ($type) { |
626
|
|
|
case 'annotations': |
627
|
|
|
case 'annotation': |
628
|
|
|
$table = $db_prefix . 'annotations'; |
629
|
|
|
$type = 'annotation'; |
630
|
|
|
break; |
631
|
|
|
|
632
|
|
|
case 'metadata': |
633
|
|
|
$table = $db_prefix . 'metadata'; |
634
|
|
|
$type = 'metadata'; |
635
|
|
|
break; |
636
|
|
|
|
637
|
|
|
default: |
638
|
|
|
return false; |
639
|
|
|
} |
640
|
|
|
|
641
|
|
|
$obj = _elgg_get_metastring_based_object_from_id($id, $type); |
642
|
|
|
|
643
|
|
|
if ($obj) { |
644
|
|
|
// Tidy up if memcache is enabled. |
645
|
|
|
// @todo only metadata is supported |
646
|
|
|
if ($type == 'metadata') { |
647
|
|
|
static $metabyname_memcache; |
648
|
|
|
if ((!$metabyname_memcache) && (is_memcache_available())) { |
649
|
|
|
$metabyname_memcache = new \ElggMemcache('metabyname_memcache'); |
650
|
|
|
} |
651
|
|
|
|
652
|
|
|
if ($metabyname_memcache) { |
653
|
|
|
// @todo why name_id? is that even populated? |
654
|
|
|
$metabyname_memcache->delete("{$obj->entity_guid}:{$obj->name_id}"); |
655
|
|
|
} |
656
|
|
|
} |
657
|
|
|
|
658
|
|
|
if ($obj->canEdit()) { |
659
|
|
|
// bc code for when we triggered 'delete', 'annotations' #4770 |
660
|
|
|
$result = true; |
661
|
|
|
if ($type == "annotation") { |
662
|
|
|
$result = elgg_trigger_event('delete', 'annotations', $obj); |
|
|
|
|
663
|
|
|
if ($result === false) { |
664
|
|
|
elgg_deprecated_notice("Use the event 'delete', 'annotation'", 1.9); |
665
|
|
|
} |
666
|
|
|
} |
667
|
|
|
|
668
|
|
|
if (elgg_trigger_event('delete', $type, $obj) && $result) { |
|
|
|
|
669
|
|
|
return (bool)delete_data("DELETE FROM $table WHERE id = $id"); |
670
|
|
|
} |
671
|
|
|
} |
672
|
|
|
} |
673
|
|
|
|
674
|
|
|
return false; |
675
|
|
|
} |
676
|
|
|
|
677
|
|
|
/** |
678
|
|
|
* Returns options to pass to elgg_get_entities() for metastrings operations. |
679
|
|
|
* |
680
|
|
|
* @param string $type Metastring type: annotation or metadata |
681
|
|
|
* @param array $options Options |
682
|
|
|
* |
683
|
|
|
* @return array |
684
|
|
|
* @access private |
685
|
|
|
*/ |
686
|
|
|
function _elgg_entities_get_metastrings_options($type, $options) { |
687
|
|
|
$valid_types = array('metadata', 'annotation'); |
688
|
|
|
if (!in_array($type, $valid_types)) { |
689
|
|
|
return false; |
690
|
|
|
} |
691
|
|
|
|
692
|
|
|
// the options for annotations are singular (annotation_name) but the table |
693
|
|
|
// is plural (elgg_annotations) so rewrite for the table name. |
694
|
|
|
$n_table = ($type == 'annotation') ? 'annotations' : $type; |
695
|
|
|
|
696
|
|
|
$singulars = array("{$type}_name", "{$type}_value", |
697
|
|
|
"{$type}_name_value_pair", "{$type}_owner_guid"); |
698
|
|
|
$options = _elgg_normalize_plural_options_array($options, $singulars); |
699
|
|
|
|
700
|
|
|
$clauses = _elgg_get_entity_metadata_where_sql('e', $n_table, $options["{$type}_names"], |
701
|
|
|
$options["{$type}_values"], $options["{$type}_name_value_pairs"], |
702
|
|
|
$options["{$type}_name_value_pairs_operator"], $options["{$type}_case_sensitive"], |
703
|
|
|
$options["order_by_{$type}"], $options["{$type}_owner_guids"]); |
704
|
|
|
|
705
|
|
|
if ($clauses) { |
706
|
|
|
// merge wheres to pass to elgg_get_entities() |
707
|
|
|
if (isset($options['wheres']) && !is_array($options['wheres'])) { |
708
|
|
|
$options['wheres'] = array($options['wheres']); |
709
|
|
|
} elseif (!isset($options['wheres'])) { |
710
|
|
|
$options['wheres'] = array(); |
711
|
|
|
} |
712
|
|
|
|
713
|
|
|
$options['wheres'] = array_merge($options['wheres'], $clauses['wheres']); |
714
|
|
|
|
715
|
|
|
// merge joins to pass to elgg_get_entities() |
716
|
|
|
if (isset($options['joins']) && !is_array($options['joins'])) { |
717
|
|
|
$options['joins'] = array($options['joins']); |
718
|
|
|
} elseif (!isset($options['joins'])) { |
719
|
|
|
$options['joins'] = array(); |
720
|
|
|
} |
721
|
|
|
|
722
|
|
|
$options['joins'] = array_merge($options['joins'], $clauses['joins']); |
723
|
|
|
|
724
|
|
|
if ($clauses['orders']) { |
725
|
|
|
$order_by_metadata = implode(", ", $clauses['orders']); |
726
|
|
View Code Duplication |
if (isset($options['order_by']) && $options['order_by']) { |
727
|
|
|
$options['order_by'] = "$order_by_metadata, {$options['order_by']}"; |
728
|
|
|
} else { |
729
|
|
|
$options['order_by'] = "$order_by_metadata, e.time_created DESC"; |
730
|
|
|
} |
731
|
|
|
} |
732
|
|
|
} |
733
|
|
|
|
734
|
|
|
return $options; |
735
|
|
|
} |
736
|
|
|
|
737
|
|
|
/** |
738
|
|
|
* Metastring unit tests |
739
|
|
|
* |
740
|
|
|
* @param string $hook unit_test |
741
|
|
|
* @param string $type system |
742
|
|
|
* @param array $value Array of other tests |
743
|
|
|
* |
744
|
|
|
* @return array |
745
|
|
|
* @access private |
746
|
|
|
*/ |
747
|
|
|
function _elgg_metastrings_test($hook, $type, $value) { |
748
|
|
|
global $CONFIG; |
749
|
|
|
$value[] = $CONFIG->path . 'engine/tests/ElggCoreMetastringsTest.php'; |
750
|
|
|
return $value; |
751
|
|
|
} |
752
|
|
|
|
753
|
|
|
return function(\Elgg\EventsService $events, \Elgg\HooksRegistrationService $hooks) { |
754
|
|
|
$hooks->registerHandler('unit_test', 'system', '_elgg_metastrings_test'); |
755
|
|
|
}; |
756
|
|
|
|
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.