diff options
Diffstat (limited to 'engine/lib/metastrings.php')
-rw-r--r-- | engine/lib/metastrings.php | 320 |
1 files changed, 320 insertions, 0 deletions
diff --git a/engine/lib/metastrings.php b/engine/lib/metastrings.php index 28f8475da..6009f0882 100644 --- a/engine/lib/metastrings.php +++ b/engine/lib/metastrings.php @@ -200,3 +200,323 @@ function delete_orphaned_metastrings() { return delete_data($query); } + + +/** + * Returns an array of either ElggAnnotation or ElggMetadata objects. + * Accepts all elgg_get_entities() options for entity restraints. + * + * @see elgg_get_entities + * + * @param array $options Array in format: + * + * metastring_names => NULL|ARR metastring names + * + * metastring_values => NULL|ARR metastring values + * + * metastring_case_sensitive => BOOL Overall Case sensitive + * + * metastring_owner_guids => NULL|ARR guids for metadata owners + * + * metastring_created_time_lower => INT Lower limit for created time. + * + * metastring_created_time_upper => INT Upper limit for created time. + * + * metastring_calculation => STR Perform the MySQL function on the metastring values returned. + * + * @param string $type Either metadata or annotations + * @return mixed + * @access private + */ +function elgg_get_metastring_based_objects($options, $type = 'metadata') { + + if ($type != 'metadata' && $type != 'annotations') { + return false; + } + + $defaults = array( + // entities + 'types' => ELGG_ENTITIES_ANY_VALUE, + 'subtypes' => ELGG_ENTITIES_ANY_VALUE, + 'type_subtype_pairs' => ELGG_ENTITIES_ANY_VALUE, + + 'guids' => ELGG_ENTITIES_ANY_VALUE, + 'owner_guids' => ELGG_ENTITIES_ANY_VALUE, + 'container_guids' => ELGG_ENTITIES_ANY_VALUE, + 'site_guids' => get_config('site_guid'), + + 'modified_time_lower' => ELGG_ENTITIES_ANY_VALUE, + 'modified_time_upper' => ELGG_ENTITIES_ANY_VALUE, + 'created_time_lower' => ELGG_ENTITIES_ANY_VALUE, + 'created_time_upper' => ELGG_ENTITIES_ANY_VALUE, + + // options are normalized to the plural in case we ever add support for them. + 'metastring_names' => ELGG_ENTITIES_ANY_VALUE, + 'metastring_values' => ELGG_ENTITIES_ANY_VALUE, + //'metastring_name_value_pairs' => ELGG_ENTITIES_ANY_VALUE, + //'metastring_name_value_pairs_operator' => 'AND', + + 'metastring_case_sensitive' => TRUE, + //'order_by_metastring' => array(), + 'metastring_calculation' => ELGG_ENTITIES_NO_VALUE, + + 'metastring_created_time_lower' => ELGG_ENTITIES_ANY_VALUE, + 'metastring_created_time_upper' => ELGG_ENTITIES_ANY_VALUE, + + 'metastring_owner_guids' => ELGG_ENTITIES_ANY_VALUE, + + // sql + 'order_by' => 'n_table.time_created asc', + 'limit' => 10, + 'offset' => 0, + 'count' => FALSE, + 'selects' => array(), + 'wheres' => array(), + 'joins' => array(), + + 'callback' => ($type == 'annotations') ? 'row_to_elggannotation' : 'row_to_elggmetadata' + ); + + $options = array_merge($defaults, $options); + + // can't use helper function with type_subtype_pair because + // it's already an array...just need to merge it + if (isset($options['type_subtype_pair'])) { + if (isset($options['type_subtype_pairs'])) { + $options['type_subtype_pairs'] = array_merge($options['type_subtype_pairs'], + $options['type_subtype_pair']); + } else { + $options['type_subtype_pairs'] = $options['type_subtype_pair']; + } + } + + $singulars = array('type', 'subtype', 'guid', 'owner_guid', 'container_guid', 'site_guid', + 'metastring_name', 'metastring_value' + ); + $options = elgg_normalise_plural_options_array($options, $singulars); + + if (!$options) { + return false; + } + + $db_prefix = elgg_get_config('dbprefix'); + + // evaluate where clauses + if (!is_array($options['wheres'])) { + $options['wheres'] = array($options['wheres']); + } + + $wheres = $options['wheres']; + + // entities + $wheres[] = elgg_get_entity_type_subtype_where_sql('e', $options['types'], + $options['subtypes'], $options['type_subtype_pairs']); + + $wheres[] = elgg_get_guid_based_where_sql('e.guid', $options['guids']); + $wheres[] = elgg_get_guid_based_where_sql('e.owner_guid', $options['owner_guids']); + $wheres[] = elgg_get_guid_based_where_sql('e.container_guid', $options['container_guids']); + $wheres[] = elgg_get_guid_based_where_sql('e.site_guid', $options['site_guids']); + + $wheres[] = elgg_get_entity_time_where_sql('e', $options['created_time_upper'], + $options['created_time_lower'], $options['modified_time_upper'], $options['modified_time_lower']); + + + $wheres[] = elgg_get_entity_time_where_sql('n_table', $options['metastring_created_time_upper'], + $options['metastring_created_time_lower'], null, null); + + $wheres[] = elgg_get_guid_based_where_sql('n_table.owner_guid', $options['metastring_owner_guids']); + + // remove identical where clauses + $wheres = array_unique($wheres); + + // see if any functions failed + // remove empty strings on successful functions + foreach ($wheres as $i => $where) { + if ($where === FALSE) { + return FALSE; + } elseif (empty($where)) { + unset($wheres[$i]); + } + } + + // evaluate join clauses + if (!is_array($options['joins'])) { + $options['joins'] = array($options['joins']); + } + + $joins = $options['joins']; + + $joins[] = "JOIN {$db_prefix}entities e ON n_table.entity_guid = e.guid"; + $joins[] = "JOIN {$db_prefix}metastrings n on n_table.name_id = n.id"; + $joins[] = "JOIN {$db_prefix}metastrings v on n_table.value_id = v.id"; + + + // remove identical join clauses + $joins = array_unique($joins); + + foreach ($joins as $i => $join) { + if ($join === FALSE) { + return FALSE; + } elseif (empty($join)) { + unset($joins[$i]); + } + } + + // metastrings + $metastring_clauses = elgg_get_metastring_sql('n_table', $options['metastring_names'], + $options['metastring_values'], $options['metastring_case_sensitive']); + + if ($metastring_clauses) { + $wheres = array_merge($wheres, $metastring_clauses['wheres']); + $joins = array_merge($joins, $metastring_clauses['joins']); + } + + // check for calculations + if ($options['count']) { + $options['metastring_calculation'] = 'count'; + } + + if ($options['metastring_calculation'] === ELGG_ENTITIES_NO_VALUE) { + $query = "SELECT DISTINCT n_table.*, n.string as name, v.string as value FROM {$db_prefix}$type n_table"; + } else { + $query = "SELECT DISTINCT v.string as value, {$options['metastring_calculation']}(v.string) as calculation FROM {$db_prefix}$type n_table"; + } + + // add joins + foreach ($joins as $j) { + $query .= " $j "; + } + + // add wheres + $query .= ' WHERE '; + + foreach ($wheres as $w) { + $query .= " $w AND "; + } + + // Add access controls + $query .= get_access_sql_suffix('e'); + if ($options['metastring_calculation'] === ELGG_ENTITIES_NO_VALUE) { + if ($options['group_by'] = sanitise_string($options['group_by'])) { + $query .= " GROUP BY {$options['group_by']}"; + } + + if ($options['order_by'] = sanitise_string($options['order_by'])) { + $query .= " ORDER BY {$options['order_by']}, n_table.id"; + } + + if ($options['limit']) { + $limit = sanitise_int($options['limit']); + $offset = sanitise_int($options['offset']); + $query .= " LIMIT $offset, $limit"; + } + + $dt = get_data($query, $options['callback']); + return $dt; + } else { + $result = get_data_row($query); + return $result->calculation; + } +} + + +/** + * Returns an array of joins and wheres for use in metastrings. + * + * @note The $pairs is reserved for name/value pairs if we want to implement those. + * + * @param string $table The annotation or metadata table name or alias + * @param array $names An array of names + * @param array $values An array of values + * @param array $pairs Name / value pairs. Not currently used. + * @param bool $case_sensitive Should name and values be case sensitive? + * + * @return array + */ +function elgg_get_metastring_sql($table, $names = null, $values = null, + $pairs = null, $case_sensitive = false) { + + if ((!$names && $names !== 0) + && (!$values && $values !== 0) + && (!$pairs && $pairs !== 0)) { + + return ''; + } + + $db_prefix = elgg_get_config('dbprefix'); + + // join counter for incremental joins. + $i = 1; + + // binary forces byte-to-byte comparision of strings, making + // it case- and diacritical-mark- sensitive. + // only supported on values. + $binary = ($case_sensitive) ? ' BINARY ' : ''; + + $access = get_access_sql_suffix($table); + + $return = array ( + 'joins' => array (), + 'wheres' => array() + ); + + $wheres = array(); + + // get names wheres and joins + $names_where = ''; + if ($names !== NULL) { + if (!is_array($names)) { + $names = array($names); + } + + $sanitised_names = array(); + foreach ($names as $name) { + // normalise to 0. + if (!$name) { + $name = '0'; + } + $sanitised_names[] = '\'' . sanitise_string($name) . '\''; + } + + if ($names_str = implode(',', $sanitised_names)) { + $return['joins'][] = "JOIN {$db_prefix}metastrings msn on $table.name_id = msn.id"; + $names_where = "(msn.string IN ($names_str))"; + } + } + + // get values wheres and joins + $values_where = ''; + if ($values !== NULL) { + if (!is_array($values)) { + $values = array($values); + } + + $sanitised_values = array(); + foreach ($values as $value) { + // normalize to 0 + if (!$value) { + $value = 0; + } + $sanitised_values[] = '\'' . sanitise_string($value) . '\''; + } + + if ($values_str = implode(',', $sanitised_values)) { + $return['joins'][] = "JOIN {$db_prefix}metastrings msv on $table.value_id = msv.id"; + $values_where = "({$binary}msv.string IN ($values_str))"; + } + } + + if ($names_where && $values_where) { + $wheres[] = "($names_where AND $values_where AND $access)"; + } elseif ($names_where) { + $wheres[] = "($names_where AND $access)"; + } elseif ($values_where) { + $wheres[] = "($values_where AND $access)"; + } + + if ($where = implode(' AND ', $wheres)) { + $return['wheres'][] = "($where)"; + } + + return $return; +} |