00001 <?php
00011 global $METASTRINGS_CACHE;
00012 $METASTRINGS_CACHE = array();
00013
00015 global $METASTRINGS_DEADNAME_CACHE;
00016 $METASTRINGS_DEADNAME_CACHE = array();
00017
00018
00019
00029 function get_metastring_id($string, $case_sensitive = TRUE) {
00030 global $CONFIG, $METASTRINGS_CACHE, $METASTRINGS_DEADNAME_CACHE;
00031
00032 $string = sanitise_string($string);
00033
00034
00035 if ($case_sensitive) {
00036 $result = array_search($string, $METASTRINGS_CACHE, true);
00037
00038 if ($result !== false) {
00039 elgg_log("** Returning id for string:$string from cache.");
00040 return $result;
00041 }
00042
00043
00044 if (in_array($string, $METASTRINGS_DEADNAME_CACHE, true)) {
00045 return false;
00046 }
00047
00048
00049 $msfc = null;
00050 static $metastrings_memcache;
00051 if ((!$metastrings_memcache) && (is_memcache_available())) {
00052 $metastrings_memcache = new ElggMemcache('metastrings_memcache');
00053 }
00054 if ($metastrings_memcache) {
00055 $msfc = $metastrings_memcache->load($string);
00056 }
00057 if ($msfc) {
00058 return $msfc;
00059 }
00060 }
00061
00062
00063 if ($case_sensitive) {
00064 $query = "SELECT * from {$CONFIG->dbprefix}metastrings where string= BINARY '$string' limit 1";
00065 } else {
00066 $query = "SELECT * from {$CONFIG->dbprefix}metastrings where string = '$string'";
00067 }
00068
00069 $row = FALSE;
00070 $metaStrings = get_data($query);
00071 if (is_array($metaStrings)) {
00072 if (sizeof($metaStrings) > 1) {
00073 $ids = array();
00074 foreach ($metaStrings as $metaString) {
00075 $ids[] = $metaString->id;
00076 }
00077 return $ids;
00078 } else if (isset($metaStrings[0])) {
00079 $row = $metaStrings[0];
00080 }
00081 }
00082
00083 if ($row) {
00084 $METASTRINGS_CACHE[$row->id] = $row->string;
00085
00086
00087 if ($metastrings_memcache) {
00088 $metastrings_memcache->save($row->string, $row->id);
00089 }
00090
00091 elgg_log("** Cacheing string '{$row->string}'");
00092
00093 return $row->id;
00094 } else {
00095 $METASTRINGS_DEADNAME_CACHE[$string] = $string;
00096 }
00097
00098 return false;
00099 }
00100
00108 function get_metastring($id) {
00109 global $CONFIG, $METASTRINGS_CACHE;
00110
00111 $id = (int) $id;
00112
00113 if (isset($METASTRINGS_CACHE[$id])) {
00114 elgg_log("** Returning string for id:$id from cache.");
00115
00116 return $METASTRINGS_CACHE[$id];
00117 }
00118
00119 $row = get_data_row("SELECT * from {$CONFIG->dbprefix}metastrings where id='$id' limit 1");
00120 if ($row) {
00121 $METASTRINGS_CACHE[$id] = $row->string;
00122 elgg_log("** Cacheing string '{$row->string}'");
00123
00124 return $row->string;
00125 }
00126
00127 return false;
00128 }
00129
00139 function add_metastring($string, $case_sensitive = true) {
00140 global $CONFIG, $METASTRINGS_CACHE, $METASTRINGS_DEADNAME_CACHE;
00141
00142 $sanstring = sanitise_string($string);
00143
00144 $id = get_metastring_id($string, $case_sensitive);
00145 if ($id) {
00146 return $id;
00147 }
00148
00149 $result = insert_data("INSERT into {$CONFIG->dbprefix}metastrings (string) values ('$sanstring')");
00150 if ($result) {
00151 $METASTRINGS_CACHE[$result] = $string;
00152 if (isset($METASTRINGS_DEADNAME_CACHE[$string])) {
00153 unset($METASTRINGS_DEADNAME_CACHE[$string]);
00154 }
00155 }
00156
00157 return $result;
00158 }
00159
00166 function delete_orphaned_metastrings() {
00167 global $CONFIG;
00168
00169
00170 if (is_memcache_available()) {
00171 $select_query = "
00172 SELECT *
00173 from {$CONFIG->dbprefix}metastrings where
00174 (
00175 (id not in (select name_id from {$CONFIG->dbprefix}metadata)) AND
00176 (id not in (select value_id from {$CONFIG->dbprefix}metadata)) AND
00177 (id not in (select name_id from {$CONFIG->dbprefix}annotations)) AND
00178 (id not in (select value_id from {$CONFIG->dbprefix}annotations))
00179 )";
00180
00181 $dead = get_data($select_query);
00182 if ($dead) {
00183 static $metastrings_memcache;
00184 if (!$metastrings_memcache) {
00185 $metastrings_memcache = new ElggMemcache('metastrings_memcache');
00186 }
00187
00188 foreach ($dead as $d) {
00189 $metastrings_memcache->delete($d->string);
00190 }
00191 }
00192 }
00193
00194 $query = "
00195 DELETE
00196 from {$CONFIG->dbprefix}metastrings where
00197 (
00198 (id not in (select name_id from {$CONFIG->dbprefix}metadata)) AND
00199 (id not in (select value_id from {$CONFIG->dbprefix}metadata)) AND
00200 (id not in (select name_id from {$CONFIG->dbprefix}annotations)) AND
00201 (id not in (select value_id from {$CONFIG->dbprefix}annotations))
00202 )";
00203
00204 return delete_data($query);
00205 }
00206
00242 function elgg_get_metastring_based_objects($options) {
00243 $options = elgg_normalize_metastrings_options($options);
00244
00245 switch ($options['metastring_type']) {
00246 case 'metadata':
00247 $type = 'metadata';
00248 $callback = 'row_to_elggmetadata';
00249 break;
00250
00251 case 'annotations':
00252 case 'annotation':
00253 $type = 'annotations';
00254 $callback = 'row_to_elggannotation';
00255 break;
00256
00257 default:
00258 return false;
00259 }
00260
00261 $defaults = array(
00262
00263 'types' => ELGG_ENTITIES_ANY_VALUE,
00264 'subtypes' => ELGG_ENTITIES_ANY_VALUE,
00265 'type_subtype_pairs' => ELGG_ENTITIES_ANY_VALUE,
00266
00267 'guids' => ELGG_ENTITIES_ANY_VALUE,
00268 'owner_guids' => ELGG_ENTITIES_ANY_VALUE,
00269 'container_guids' => ELGG_ENTITIES_ANY_VALUE,
00270 'site_guids' => get_config('site_guid'),
00271
00272 'modified_time_lower' => ELGG_ENTITIES_ANY_VALUE,
00273 'modified_time_upper' => ELGG_ENTITIES_ANY_VALUE,
00274 'created_time_lower' => ELGG_ENTITIES_ANY_VALUE,
00275 'created_time_upper' => ELGG_ENTITIES_ANY_VALUE,
00276
00277
00278 'metastring_names' => ELGG_ENTITIES_ANY_VALUE,
00279 'metastring_values' => ELGG_ENTITIES_ANY_VALUE,
00280
00281
00282
00283 'metastring_case_sensitive' => TRUE,
00284
00285 'metastring_calculation' => ELGG_ENTITIES_NO_VALUE,
00286
00287 'metastring_created_time_lower' => ELGG_ENTITIES_ANY_VALUE,
00288 'metastring_created_time_upper' => ELGG_ENTITIES_ANY_VALUE,
00289
00290 'metastring_owner_guids' => ELGG_ENTITIES_ANY_VALUE,
00291
00292 'metastring_ids' => ELGG_ENTITIES_ANY_VALUE,
00293
00294
00295 'order_by' => 'n_table.time_created asc',
00296 'limit' => 10,
00297 'offset' => 0,
00298 'count' => FALSE,
00299 'selects' => array(),
00300 'wheres' => array(),
00301 'joins' => array(),
00302
00303 'callback' => $callback
00304 );
00305
00306
00307 $options['site_guid'] = ELGG_ENTITIES_ANY_VALUE;
00308
00309 $options = array_merge($defaults, $options);
00310
00311
00312
00313 if (isset($options['type_subtype_pair'])) {
00314 if (isset($options['type_subtype_pairs'])) {
00315 $options['type_subtype_pairs'] = array_merge($options['type_subtype_pairs'],
00316 $options['type_subtype_pair']);
00317 } else {
00318 $options['type_subtype_pairs'] = $options['type_subtype_pair'];
00319 }
00320 }
00321
00322 $singulars = array(
00323 'type', 'subtype', 'type_subtype_pair',
00324 'guid', 'owner_guid', 'container_guid', 'site_guid',
00325 'metastring_name', 'metastring_value',
00326 'metastring_owner_guid', 'metastring_id',
00327 'select', 'where', 'join'
00328 );
00329
00330 $options = elgg_normalise_plural_options_array($options, $singulars);
00331
00332 if (!$options) {
00333 return false;
00334 }
00335
00336 $db_prefix = elgg_get_config('dbprefix');
00337
00338
00339 if (!is_array($options['wheres'])) {
00340 $options['wheres'] = array($options['wheres']);
00341 }
00342
00343 $wheres = $options['wheres'];
00344
00345
00346 $wheres[] = elgg_get_entity_type_subtype_where_sql('e', $options['types'],
00347 $options['subtypes'], $options['type_subtype_pairs']);
00348
00349 $wheres[] = elgg_get_guid_based_where_sql('e.guid', $options['guids']);
00350 $wheres[] = elgg_get_guid_based_where_sql('e.owner_guid', $options['owner_guids']);
00351 $wheres[] = elgg_get_guid_based_where_sql('e.container_guid', $options['container_guids']);
00352 $wheres[] = elgg_get_guid_based_where_sql('e.site_guid', $options['site_guids']);
00353
00354 $wheres[] = elgg_get_entity_time_where_sql('e', $options['created_time_upper'],
00355 $options['created_time_lower'], $options['modified_time_upper'], $options['modified_time_lower']);
00356
00357
00358 $wheres[] = elgg_get_entity_time_where_sql('n_table', $options['metastring_created_time_upper'],
00359 $options['metastring_created_time_lower'], null, null);
00360
00361 $wheres[] = elgg_get_guid_based_where_sql('n_table.owner_guid',
00362 $options['metastring_owner_guids']);
00363
00364
00365
00366 foreach ($wheres as $i => $where) {
00367 if ($where === FALSE) {
00368 return FALSE;
00369 } elseif (empty($where)) {
00370 unset($wheres[$i]);
00371 }
00372 }
00373
00374
00375 $wheres = array_unique($wheres);
00376
00377
00378 if (!is_array($options['joins'])) {
00379 $options['joins'] = array($options['joins']);
00380 }
00381
00382 $joins = $options['joins'];
00383 $joins[] = "JOIN {$db_prefix}entities e ON n_table.entity_guid = e.guid";
00384
00385
00386 if (!is_array($options['selects'])) {
00387 $options['selects'] = array($options['selects']);
00388 }
00389
00390 $selects = $options['selects'];
00391
00392
00393
00394
00395
00396 $custom_callback = ($options['callback'] == 'row_to_elggmetadata'
00397 || $options['callback'] == 'row_to_elggannotation');
00398 $is_calculation = $options['metastring_calculation'] ? true : false;
00399
00400 if ($custom_callback || $is_calculation) {
00401 $joins[] = "JOIN {$db_prefix}metastrings n on n_table.name_id = n.id";
00402 $joins[] = "JOIN {$db_prefix}metastrings v on n_table.value_id = v.id";
00403
00404 $selects[] = 'n.string as name';
00405 $selects[] = 'v.string as value';
00406 }
00407
00408 foreach ($joins as $i => $join) {
00409 if ($join === FALSE) {
00410 return FALSE;
00411 } elseif (empty($join)) {
00412 unset($joins[$i]);
00413 }
00414 }
00415
00416
00417 $metastring_clauses = elgg_get_metastring_sql('n_table', $options['metastring_names'],
00418 $options['metastring_values'], null, $options['metastring_ids'],
00419 $options['metastring_case_sensitive']);
00420
00421 if ($metastring_clauses) {
00422 $wheres = array_merge($wheres, $metastring_clauses['wheres']);
00423 $joins = array_merge($joins, $metastring_clauses['joins']);
00424 } else {
00425 $wheres[] = get_access_sql_suffix('n_table');
00426 }
00427
00428 if ($options['metastring_calculation'] === ELGG_ENTITIES_NO_VALUE) {
00429 $selects = array_unique($selects);
00430
00431 $select_str = '';
00432 if ($selects) {
00433 foreach ($selects as $select) {
00434 $select_str .= ", $select";
00435 }
00436 }
00437
00438 $query = "SELECT DISTINCT n_table.*{$select_str} FROM {$db_prefix}$type n_table";
00439 } else {
00440 $query = "SELECT {$options['metastring_calculation']}(v.string) as calculation FROM {$db_prefix}$type n_table";
00441 }
00442
00443
00444 $joins = array_unique($joins);
00445
00446
00447 foreach ($joins as $j) {
00448 $query .= " $j ";
00449 }
00450
00451
00452 $query .= ' WHERE ';
00453
00454 foreach ($wheres as $w) {
00455 $query .= " $w AND ";
00456 }
00457
00458
00459 $query .= get_access_sql_suffix('e');
00460
00461
00462 if (isset($options['reverse_order_by']) && $options['reverse_order_by']) {
00463 $options['order_by'] = elgg_sql_reverse_order_by_clause($options['order_by'],
00464 $defaults['order_by']);
00465 }
00466
00467 if ($options['metastring_calculation'] === ELGG_ENTITIES_NO_VALUE) {
00468 if (isset($options['group_by'])) {
00469 $options['group_by'] = sanitise_string($options['group_by']);
00470 $query .= " GROUP BY {$options['group_by']}";
00471 }
00472
00473 if (isset($options['order_by']) && $options['order_by']) {
00474 $options['order_by'] = sanitise_string($options['order_by']);
00475 $query .= " ORDER BY {$options['order_by']}, n_table.id";
00476 }
00477
00478 if ($options['limit']) {
00479 $limit = sanitise_int($options['limit']);
00480 $offset = sanitise_int($options['offset'], false);
00481 $query .= " LIMIT $offset, $limit";
00482 }
00483
00484 $dt = get_data($query, $options['callback']);
00485 return $dt;
00486 } else {
00487 $result = get_data_row($query);
00488 return $result->calculation;
00489 }
00490 }
00491
00507 function elgg_get_metastring_sql($table, $names = null, $values = null,
00508 $pairs = null, $ids = null, $case_sensitive = false) {
00509
00510 if ((!$names && $names !== 0)
00511 && (!$values && $values !== 0)
00512 && !$ids
00513 && (!$pairs && $pairs !== 0)) {
00514
00515 return array();
00516 }
00517
00518 $db_prefix = elgg_get_config('dbprefix');
00519
00520
00521
00522
00523 $binary = ($case_sensitive) ? ' BINARY ' : '';
00524
00525 $return = array (
00526 'joins' => array (),
00527 'wheres' => array()
00528 );
00529
00530 $wheres = array();
00531
00532
00533 $names_where = '';
00534 if ($names !== NULL) {
00535 if (!is_array($names)) {
00536 $names = array($names);
00537 }
00538
00539 $sanitised_names = array();
00540 foreach ($names as $name) {
00541
00542 if (!$name) {
00543 $name = '0';
00544 }
00545 $sanitised_names[] = '\'' . sanitise_string($name) . '\'';
00546 }
00547
00548 if ($names_str = implode(',', $sanitised_names)) {
00549 $return['joins'][] = "JOIN {$db_prefix}metastrings msn on $table.name_id = msn.id";
00550 $names_where = "(msn.string IN ($names_str))";
00551 }
00552 }
00553
00554
00555 $values_where = '';
00556 if ($values !== NULL) {
00557 if (!is_array($values)) {
00558 $values = array($values);
00559 }
00560
00561 $sanitised_values = array();
00562 foreach ($values as $value) {
00563
00564 if (!$value) {
00565 $value = 0;
00566 }
00567 $sanitised_values[] = '\'' . sanitise_string($value) . '\'';
00568 }
00569
00570 if ($values_str = implode(',', $sanitised_values)) {
00571 $return['joins'][] = "JOIN {$db_prefix}metastrings msv on $table.value_id = msv.id";
00572 $values_where = "({$binary}msv.string IN ($values_str))";
00573 }
00574 }
00575
00576 if ($ids !== NULL) {
00577 if (!is_array($ids)) {
00578 $ids = array($ids);
00579 }
00580
00581 $ids_str = implode(',', $ids);
00582
00583 if ($ids_str) {
00584 $wheres[] = "n_table.id IN ($ids_str)";
00585 }
00586 }
00587
00588 if ($names_where && $values_where) {
00589 $wheres[] = "($names_where AND $values_where)";
00590 } elseif ($names_where) {
00591 $wheres[] = $names_where;
00592 } elseif ($values_where) {
00593 $wheres[] = $values_where;
00594 }
00595
00596 $wheres[] = get_access_sql_suffix($table);
00597
00598 if ($where = implode(' AND ', $wheres)) {
00599 $return['wheres'][] = "($where)";
00600 }
00601
00602 return $return;
00603 }
00604
00613 function elgg_normalize_metastrings_options(array $options = array()) {
00614
00615
00616
00617 $type = elgg_extract('metastring_type', $options, null);
00618 $type = elgg_extract('metastrings_type', $options, $type);
00619
00620 $options['metastring_type'] = $type;
00621
00622
00623 $prefixes = array('metadata_', 'annotation_', 'annotations_');
00624
00625
00626 $map = array(
00627 'names' => 'metastring_names',
00628 'values' => 'metastring_values',
00629 'case_sensitive' => 'metastring_case_sensitive',
00630 'owner_guids' => 'metastring_owner_guids',
00631 'created_time_lower' => 'metastring_created_time_lower',
00632 'created_time_upper' => 'metastring_created_time_upper',
00633 'calculation' => 'metastring_calculation',
00634 'ids' => 'metastring_ids'
00635 );
00636
00637 foreach ($prefixes as $prefix) {
00638 $singulars = array("{$prefix}name", "{$prefix}value", "{$prefix}owner_guid", "{$prefix}id");
00639 $options = elgg_normalise_plural_options_array($options, $singulars);
00640
00641 foreach ($map as $specific => $normalized) {
00642 $key = $prefix . $specific;
00643 if (isset($options[$key])) {
00644 $options[$normalized] = $options[$key];
00645 }
00646 }
00647 }
00648
00649 return $options;
00650 }
00651
00667 function elgg_set_metastring_based_object_enabled_by_id($id, $enabled, $type) {
00668 $id = (int)$id;
00669 $db_prefix = elgg_get_config('dbprefix');
00670
00671 $object = elgg_get_metastring_based_object_from_id($id, $type);
00672
00673 switch($type) {
00674 case 'annotation':
00675 case 'annotations':
00676 $table = "{$db_prefix}annotations";
00677 break;
00678
00679 case 'metadata':
00680 $table = "{$db_prefix}metadata";
00681 break;
00682 }
00683
00684 if ($enabled === 'yes' || $enabled === 1 || $enabled === true) {
00685 $enabled = 'yes';
00686 $event = 'enable';
00687 } elseif ($enabled === 'no' || $enabled === 0 || $enabled === false) {
00688 $enabled = 'no';
00689 $event = 'disable';
00690 } else {
00691 return false;
00692 }
00693
00694 $return = false;
00695
00696 if ($object) {
00697
00698 if ($object->enabled == $enabled) {
00699 $return = false;
00700 } elseif ($object->canEdit() && (elgg_trigger_event($event, $type, $object))) {
00701 $return = update_data("UPDATE $table SET enabled = '$enabled' where id = $id");
00702 }
00703 }
00704
00705 return $return;
00706 }
00707
00724 function elgg_batch_metastring_based_objects(array $options, $callback, $inc_offset = true) {
00725 if (!$options || !is_array($options)) {
00726 return false;
00727 }
00728
00729 $batch = new ElggBatch('elgg_get_metastring_based_objects', $options, $callback, 50, $inc_offset);
00730 return $batch->callbackResult;
00731 }
00732
00743 function elgg_get_metastring_based_object_from_id($id, $type) {
00744 $id = (int)$id;
00745 if (!$id) {
00746 return false;
00747 }
00748
00749 $options = array(
00750 'metastring_type' => $type,
00751 'metastring_id' => $id
00752 );
00753
00754 $obj = elgg_get_metastring_based_objects($options);
00755
00756 if ($obj && count($obj) == 1) {
00757 return $obj[0];
00758 }
00759
00760 return false;
00761 }
00762
00773 function elgg_delete_metastring_based_object_by_id($id, $type) {
00774 $id = (int)$id;
00775 $db_prefix = elgg_get_config('dbprefix');
00776
00777 switch ($type) {
00778 case 'annotation':
00779 case 'annotations':
00780 $type = 'annotations';
00781 break;
00782
00783 case 'metadata':
00784 $type = 'metadata';
00785 break;
00786
00787 default:
00788 return false;
00789 }
00790
00791 $obj = elgg_get_metastring_based_object_from_id($id, $type);
00792 $table = $db_prefix . $type;
00793
00794 if ($obj) {
00795
00796
00797 if ($type == 'metadata') {
00798 static $metabyname_memcache;
00799 if ((!$metabyname_memcache) && (is_memcache_available())) {
00800 $metabyname_memcache = new ElggMemcache('metabyname_memcache');
00801 }
00802
00803 if ($metabyname_memcache) {
00804
00805 $metabyname_memcache->delete("{$obj->entity_guid}:{$obj->name_id}");
00806 }
00807 }
00808
00809 if (($obj->canEdit()) && (elgg_trigger_event('delete', $type, $obj))) {
00810 return (bool)delete_data("DELETE from $table where id=$id");
00811 }
00812 }
00813
00814 return false;
00815 }
00816
00831 function elgg_entities_get_metastrings_options($type, $options) {
00832 $valid_types = array('metadata', 'annotation');
00833 if (!in_array($type, $valid_types)) {
00834 return FALSE;
00835 }
00836
00837
00838
00839 $n_table = ($type == 'annotation') ? 'annotations' : $type;
00840
00841 $singulars = array("{$type}_name", "{$type}_value",
00842 "{$type}_name_value_pair", "{$type}_owner_guid");
00843 $options = elgg_normalise_plural_options_array($options, $singulars);
00844
00845 $clauses = elgg_get_entity_metadata_where_sql('e', $n_table, $options["{$type}_names"],
00846 $options["{$type}_values"], $options["{$type}_name_value_pairs"],
00847 $options["{$type}_name_value_pairs_operator"], $options["{$type}_case_sensitive"],
00848 $options["order_by_{$type}"], $options["{$type}_owner_guids"]);
00849
00850 if ($clauses) {
00851
00852 if (isset($options['wheres']) && !is_array($options['wheres'])) {
00853 $options['wheres'] = array($options['wheres']);
00854 } elseif (!isset($options['wheres'])) {
00855 $options['wheres'] = array();
00856 }
00857
00858 $options['wheres'] = array_merge($options['wheres'], $clauses['wheres']);
00859
00860
00861 if (isset($options['joins']) && !is_array($options['joins'])) {
00862 $options['joins'] = array($options['joins']);
00863 } elseif (!isset($options['joins'])) {
00864 $options['joins'] = array();
00865 }
00866
00867 $options['joins'] = array_merge($options['joins'], $clauses['joins']);
00868
00869 if ($clauses['orders']) {
00870 $order_by_metadata = implode(", ", $clauses['orders']);
00871 if (isset($options['order_by']) && $options['order_by']) {
00872 $options['order_by'] = "$order_by_metadata, {$options['order_by']}";
00873 } else {
00874 $options['order_by'] = "$order_by_metadata, e.time_created DESC";
00875 }
00876 }
00877 }
00878
00879 return $options;
00880 }
00881
00882
00883 elgg_register_plugin_hook_handler('unit_test', 'system', 'metastrings_test');
00884
00896 function metastrings_test($hook, $type, $value, $params) {
00897 global $CONFIG;
00898 $value[] = $CONFIG->path . 'engine/tests/api/metastrings.php';
00899 return $value;
00900 }