aboutsummaryrefslogtreecommitdiff
path: root/engine/lib/metastrings.php
diff options
context:
space:
mode:
Diffstat (limited to 'engine/lib/metastrings.php')
-rw-r--r--engine/lib/metastrings.php320
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;
+}