/** * Listen to the creation of metadata * * @param string $event the name of the event * @param string $type the type of the event * @param ElggMetadata $metadata supplied metadata * * @return void */ function tag_tools_create_metadata_event_handler($event, $type, $metadata) { if (empty($metadata) || !$metadata instanceof ElggMetadata) { return; } // is it a tag if ($metadata->name != 'tags') { return; } // get the entity for further use $ia = elgg_set_ignore_access(true); $entity_guid = $metadata->entity_guid; // can't use elgg get entity because cache is not correctly updated $entity_row = get_entity_as_row($entity_guid); elgg_set_ignore_access($ia); // shortcut for private entities if ($entity_row->access_id == ACCESS_PRIVATE) { return; } // only send notifications on creation of the entity $time_created_treshold = 5; if ($entity_row->time_created < time() - $time_created_treshold) { // assume it is an update return; } // check of the entity is allowed for notifications if (!tag_tools_is_notification_entity($entity_row->guid)) { return; } $tag = $metadata->value; $options = ['type' => 'user', 'annotation_name_value_pairs' => ['name' => 'follow_tag', 'value' => $tag], 'limit' => false]; $ia = elgg_set_ignore_access(true); $dbprefix = elgg_get_config('dbprefix'); $entities = new ElggBatch('elgg_get_entities_from_annotations', $options); foreach ($entities as $user) { // check if not trying to notify the owner if ($user->getGUID() == $entity_row->owner_guid) { continue; } // force a correct access bit elgg_set_ignore_access(false); // check access for the user, can't use has_access_to_entity // because that requires a full entity $access_bit = _elgg_get_access_where_sql(['user_guid' => $user->getGUID()]); // ignore access to get the correct next user elgg_set_ignore_access(true); // build correct query to check access $query = "SELECT guid FROM {$dbprefix}entities e\n\t\t\t WHERE e.guid = {$entity_guid}\n\t\t\t AND {$access_bit}"; if (get_data($query)) { // regsiter shutdown function because we need the full entity // this is a workaround and should be reviewed in the near future register_shutdown_function('tag_tools_notify_user', $user->getGUID(), $entity_row->guid, $tag); } } elgg_set_ignore_access($ia); }
/** * Return the number of users registered in the system. * * @param bool $show_deactivated Count not enabled users? * * @return int */ function get_number_users($show_deactivated = false) { global $CONFIG; $access = ""; if (!$show_deactivated) { $access = "and " . _elgg_get_access_where_sql(array('table_alias' => '')); } $query = "SELECT count(*) as count\n\t\tfrom {$CONFIG->dbprefix}entities where type='user' {$access}"; $result = get_data_row($query); if ($result) { return $result->count; } return false; }
/** * Get an array of users from an email address * * @param string $email Email address. * * @return array */ function get_user_by_email($email) { global $CONFIG; $email = sanitise_string($email); $access = _elgg_get_access_where_sql(); $query = "SELECT e.* FROM {$CONFIG->dbprefix}entities e\n\t\tJOIN {$CONFIG->dbprefix}users_entity u ON e.guid = u.guid\n\t\tWHERE email = '{$email}' AND {$access}"; return get_data($query, 'entity_row_to_elggstar'); }
function elgg_solr_get_entity_guids(array $options = array()) { global $CONFIG; $defaults = array('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' => $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, 'reverse_order_by' => false, 'order_by' => 'e.time_created desc', 'group_by' => ELGG_ENTITIES_ANY_VALUE, 'limit' => 10, 'offset' => 0, 'count' => false, 'selects' => array(), 'wheres' => array(), 'joins' => array(), 'callback' => false, '__ElggBatch' => null); $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'); $options = _elgg_normalize_plural_options_array($options, $singulars); // evaluate where clauses if (!is_array($options['wheres'])) { $options['wheres'] = array($options['wheres']); } $wheres = $options['wheres']; $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']); // 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]); } } // remove identical where clauses $wheres = array_unique($wheres); // evaluate join clauses if (!is_array($options['joins'])) { $options['joins'] = array($options['joins']); } // remove identical join clauses $joins = array_unique($options['joins']); foreach ($joins as $i => $join) { if ($join === false) { return false; } elseif (empty($join)) { unset($joins[$i]); } } // evalutate selects if ($options['selects']) { $selects = ''; foreach ($options['selects'] as $select) { $selects .= ", {$select}"; } } else { $selects = ''; } if (!$options['count']) { $distinct = ''; if ($options['require_distinct']) { $distinct = ' DISTINCT'; } $query = "SELECT{$distinct} e.guid{$selects} FROM {$CONFIG->dbprefix}entities e "; } else { $query = "SELECT count(DISTINCT e.guid) as total FROM {$CONFIG->dbprefix}entities e "; } // add joins foreach ($joins as $j) { $query .= " {$j} "; } // add wheres $query .= ' WHERE '; foreach ($wheres as $w) { $query .= " {$w} AND "; } // Add access controls $query .= _elgg_get_access_where_sql(); // reverse order by if ($options['reverse_order_by']) { $options['order_by'] = _elgg_sql_reverse_order_by_clause($options['order_by']); } if (!$options['count']) { if ($options['group_by']) { $query .= " GROUP BY {$options['group_by']}"; } if ($options['order_by']) { $query .= " ORDER BY {$options['order_by']}"; } if ($options['limit']) { $limit = sanitise_int($options['limit'], false); $offset = sanitise_int($options['offset'], false); $query .= " LIMIT {$offset}, {$limit}"; } if ($options['callback'] === 'entity_row_to_elggstar') { $dt = _elgg_fetch_entities_from_sql($query, $options['__ElggBatch']); } else { $dt = get_data($query, $options['callback']); } if ($dt) { // populate entity and metadata caches $guids = array(); foreach ($dt as $item) { // A custom callback could result in items that aren't ElggEntity's, so check for them if ($item instanceof ElggEntity) { _elgg_cache_entity($item); // plugins usually have only settings if (!$item instanceof ElggPlugin) { $guids[] = $item->guid; } } } // @todo Without this, recursive delete fails. See #4568 reset($dt); if ($guids) { _elgg_get_metadata_cache()->populateFromEntities($guids); } } return $dt; } else { $total = get_data_row($query); return (int) $total->total; } }
public function testAccessPluginHookAddAnd() { elgg_register_plugin_hook_handler('get_sql', 'access', array($this, 'addAndCallback')); $sql = _elgg_get_access_where_sql(); $ans = "((1 = 1) AND (e.enabled = 'yes' AND 57 > 32))"; $this->assertTrue($this->assertSqlEqual($ans, $sql), "{$sql} does not match {$ans}"); }
/** * Returns metadata name and value SQL where for entities. * NB: $names and $values are not paired. Use $pairs for this. * Pairs default to '=' operand. * * This function is reused for annotations because the tables are * exactly the same. * * @param string $e_table Entities table name * @param string $n_table Normalized metastrings table name (Where entities, * values, and names are joined. annotations / metadata) * @param array|null $names Array of names * @param array|null $values Array of values * @param array|null $pairs Array of names / values / operands * @param string $pair_operator ("AND" or "OR") Operator to use to join the where clauses for pairs * @param bool $case_sensitive Case sensitive metadata names? * @param array|null $order_by_metadata Array of names / direction * @param array|null $owner_guids Array of owner GUIDs * * @return false|array False on fail, array('joins', 'wheres') * @since 1.7.0 * @access private */ function _elgg_get_entity_metadata_where_sql($e_table, $n_table, $names = null, $values = null, $pairs = null, $pair_operator = 'AND', $case_sensitive = true, $order_by_metadata = null, $owner_guids = null) { global $CONFIG; // short circuit if nothing requested // 0 is a valid (if not ill-conceived) metadata name. // 0 is also a valid metadata value for false, null, or 0 // 0 is also a valid(ish) owner_guid if (!$names && $names !== 0 && (!$values && $values !== 0) && (!$pairs && $pairs !== 0) && (!$owner_guids && $owner_guids !== 0) && !$order_by_metadata) { return ''; } // 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 = _elgg_get_access_where_sql(array('table_alias' => 'n_table')); $return = array('joins' => array(), 'wheres' => array(), 'orders' => array()); // will always want to join these tables if pulling metastrings. $return['joins'][] = "JOIN {$CONFIG->dbprefix}{$n_table} n_table on\n\t\t{$e_table}.guid = n_table.entity_guid"; $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 {$CONFIG->dbprefix}metastrings msn on n_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 {$CONFIG->dbprefix}metastrings msv on n_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})"; } // add pairs // pairs must be in arrays. if (is_array($pairs)) { // check if this is an array of pairs or just a single pair. if (isset($pairs['name']) || isset($pairs['value'])) { $pairs = array($pairs); } $pair_wheres = array(); // @todo when the pairs are > 3 should probably split the query up to // denormalize the strings table. foreach ($pairs as $index => $pair) { // @todo move this elsewhere? // support shortcut 'n' => 'v' method. if (!is_array($pair)) { $pair = array('name' => $index, 'value' => $pair); } // must have at least a name and value if (!isset($pair['name']) || !isset($pair['value'])) { // @todo should probably return false. continue; } // case sensitivity can be specified per pair. // default to higher level setting. if (isset($pair['case_sensitive'])) { $pair_binary = $pair['case_sensitive'] ? ' BINARY ' : ''; } else { $pair_binary = $binary; } if (isset($pair['operand'])) { $operand = sanitise_string($pair['operand']); } else { $operand = ' = '; } // for comparing $trimmed_operand = trim(strtolower($operand)); $access = _elgg_get_access_where_sql(array('table_alias' => "n_table{$i}")); // if the value is an int, don't quote it because str '15' < str '5' // if the operand is IN don't quote it because quoting should be done already. if (is_numeric($pair['value'])) { $value = sanitise_string($pair['value']); } else { if (is_bool($pair['value'])) { $value = (int) $pair['value']; } else { if (is_array($pair['value'])) { $values_array = array(); foreach ($pair['value'] as $pair_value) { if (is_numeric($pair_value)) { $values_array[] = sanitise_string($pair_value); } else { $values_array[] = "'" . sanitise_string($pair_value) . "'"; } } if ($values_array) { $value = '(' . implode(', ', $values_array) . ')'; } // @todo allow support for non IN operands with array of values. // will have to do more silly joins. $operand = 'IN'; } else { if ($trimmed_operand == 'in') { $value = "({$pair['value']})"; } else { $value = "'" . sanitise_string($pair['value']) . "'"; } } } } $name = sanitise_string($pair['name']); // @todo The multiple joins are only needed when the operator is AND $return['joins'][] = "JOIN {$CONFIG->dbprefix}{$n_table} n_table{$i}\n\t\t\t\ton {$e_table}.guid = n_table{$i}.entity_guid"; $return['joins'][] = "JOIN {$CONFIG->dbprefix}metastrings msn{$i}\n\t\t\t\ton n_table{$i}.name_id = msn{$i}.id"; $return['joins'][] = "JOIN {$CONFIG->dbprefix}metastrings msv{$i}\n\t\t\t\ton n_table{$i}.value_id = msv{$i}.id"; $pair_wheres[] = "(msn{$i}.string = '{$name}' AND {$pair_binary}msv{$i}.string\n\t\t\t\t{$operand} {$value} AND {$access})"; $i++; } if ($where = implode(" {$pair_operator} ", $pair_wheres)) { $wheres[] = "({$where})"; } } // add owner_guids if ($owner_guids) { if (is_array($owner_guids)) { $sanitised = array_map('sanitise_int', $owner_guids); $owner_str = implode(',', $sanitised); } else { $owner_str = sanitise_int($owner_guids); } $wheres[] = "(n_table.owner_guid IN ({$owner_str}))"; } if ($where = implode(' AND ', $wheres)) { $return['wheres'][] = "({$where})"; } if (is_array($order_by_metadata)) { if (count($order_by_metadata) > 0 && !isset($order_by_metadata[0])) { // singleton, so fix $order_by_metadata = array($order_by_metadata); } foreach ($order_by_metadata as $order_by) { if (is_array($order_by) && isset($order_by['name'])) { $name = sanitise_string($order_by['name']); if (isset($order_by['direction'])) { $direction = sanitise_string($order_by['direction']); } else { $direction = 'ASC'; } $return['joins'][] = "JOIN {$CONFIG->dbprefix}{$n_table} n_table{$i}\n\t\t\t\t\ton {$e_table}.guid = n_table{$i}.entity_guid"; $return['joins'][] = "JOIN {$CONFIG->dbprefix}metastrings msn{$i}\n\t\t\t\t\ton n_table{$i}.name_id = msn{$i}.id"; $return['joins'][] = "JOIN {$CONFIG->dbprefix}metastrings msv{$i}\n\t\t\t\t\ton n_table{$i}.value_id = msv{$i}.id"; $access = _elgg_get_access_where_sql(array('table_alias' => "n_table{$i}")); $return['wheres'][] = "(msn{$i}.string = '{$name}' AND {$access})"; if (isset($order_by['as']) && $order_by['as'] == 'integer') { $return['orders'][] = "CAST(msv{$i}.string AS SIGNED) {$direction}"; } else { $return['orders'][] = "msv{$i}.string {$direction}"; } $i++; } } } return $return; }
/** * Returns the SQL where clause for a table with access_id and enabled columns. * * This handles returning where clauses for ACCESS_FRIENDS in addition to using * get_access_list() for access collections and the standard access levels. * * Note that if this code is executed in privileged mode it will return (1=1). * * @param string $table_prefix Optional table prefix for the access code. * @param int $owner Optional user guid to get access information for. Defaults * to logged in user. * @return string * @access private * @deprecated 1.9 Use _elgg_get_access_where_sql() */ function get_access_sql_suffix($table_prefix = '', $owner = null) { elgg_deprecated_notice(__FUNCTION__ . ' is deprecated by _elgg_get_access_where_sql()', 1.9); return _elgg_get_access_where_sql(array('table_alias' => $table_prefix, 'user_guid' => (int) $owner)); }
/** * Returns a list of months in which entities were updated or created. * * @tip Use this to generate a list of archives by month for when entities were added or updated. * * @todo document how to pass in array for $subtype * * @warning Months are returned in the form YYYYMM. * * @param string $type The type of entity * @param string $subtype The subtype of entity * @param int $container_guid The container GUID that the entities belong to * @param int $site_guid The site GUID * @param string $order_by Order_by SQL order by clause * * @return array|false Either an array months as YYYYMM, or false on failure */ function getDates($type = '', $subtype = '', $container_guid = 0, $site_guid = 0, $order_by = 'time_created') { $site_guid = (int) $site_guid; if ($site_guid == 0) { $site_guid = $this->CONFIG->site_guid; } $where = array(); if ($type != "") { $type = sanitise_string($type); $where[] = "type='{$type}'"; } if (is_array($subtype)) { $tempwhere = ""; if (sizeof($subtype)) { foreach ($subtype as $typekey => $subtypearray) { foreach ($subtypearray as $subtypeval) { $typekey = sanitise_string($typekey); if (!empty($subtypeval)) { if (!($subtypeval = (int) get_subtype_id($typekey, $subtypeval))) { return false; } } else { $subtypeval = 0; } if (!empty($tempwhere)) { $tempwhere .= " or "; } $tempwhere .= "(type = '{$typekey}' and subtype = {$subtypeval})"; } } } if (!empty($tempwhere)) { $where[] = "({$tempwhere})"; } } else { if ($subtype) { if (!($subtype_id = get_subtype_id($type, $subtype))) { return false; } else { $where[] = "subtype={$subtype_id}"; } } } if ($container_guid !== 0) { if (is_array($container_guid)) { foreach ($container_guid as $key => $val) { $container_guid[$key] = (int) $val; } $where[] = "container_guid in (" . implode(",", $container_guid) . ")"; } else { $container_guid = (int) $container_guid; $where[] = "container_guid = {$container_guid}"; } } if ($site_guid > 0) { $where[] = "site_guid = {$site_guid}"; } $where[] = _elgg_get_access_where_sql(array('table_alias' => '')); $sql = "SELECT DISTINCT EXTRACT(YEAR_MONTH FROM FROM_UNIXTIME(time_created)) AS yearmonth\n\t\t\tFROM {$this->CONFIG->dbprefix}entities where "; foreach ($where as $w) { $sql .= " {$w} and "; } $sql .= "1=1 ORDER BY {$order_by}"; if ($result = _elgg_services()->db->getData($sql)) { $endresult = array(); foreach ($result as $res) { $endresult[] = $res->yearmonth; } return $endresult; } return false; }
/** * Populate the cache from a set of entities * * @param int|array $guids Array of or single GUIDs * @return void */ public function populateFromEntities($guids) { if (empty($guids)) { return; } $version = (int) elgg_get_config('version'); if (!empty($version) && $version < 2016110900) { // can't use this during upgrade from 2.x to 3.0 return; } $access_key = $this->getAccessKey(); if (!is_array($guids)) { $guids = array($guids); } $guids = array_unique($guids); // could be useful at some point in future //$guids = $this->filterMetadataHeavyEntities($guids); $db_prefix = _elgg_services()->db->prefix; $options = array('guids' => $guids, 'limit' => 0, 'callback' => false, 'distinct' => false, 'order_by' => 'n_table.entity_guid, n_table.time_created ASC, n_table.id ASC', 'wheres' => array(_elgg_get_access_where_sql(array('table_alias' => 'n_table', 'guid_column' => 'entity_guid')))); $data = _elgg_services()->metadataTable->getAll($options); // make sure we show all entities as loaded foreach ($guids as $guid) { $this->values[$access_key][$guid] = null; } // build up metadata for each entity, save when GUID changes (or data ends) $last_guid = null; $metadata = array(); $last_row_idx = count($data) - 1; foreach ($data as $i => $row) { $name = $row->name; $value = $row->value_type === 'text' ? $row->value : (int) $row->value; $guid = $row->entity_guid; if ($guid !== $last_guid) { if ($last_guid) { $this->values[$access_key][$last_guid] = $metadata; } $metadata = array(); } if (isset($metadata[$name])) { $metadata[$name] = (array) $metadata[$name]; $metadata[$name][] = $value; } else { $metadata[$name] = $value; } if ($i == $last_row_idx) { $this->values[$access_key][$guid] = $metadata; } $last_guid = $guid; } }
/** * Get an array of users from an email address * * @param string $email Email address. * * @return array */ function getByEmail($email) { $email = sanitise_string($email); $access = _elgg_get_access_where_sql(); $query = "SELECT e.* FROM {$this->CONFIG->dbprefix}entities e\n\t\t\tJOIN {$this->CONFIG->dbprefix}users_entity u ON e.guid = u.guid\n\t\t\tWHERE email = '{$email}' AND {$access}"; return _elgg_services()->db->getData($query, 'entity_row_to_elggstar'); }
/** * Get river items * * @note If using types and subtypes in a query, they are joined with an AND. * * @param array $options Parameters: * ids => INT|ARR River item id(s) * subject_guids => INT|ARR Subject guid(s) * object_guids => INT|ARR Object guid(s) * target_guids => INT|ARR Target guid(s) * annotation_ids => INT|ARR The identifier of the annotation(s) * action_types => STR|ARR The river action type(s) identifier * posted_time_lower => INT The lower bound on the time posted * posted_time_upper => INT The upper bound on the time posted * * types => STR|ARR Entity type string(s) * subtypes => STR|ARR Entity subtype string(s) * type_subtype_pairs => ARR Array of type => subtype pairs where subtype * can be an array of subtype strings * * relationship => STR Relationship identifier * relationship_guid => INT|ARR Entity guid(s) * inverse_relationship => BOOL Subject or object of the relationship (false) * * limit => INT Number to show per page (20) * offset => INT Offset in list (0) * count => BOOL Count the river items? (false) * order_by => STR Order by clause (rv.posted desc) * group_by => STR Group by clause * * distinct => BOOL If set to false, Elgg will drop the DISTINCT * clause from the MySQL query, which will improve * performance in some situations. Avoid setting this * option without a full understanding of the * underlying SQL query Elgg creates. (true) * * @return array|int * @since 1.8.0 */ function elgg_get_group_river(array $options = array()) { global $CONFIG; //error_log("group river"); $defaults = array('ids' => ELGG_ENTITIES_ANY_VALUE, 'subject_guids' => ELGG_ENTITIES_ANY_VALUE, 'object_guids' => ELGG_ENTITIES_ANY_VALUE, 'target_guids' => ELGG_ENTITIES_ANY_VALUE, 'annotation_ids' => ELGG_ENTITIES_ANY_VALUE, 'action_types' => ELGG_ENTITIES_ANY_VALUE, 'relationship' => null, 'relationship_guid' => null, 'inverse_relationship' => false, 'types' => ELGG_ENTITIES_ANY_VALUE, 'subtypes' => ELGG_ENTITIES_ANY_VALUE, 'type_subtype_pairs' => ELGG_ENTITIES_ANY_VALUE, 'posted_time_lower' => ELGG_ENTITIES_ANY_VALUE, 'posted_time_upper' => ELGG_ENTITIES_ANY_VALUE, 'limit' => 20, 'offset' => 0, 'count' => false, 'distinct' => false, 'order_by' => 'u.posted desc', 'group_by' => ELGG_ENTITIES_ANY_VALUE, 'wheres' => array(), 'wheres1' => array(), 'wheres2' => array(), 'joins' => array()); $options = array_merge($defaults, $options); $singulars = array('id', 'subject_guid', 'object_guid', 'target_guid', 'annotation_id', 'action_type', 'type', 'subtype'); $options = _elgg_normalize_plural_options_array($options, $singulars); $wheres1 = $options['wheres1']; $wheres2 = $options['wheres2']; /* $wheres[] = _elgg_get_guid_based_where_sql('rv.id', $options['ids']); $wheres[] = _elgg_get_guid_based_where_sql('rv.subject_guid', $options['subject_guids']); $wheres[] = _elgg_get_guid_based_where_sql('rv.object_guid', $options['object_guids']); $wheres[] = _elgg_get_guid_based_where_sql('rv.target_guid', $options['target_guids']); $wheres[] = _elgg_get_guid_based_where_sql('rv.annotation_id', $options['annotation_ids']); $wheres[] = _elgg_river_get_action_where_sql($options['action_types']); $wheres[] = _elgg_get_river_type_subtype_where_sql('rv', $options['types'], $options['subtypes'], $options['type_subtype_pairs']); */ /*if ($options['posted_time_lower'] && is_int($options['posted_time_lower'])) { $wheres1[] = "rv.posted >= {$options['posted_time_lower']}"; $wheres2[] = "rv.posted >= {$options['posted_time_lower']}"; } if ($options['posted_time_upper'] && is_int($options['posted_time_upper'])) { $wheres1[] = "rv.posted <= {$options['posted_time_upper']}"; $wheres2[] = "rv.posted <= {$options['posted_time_upper']}"; }*/ if (!access_get_show_hidden_status()) { $wheres1[] = "rv.enabled = 'yes'"; $wheres2[] = "rv.enabled = 'yes'"; } $dbprefix = elgg_get_config('dbprefix'); $join1 = "JOIN {$dbprefix}entities oe ON rv.object_guid = oe.guid"; // LEFT JOIN is used because all river items do not necessarily have target $join2 = "LEFT JOIN {$dbprefix}entities te ON rv.target_guid = te.guid"; // see if any functions failed // remove empty strings on successful functions /*foreach ($wheres1 as $i => $where) { if ($where === false) { return false; } elseif (empty($where)) { unset($wheres1[$i]); } } foreach ($wheres2 as $i => $where) { if ($where === false) { return false; } elseif (empty($where)) { unset($wheres2[$i]); } } // remove identical where clauses $wheres1 = array_unique($wheres1); $wheres2 = array_unique($wheres2); */ // Wheres for the 2 parts of the union query $w1 = ""; foreach ($wheres1 as $w) { $w1 .= " {$w} AND "; } $w2 = ""; foreach ($wheres2 as $w) { $w2 .= " {$w} AND "; } // Make sure that user has access to all the entities referenced by each river item $object_access_where = _elgg_get_access_where_sql(array('table_alias' => 'oe')); $target_access_where = _elgg_get_access_where_sql(array('table_alias' => 'te')); if (!$options['count']) { $GOL = ""; // Group by / order / limit $options['group_by'] = sanitise_string($options['group_by']); if ($options['group_by']) { $GOL .= " GROUP BY {$options['group_by']}"; } $options['order_by'] = sanitise_string($options['order_by']); $GOL .= " ORDER BY {$options['order_by']}"; if ($options['limit']) { $limit = sanitise_int($options['limit']); $offset = sanitise_int($options['offset'], false); $GOL .= " LIMIT {$offset}, {$limit}"; } // custom UNION - based query $query = "SELECT u.* FROM ( ( SELECT rv.* FROM {$CONFIG->dbprefix}river rv {$join1} WHERE {$w1} {$object_access_where} ) UNION " . "( SELECT rv.* FROM {$CONFIG->dbprefix}river rv {$join2} WHERE {$w2} ({$target_access_where} OR te.guid IS NULL) ) ) u {$GOL}"; $river_items = get_data($query, '_elgg_row_to_elgg_river_item'); _elgg_prefetch_river_entities($river_items); // error_log($query); return $river_items; } else { $query = "SELECT sum(count) as total FROM ( ( SELECT count(*) as count FROM {$CONFIG->dbprefix}river rv {$join1} WHERE {$w1} {$object_access_where} ) UNION " . "( SELECT count(*) as count FROM {$CONFIG->dbprefix}river rv {$join2} WHERE {$w2} ({$target_access_where} OR te.guid IS NULL) ) ) u"; // error_log($query); $total = get_data_row($query); return (int) $total->total; } }
/** * Can a user access an entity. * * @warning If a logged in user doesn't have access to an entity, the * core engine will not load that entity. * * @tip This is mostly useful for checking if a user other than the logged in * user has access to an entity that is currently loaded. * * @todo This function would be much more useful if we could pass the guid of the * entity to test access for. We need to be able to tell whether the entity exists * and whether the user has access to the entity. * * @param ElggEntity $entity The entity to check access for. * @param ElggUser $user Optionally user to check access for. Defaults to * logged in user (which is a useless default). * * @return bool */ function has_access_to_entity($entity, $user = null) { global $CONFIG; // See #7159. Must not allow ignore access to affect query $ia = elgg_set_ignore_access(false); if (!isset($user)) { $access_bit = _elgg_get_access_where_sql(); } else { $access_bit = _elgg_get_access_where_sql(array('user_guid' => $user->getGUID())); } elgg_set_ignore_access($ia); $query = "SELECT guid from {$CONFIG->dbprefix}entities e WHERE e.guid = " . $entity->getGUID(); // Add access controls $query .= " AND " . $access_bit; if (get_data($query)) { return true; } else { return false; } }
$offset = 0; $limit = (int) $widget->num_display; if ($limit < 1) { $limit = 10; } $sql = "SELECT {$dbprefix}river.*"; $sql .= " FROM {$dbprefix}river"; $sql .= " INNER JOIN {$dbprefix}entities AS entities1 ON {$dbprefix}river.object_guid = entities1.guid"; $sql .= ' WHERE (entities1.container_guid in (' . implode(',', $group_guid) . ')'; $sql .= " OR {$dbprefix}river.object_guid IN (" . implode(',', $group_guid) . '))'; if (!empty($activity_filter) && is_string($activity_filter)) { list($type, $subtype) = explode(',', $activity_filter); if (!empty($type)) { $filter_where = " ({$dbprefix}river.type = '" . sanitise_string($type) . "'"; if (!empty($subtype)) { $filter_where .= " AND {$dbprefix}river.subtype = '" . sanitise_string($subtype) . "'"; } $filter_where .= ')'; $sql .= ' AND ' . $filter_where; } } $sql .= ' AND ' . _elgg_get_access_where_sql(['table_alias' => 'entities1']); $sql .= " ORDER BY {$dbprefix}river.posted DESC"; $sql .= " LIMIT {$offset},{$limit}"; $items = get_data($sql, '_elgg_row_to_elgg_river_item'); if (empty($items)) { echo elgg_echo('widgets:group_river_widget:view:noactivity'); return; } $options = ['pagination' => false, 'count' => count($items), 'items' => $items, 'list_class' => 'elgg-list-river elgg-river', 'limit' => $limit, 'offset' => $offset]; echo elgg_view('page/components/list', $options);
/** * Can a user access an entity. * * @warning If a logged in user doesn't have access to an entity, the * core engine will not load that entity. * * @tip This is mostly useful for checking if a user other than the logged in * user has access to an entity that is currently loaded. * * @todo This function would be much more useful if we could pass the guid of the * entity to test access for. We need to be able to tell whether the entity exists * and whether the user has access to the entity. * * @param ElggEntity $entity The entity to check access for. * @param ElggUser $user Optionally user to check access for. Defaults to * logged in user (which is a useless default). * * @return bool */ function has_access_to_entity($entity, $user = null) { global $CONFIG; if (!isset($user)) { $access_bit = _elgg_get_access_where_sql(); } else { $access_bit = _elgg_get_access_where_sql(array('user_guid' => $user->getGUID())); } $query = "SELECT guid from {$CONFIG->dbprefix}entities e WHERE e.guid = " . $entity->getGUID(); // Add access controls $query .= " AND " . $access_bit; if (get_data($query)) { return true; } else { return false; } }
/** * Returns metadata name and value SQL where for entities. * NB: $names and $values are not paired. Use $pairs for this. * Pairs default to '=' operand. * * This function is reused for annotations because the tables are * exactly the same. * * @param string $e_table Entities table name * @param string $n_table Normalized metastrings table name (Where entities, * values, and names are joined. annotations / metadata) * @param array|null $names Array of names * @param array|null $values Array of values * @param array|null $pairs Array of names / values / operands * @param string $pair_operator ("AND" or "OR") Operator to use to join the where clauses for pairs * @param bool $case_sensitive Case sensitive metadata names? * @param array|null $order_by_metadata Array of names / direction * @param array|null $owner_guids Array of owner GUIDs * * @return false|array False on fail, array('joins', 'wheres') * @access private */ function getEntityMetadataWhereSql($e_table, $n_table, $names = null, $values = null, $pairs = null, $pair_operator = 'AND', $case_sensitive = true, $order_by_metadata = null, $owner_guids = null) { // short circuit if nothing requested // 0 is a valid (if not ill-conceived) metadata name. // 0 is also a valid metadata value for false, null, or 0 // 0 is also a valid(ish) owner_guid if (!$names && $names !== 0 && (!$values && $values !== 0) && (!$pairs && $pairs !== 0) && (!$owner_guids && $owner_guids !== 0) && !$order_by_metadata) { return ''; } // 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 = _elgg_get_access_where_sql(array('table_alias' => 'n_table', 'guid_column' => 'entity_guid')); $return = array('joins' => array(), 'wheres' => array(), 'orders' => array()); $return['joins'][] = "JOIN {$this->db->prefix}{$n_table} n_table on\n\t\t\t{$e_table}.guid = n_table.entity_guid"; $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[] = '\'' . $this->db->sanitizeString($name) . '\''; } if ($names_str = implode(',', $sanitised_names)) { $names_where = "(n_table.name 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[] = '\'' . $this->db->sanitizeString($value) . '\''; } if ($values_str = implode(',', $sanitised_values)) { $values_where = "({$binary}n_table.value 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})"; } // add pairs // pairs must be in arrays. if (is_array($pairs)) { // check if this is an array of pairs or just a single pair. if (isset($pairs['name']) || isset($pairs['value'])) { $pairs = array($pairs); } $pair_wheres = array(); // @todo when the pairs are > 3 should probably split the query up to // denormalize the strings table. foreach ($pairs as $index => $pair) { // @todo move this elsewhere? // support shortcut 'n' => 'v' method. if (!is_array($pair)) { $pair = array('name' => $index, 'value' => $pair); } // must have at least a name and value if (!isset($pair['name']) || !isset($pair['value'])) { // @todo should probably return false. continue; } // case sensitivity can be specified per pair. // default to higher level setting. if (isset($pair['case_sensitive'])) { $pair_binary = $pair['case_sensitive'] ? ' BINARY ' : ''; } else { $pair_binary = $binary; } if (isset($pair['operand'])) { $operand = $this->db->sanitizeString($pair['operand']); } else { $operand = ' = '; } // for comparing $trimmed_operand = trim(strtolower($operand)); $access = _elgg_get_access_where_sql(array('table_alias' => "n_table{$i}", 'guid_column' => 'entity_guid')); // certain operands can't work well with strings that can be interpreted as numbers // for direct comparisons like IN, =, != we treat them as strings // gt/lt comparisons need to stay unencapsulated because strings '5' > '15' // see https://github.com/Elgg/Elgg/issues/7009 $num_safe_operands = array('>', '<', '>=', '<='); $num_test_operand = trim(strtoupper($operand)); if (is_numeric($pair['value']) && in_array($num_test_operand, $num_safe_operands)) { $value = $this->db->sanitizeString($pair['value']); } else { if (is_bool($pair['value'])) { $value = (int) $pair['value']; } else { if (is_array($pair['value'])) { $values_array = array(); foreach ($pair['value'] as $pair_value) { if (is_numeric($pair_value) && !in_array($num_test_operand, $num_safe_operands)) { $values_array[] = $this->db->sanitizeString($pair_value); } else { $values_array[] = "'" . $this->db->sanitizeString($pair_value) . "'"; } } if ($values_array) { $value = '(' . implode(', ', $values_array) . ')'; } // @todo allow support for non IN operands with array of values. // will have to do more silly joins. $operand = 'IN'; } else { if ($trimmed_operand == 'in') { $value = "({$pair['value']})"; } else { $value = "'" . $this->db->sanitizeString($pair['value']) . "'"; } } } } $name = $this->db->sanitizeString($pair['name']); $return['joins'][] = "JOIN {$this->db->prefix}{$n_table} n_table{$i}\n\t\t\t\t\ton {$e_table}.guid = n_table{$i}.entity_guid"; $pair_wheres[] = "(n_table{$i}.name = '{$name}' AND {$pair_binary}n_table{$i}.value\n\t\t\t\t\t{$operand} {$value} AND {$access})"; $i++; } if ($where = implode(" {$pair_operator} ", $pair_wheres)) { $wheres[] = "({$where})"; } } // add owner_guids if ($owner_guids) { if (is_array($owner_guids)) { $sanitised = array_map('sanitise_int', $owner_guids); $owner_str = implode(',', $sanitised); } else { $owner_str = (int) $owner_guids; } $wheres[] = "(n_table.owner_guid IN ({$owner_str}))"; } if ($where = implode(' AND ', $wheres)) { $return['wheres'][] = "({$where})"; } if (is_array($order_by_metadata)) { if (count($order_by_metadata) > 0 && !isset($order_by_metadata[0])) { // singleton, so fix $order_by_metadata = array($order_by_metadata); } foreach ($order_by_metadata as $order_by) { if (is_array($order_by) && isset($order_by['name'])) { $name = $this->db->sanitizeString($order_by['name']); if (isset($order_by['direction'])) { $direction = $this->db->sanitizeString($order_by['direction']); } else { $direction = 'ASC'; } $return['joins'][] = "JOIN {$this->db->prefix}{$n_table} n_table{$i}\n\t\t\t\t\t\ton {$e_table}.guid = n_table{$i}.entity_guid"; $access = _elgg_get_access_where_sql(array('table_alias' => "n_table{$i}", 'guid_column' => 'entity_guid')); $return['wheres'][] = "(n_table{$i}.name = '{$name}' AND {$access})"; if (isset($order_by['as']) && $order_by['as'] == 'integer') { $return['orders'][] = "CAST(n_table{$i}.value AS SIGNED) {$direction}"; } else { $return['orders'][] = "n_table{$i}.value {$direction}"; } $i++; } } } return $return; }
/** * Add query query_specs for a metadata object * * @param stdClass $row Data row * @return void */ public function addQuerySpecs(stdClass $row) { $this->clearQuerySpecs($row); // Return this metadata object when _elgg_get_metastring_based_objects() is called $e_access_sql = _elgg_get_access_where_sql(array('table_alias' => 'e')); $md_access_sql = _elgg_get_access_where_sql(array('table_alias' => 'n_table', 'guid_column' => 'entity_guid')); $dbprefix = elgg_get_config('dbprefix'); $sql = "SELECT DISTINCT n_table.*\n\t\t\tFROM {$dbprefix}metadata n_table\n\t\t\t\tJOIN {$dbprefix}entities e ON n_table.entity_guid = e.guid\n\t\t\t\tWHERE (n_table.id IN ({$row->id}) AND {$md_access_sql}) AND {$e_access_sql}\n\t\t\t\tORDER BY n_table.time_created ASC, n_table.id ASC, n_table.id"; $this->query_specs[$row->id][] = $this->db->addQuerySpec(['sql' => $sql, 'results' => function () use($row) { if (isset($this->rows[$row->id])) { return [$this->rows[$row->id]]; } return []; }]); $sql = "INSERT INTO {$dbprefix}metadata\n\t\t\t\t(entity_guid, name, value, value_type, owner_guid, time_created, access_id)\n\t\t\t\tVALUES (:entity_guid, :name, :value, :value_type, :owner_guid, :time_created, :access_id)"; $this->query_specs[$row->id][] = $this->db->addQuerySpec(['sql' => $sql, 'params' => [':entity_guid' => $row->entity_guid, ':name' => $row->name, ':value' => $row->value, ':value_type' => $row->value_type, ':owner_guid' => $row->owner_guid, ':time_created' => $row->time_created, ':access_id' => $row->access_id], 'insert_id' => $row->id]); $sql = "UPDATE {$dbprefix}metadata\n\t\t\tSET name = :name,\n\t\t\t value = :value,\n\t\t\t\tvalue_type = :value_type,\n\t\t\t\taccess_id = :access_id,\n\t\t\t owner_guid = :owner_guid\n\t\t\tWHERE id = :id"; $this->query_specs[$row->id][] = $this->db->addQuerySpec(['sql' => $sql, 'params' => [':name' => $row->name, ':value' => $row->value, ':value_type' => $row->value_type, ':owner_guid' => $row->owner_guid, ':access_id' => $row->access_id, ':id' => $row->id], 'results' => function () use($row) { if (isset($this->rows[$row->id])) { return [$row->id]; } return []; }]); // Enable/disable metadata $sql = "UPDATE {$dbprefix}metadata SET enabled = :enabled where id = :id"; $this->query_specs[$row->id][] = $this->db->addQuerySpec(['sql' => $sql, 'params' => [':id' => $row->id, ':enabled' => 'yes'], 'results' => function () use($row) { if (isset($this->rows[$row->id])) { $this->rows[$row->id]->enabled = 'yes'; return [$row->id]; } return []; }]); $this->query_specs[$row->id][] = $this->db->addQuerySpec(['sql' => $sql, 'params' => [':id' => $row->id, ':enabled' => 'no'], 'results' => function () use($row) { if (isset($this->rows[$row->id])) { $this->rows[$row->id]->enabled = 'no'; return [$row->id]; } return []; }]); // Delete $sql = "DELETE FROM {$dbprefix}metadata WHERE id = :id"; $this->query_specs[$row->id][] = $this->db->addQuerySpec(['sql' => $sql, 'params' => [':id' => $row->id], 'results' => function () use($row) { if (isset($this->rows[$row->id])) { unset($this->rows[$row->id]); $this->clearQuerySpecs($row); return [$row->id]; } return []; }]); }
/** * Populate the cache from a set of entities * * @param int|array $guids Array of or single GUIDs * @return void */ public function populateFromEntities($guids) { if (empty($guids)) { return; } if (!is_array($guids)) { $guids = array($guids); } $guids = array_unique($guids); // could be useful at some point in future //$guids = $this->filterMetadataHeavyEntities($guids); $db_prefix = elgg_get_config('dbprefix'); $options = array('guids' => $guids, 'limit' => 0, 'callback' => false, 'joins' => array("JOIN {$db_prefix}metastrings v ON n_table.value_id = v.id", "JOIN {$db_prefix}metastrings n ON n_table.name_id = n.id"), 'selects' => array('n.string AS name', 'v.string AS value'), 'order_by' => 'n_table.entity_guid, n_table.time_created ASC', 'wheres' => array(_elgg_get_access_where_sql(array('table_alias' => 'n_table')))); $data = elgg_get_metadata($options); // build up metadata for each entity, save when GUID changes (or data ends) $last_guid = null; $metadata = array(); $last_row_idx = count($data) - 1; foreach ($data as $i => $row) { $name = $row->name; $value = $row->value_type === 'text' ? $row->value : (int) $row->value; $guid = $row->entity_guid; if ($guid !== $last_guid) { if ($last_guid) { $this->saveAll($last_guid, $metadata); } $metadata = array(); } if (isset($metadata[$name])) { $metadata[$name] = (array) $metadata[$name]; $metadata[$name][] = $value; } else { $metadata[$name] = $value; } if ($i == $last_row_idx) { $this->saveAll($guid, $metadata); } $last_guid = $guid; } }
/** * Get Elgg access SQL suffix * * @param string $table_alias Table alias * @return string */ function sqlGetAccessSuffix($table_alias = 'e') { return _elgg_get_access_where_sql(array('table_alias' => $table_alias)); }
/** * Construct and execute the query required for the activity stream. * * @deprecated 1.8 This is outdated and uses the systemlog table instead of the river table. * Don't use it. */ function get_activity_stream_data($limit = 10, $offset = 0, $type = "", $subtype = "", $owner_guid = "", $owner_relationship = "") { elgg_deprecated_notice("get_activity_stream_data was deprecated", 1.8); global $CONFIG; $limit = (int) $limit; $offset = (int) $offset; if ($type) { if (!is_array($type)) { $type = array(sanitise_string($type)); } else { foreach ($type as $k => $v) { $type[$k] = sanitise_string($v); } } } if ($subtype) { if (!is_array($subtype)) { $subtype = array(sanitise_string($subtype)); } else { foreach ($subtype as $k => $v) { $subtype[$k] = sanitise_string($v); } } } if ($owner_guid) { if (is_array($owner_guid)) { foreach ($owner_guid as $k => $v) { $owner_guid[$k] = (int) $v; } } else { $owner_guid = array((int) $owner_guid); } } $owner_relationship = sanitise_string($owner_relationship); // Get a list of possible views $activity_events = array(); $activity_views = array_merge(elgg_view_tree('activity', 'default'), elgg_view_tree('river', 'default')); $done = array(); foreach ($activity_views as $view) { $fragments = explode('/', $view); $tmp = explode('/', $view, 2); $tmp = $tmp[1]; if (isset($fragments[0]) && ($fragments[0] == 'river' || $fragments[0] == 'activity') && !in_array($tmp, $done)) { if (isset($fragments[1])) { $f = array(); for ($n = 1; $n < count($fragments); $n++) { $val = sanitise_string($fragments[$n]); switch ($n) { case 1: $key = 'type'; break; case 2: $key = 'subtype'; break; case 3: $key = 'event'; break; } $f[$key] = $val; } // Filter result based on parameters $add = true; if ($type) { if (!in_array($f['type'], $type)) { $add = false; } } if ($add && $subtype) { if (!in_array($f['subtype'], $subtype)) { $add = false; } } if ($add && $event) { if (!in_array($f['event'], $event)) { $add = false; } } if ($add) { $activity_events[] = $f; } } $done[] = $tmp; } } $n = 0; foreach ($activity_events as $details) { // Get what we're talking about if ($details['subtype'] == 'default') { $details['subtype'] = ''; } if ($details['type'] && $details['event']) { if ($n > 0) { $obj_query .= " or "; } $access = ""; if ($details['type'] != 'relationship') { $access = " and " . _elgg_get_access_where_sql(array('table_alias' => 'sl')); } $obj_query .= "( sl.object_type='{$details['type']}'\n\t\t\t\tAND sl.object_subtype='{$details['subtype']}'\n\t\t\t\tAND sl.event='{$details['event']}' {$access} )"; $n++; } } // User if (count($owner_guid) && $owner_guid[0] != 0) { $user = "******" . implode(',', $owner_guid) . ")"; if ($owner_relationship) { $friendsarray = ""; if ($friends = elgg_get_entities_from_relationship(array('relationship' => $owner_relationship, 'relationship_guid' => $owner_guid[0], 'inverse_relationship' => FALSE, 'type' => 'user', 'subtype' => $subtype, 'limit' => false))) { $friendsarray = array(); foreach ($friends as $friend) { $friendsarray[] = $friend->getGUID(); } $user = "******" . implode(',', $friendsarray) . ")"; } } } $query = "SELECT sl.* FROM {$CONFIG->dbprefix}system_log sl\n\t\tWHERE 1 {$user} AND ({$obj_query})\n\t\tORDER BY sl.time_created desc limit {$offset}, {$limit}"; return get_data($query); }
function elgg_solr_get_annotation_ids($options) { $options = _elgg_normalize_metastrings_options($options); $type = 'annotations'; $callback = false; $defaults = array('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, 'metastring_names' => ELGG_ENTITIES_ANY_VALUE, 'metastring_values' => ELGG_ENTITIES_ANY_VALUE, 'metastring_case_sensitive' => true, '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, 'metastring_ids' => ELGG_ENTITIES_ANY_VALUE, 'order_by' => 'n_table.time_created ASC, n_table.id ASC', 'limit' => elgg_get_config('default_limit'), 'offset' => 0, 'count' => false, 'selects' => array(), 'wheres' => array(), 'joins' => array(), 'distinct' => true, 'preload_owners' => false, 'callback' => $callback); // @todo Ignore site_guid right now because of #2910 $options['site_guid'] = ELGG_ENTITIES_ANY_VALUE; $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', 'type_subtype_pair', 'guid', 'owner_guid', 'container_guid', 'site_guid', 'metastring_name', 'metastring_value', 'metastring_owner_guid', 'metastring_id', 'select', 'where', 'join'); $options = _elgg_normalize_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_services()->entityTable->getEntityTypeSubtypeWhereSql('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']); // 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]); } } // remove identical where clauses $wheres = array_unique($wheres); // 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"; // evaluate selects if (!is_array($options['selects'])) { $options['selects'] = array($options['selects']); } $selects = $options['selects']; // For performance reasons we don't want the joins required for metadata / annotations // unless we're going through one of their callbacks. // this means we expect the functions passing different callbacks to pass their required joins. // If we're doing a calculation $custom_callback = $options['callback'] == 'row_to_elggmetadata' || $options['callback'] == 'row_to_elggannotation'; $is_calculation = $options['metastring_calculation'] ? true : false; if ($custom_callback || $is_calculation) { $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"; $selects[] = 'n.string as name'; $selects[] = 'v.string as value'; } 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'], null, $options['metastring_ids'], $options['metastring_case_sensitive']); if ($metastring_clauses) { $wheres = array_merge($wheres, $metastring_clauses['wheres']); $joins = array_merge($joins, $metastring_clauses['joins']); } else { $wheres[] = _elgg_get_access_where_sql(array('table_alias' => 'n_table', 'guid_column' => 'entity_guid')); } $distinct = $options['distinct'] ? "DISTINCT " : ""; if ($options['metastring_calculation'] === ELGG_ENTITIES_NO_VALUE && !$options['count']) { $selects = array_unique($selects); // evalutate selects $select_str = ''; if ($selects) { foreach ($selects as $select) { $select_str .= ", {$select}"; } } $query = "SELECT {$distinct} n_table.id{$select_str} FROM {$db_prefix}{$type} n_table"; } elseif ($options['count']) { // count is over the entities $query = "SELECT count({$distinct} e.guid) as calculation FROM {$db_prefix}{$type} n_table"; } else { $query = "SELECT {$options['metastring_calculation']}(v.string) as calculation FROM {$db_prefix}{$type} n_table"; } // remove identical join clauses $joins = array_unique($joins); // add joins foreach ($joins as $j) { $query .= " {$j} "; } // add wheres $query .= ' WHERE '; foreach ($wheres as $w) { $query .= " {$w} AND "; } // Add access controls $query .= _elgg_get_access_where_sql(array('table_alias' => 'e')); // reverse order by if (isset($options['reverse_order_by']) && $options['reverse_order_by']) { $options['order_by'] = _elgg_sql_reverse_order_by_clause($options['order_by']); } if ($options['metastring_calculation'] === ELGG_ENTITIES_NO_VALUE && !$options['count']) { if (isset($options['group_by'])) { $options['group_by'] = sanitise_string($options['group_by']); $query .= " GROUP BY {$options['group_by']}"; } if (isset($options['order_by']) && $options['order_by']) { $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'], false); $query .= " LIMIT {$offset}, {$limit}"; } $dt = get_data($query, $options['callback']); return $dt; } else { $result = get_data_row($query); return $result->calculation; } }
/** * Searches for a user based on a complete or partial name or username. * * @param string $criteria The partial or full name or username. * @param int $limit Limit of the search. * @param int $offset Offset. * @param string $order_by The order. * @param boolean $count Whether to return the count of results or just the results. * * @return mixed * @deprecated 1.7 */ function search_for_user($criteria, $limit = 10, $offset = 0, $order_by = "", $count = false) { elgg_deprecated_notice('search_for_user() was deprecated by new search.', 1.7); global $CONFIG; $criteria = sanitise_string($criteria); $limit = (int) $limit; $offset = (int) $offset; $order_by = sanitise_string($order_by); $access = _elgg_get_access_where_sql(); if ($order_by == "") { $order_by = "e.time_created desc"; } if ($count) { $query = "SELECT count(e.guid) as total "; } else { $query = "SELECT e.* "; } $query .= "from {$CONFIG->dbprefix}entities e\n\t\tjoin {$CONFIG->dbprefix}users_entity u on e.guid=u.guid where "; $query .= "(u.name like \"%{$criteria}%\" or u.username like \"%{$criteria}%\")"; $query .= " and {$access}"; if (!$count) { $query .= " order by {$order_by} limit {$offset}, {$limit}"; return get_data($query, "entity_row_to_elggstar"); } else { if ($count = get_data_row($query)) { return $count->total; } } return false; }
/** * 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 array $ids Metastring IDs * @param bool $case_sensitive Should name and values be case sensitive? * * @return array * @access private */ function _elgg_get_metastring_sql($table, $names = null, $values = null, $pairs = null, $ids = null, $case_sensitive = false) { if (!$names && $names !== 0 && (!$values && $values !== 0) && !$ids && (!$pairs && $pairs !== 0)) { return array(); } $db_prefix = elgg_get_config('dbprefix'); // binary forces byte-to-byte comparision of strings, making // it case- and diacritical-mark- sensitive. // only supported on values. $binary = $case_sensitive ? ' BINARY ' : ''; $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 ($ids !== null) { if (!is_array($ids)) { $ids = array($ids); } $ids_str = implode(',', $ids); if ($ids_str) { $wheres[] = "n_table.id IN ({$ids_str})"; } } if ($names_where && $values_where) { $wheres[] = "({$names_where} AND {$values_where})"; } elseif ($names_where) { $wheres[] = $names_where; } elseif ($values_where) { $wheres[] = $values_where; } $wheres[] = _elgg_get_access_where_sql(array('table_alias' => $table)); if ($where = implode(' AND ', $wheres)) { $return['wheres'][] = "({$where})"; } return $return; }
/** * Get river items * * @note If using types and subtypes in a query, they are joined with an AND. * * @param array $options Parameters: * ids => INT|ARR River item id(s) * subject_guids => INT|ARR Subject guid(s) * object_guids => INT|ARR Object guid(s) * target_guids => INT|ARR Target guid(s) * annotation_ids => INT|ARR The identifier of the annotation(s) * action_types => STR|ARR The river action type(s) identifier * posted_time_lower => INT The lower bound on the time posted * posted_time_upper => INT The upper bound on the time posted * * types => STR|ARR Entity type string(s) * subtypes => STR|ARR Entity subtype string(s) * type_subtype_pairs => ARR Array of type => subtype pairs where subtype * can be an array of subtype strings * * relationship => STR Relationship identifier * relationship_guid => INT|ARR Entity guid(s) * inverse_relationship => BOOL Subject or object of the relationship (false) * * limit => INT Number to show per page (20) * offset => INT Offset in list (0) * count => BOOL Count the river items? (false) * order_by => STR Order by clause (rv.posted desc) * group_by => STR Group by clause * * distinct => BOOL If set to false, Elgg will drop the DISTINCT * clause from the MySQL query, which will improve * performance in some situations. Avoid setting this * option without a full understanding of the * underlying SQL query Elgg creates. (true) * * @return array|int * @since 1.8.0 */ function elgg_get_river(array $options = array()) { global $CONFIG; $defaults = array('ids' => ELGG_ENTITIES_ANY_VALUE, 'subject_guids' => ELGG_ENTITIES_ANY_VALUE, 'object_guids' => ELGG_ENTITIES_ANY_VALUE, 'target_guids' => ELGG_ENTITIES_ANY_VALUE, 'annotation_ids' => ELGG_ENTITIES_ANY_VALUE, 'action_types' => ELGG_ENTITIES_ANY_VALUE, 'relationship' => null, 'relationship_guid' => null, 'inverse_relationship' => false, 'types' => ELGG_ENTITIES_ANY_VALUE, 'subtypes' => ELGG_ENTITIES_ANY_VALUE, 'type_subtype_pairs' => ELGG_ENTITIES_ANY_VALUE, 'posted_time_lower' => ELGG_ENTITIES_ANY_VALUE, 'posted_time_upper' => ELGG_ENTITIES_ANY_VALUE, 'limit' => 20, 'offset' => 0, 'count' => false, 'distinct' => true, 'order_by' => 'rv.posted desc', 'group_by' => ELGG_ENTITIES_ANY_VALUE, 'wheres' => array(), 'joins' => array()); $options = array_merge($defaults, $options); $singulars = array('id', 'subject_guid', 'object_guid', 'target_guid', 'annotation_id', 'action_type', 'type', 'subtype'); $options = _elgg_normalize_plural_options_array($options, $singulars); $wheres = $options['wheres']; $wheres[] = _elgg_get_guid_based_where_sql('rv.id', $options['ids']); $wheres[] = _elgg_get_guid_based_where_sql('rv.subject_guid', $options['subject_guids']); $wheres[] = _elgg_get_guid_based_where_sql('rv.object_guid', $options['object_guids']); $wheres[] = _elgg_get_guid_based_where_sql('rv.target_guid', $options['target_guids']); $wheres[] = _elgg_get_guid_based_where_sql('rv.annotation_id', $options['annotation_ids']); $wheres[] = _elgg_river_get_action_where_sql($options['action_types']); $wheres[] = _elgg_get_river_type_subtype_where_sql('rv', $options['types'], $options['subtypes'], $options['type_subtype_pairs']); if ($options['posted_time_lower'] && is_int($options['posted_time_lower'])) { $wheres[] = "rv.posted >= {$options['posted_time_lower']}"; } if ($options['posted_time_upper'] && is_int($options['posted_time_upper'])) { $wheres[] = "rv.posted <= {$options['posted_time_upper']}"; } if (!access_get_show_hidden_status()) { $wheres[] = "rv.enabled = 'yes'"; } $joins = $options['joins']; $dbprefix = elgg_get_config('dbprefix'); $joins[] = "JOIN {$dbprefix}entities oe ON rv.object_guid = oe.guid"; // LEFT JOIN is used because all river items do not necessarily have target $joins[] = "LEFT JOIN {$dbprefix}entities te ON rv.target_guid = te.guid"; if ($options['relationship_guid']) { $clauses = elgg_get_entity_relationship_where_sql('rv.subject_guid', $options['relationship'], $options['relationship_guid'], $options['inverse_relationship']); if ($clauses) { $wheres = array_merge($wheres, $clauses['wheres']); $joins = array_merge($joins, $clauses['joins']); } } // 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]); } } // remove identical where clauses $wheres = array_unique($wheres); if (!$options['count']) { $distinct = $options['distinct'] ? "DISTINCT" : ""; $query = "SELECT {$distinct} rv.* FROM {$CONFIG->dbprefix}river rv "; } else { // note: when DISTINCT unneeded, it's slightly faster to compute COUNT(*) than IDs $count_expr = $options['distinct'] ? "DISTINCT rv.id" : "*"; $query = "SELECT COUNT({$count_expr}) as total FROM {$CONFIG->dbprefix}river rv "; } // add joins foreach ($joins as $j) { $query .= " {$j} "; } // add wheres $query .= ' WHERE '; foreach ($wheres as $w) { $query .= " {$w} AND "; } // Make sure that user has access to all the entities referenced by each river item $object_access_where = _elgg_get_access_where_sql(array('table_alias' => 'oe')); $target_access_where = _elgg_get_access_where_sql(array('table_alias' => 'te')); // We use LEFT JOIN with entities table but the WHERE clauses are used // regardless if a JOIN is successfully made. The "te.guid IS NULL" is // needed because of this. $query .= "{$object_access_where} AND ({$target_access_where} OR te.guid IS NULL) "; if (!$options['count']) { $options['group_by'] = sanitise_string($options['group_by']); if ($options['group_by']) { $query .= " GROUP BY {$options['group_by']}"; } $options['order_by'] = sanitise_string($options['order_by']); $query .= " ORDER BY {$options['order_by']}"; if ($options['limit']) { $limit = sanitise_int($options['limit']); $offset = sanitise_int($options['offset'], false); $query .= " LIMIT {$offset}, {$limit}"; } $river_items = get_data($query, '_elgg_row_to_elgg_river_item'); _elgg_prefetch_river_entities($river_items); return $river_items; } else { $total = get_data_row($query); return (int) $total->total; } }
/** * Get the river's access where clause * * @return string * @since 1.8.0 * @access private */ function elgg_river_get_access_sql() { // @todo deprecate? this is only used once in elgg_get_river return _elgg_get_access_where_sql(array('table_alias' => '', 'owner_guid_column' => 'rv.subject_guid', 'guid_column' => 'object_guid', 'access_id_column' => 'rv.access_id', 'use_enabled_clause' => false)); }
/** * Get popular tags and their frequencies * * Supports similar arguments as elgg_get_entities() * * @param array $options Array in format: * * threshold => INT minimum tag count * * tag_names => array() metadata tag names - must be registered tags * * limit => INT number of tags to return * * types => null|STR entity type (SQL: type = '$type') * * subtypes => null|STR entity subtype (SQL: subtype = '$subtype') * * type_subtype_pairs => null|ARR (array('type' => 'subtype')) * (SQL: type = '$type' AND subtype = '$subtype') pairs * * owner_guids => null|INT entity guid * * container_guids => null|INT container_guid * * site_guids => null (current_site)|INT site_guid * * created_time_lower => null|INT Created time lower boundary in epoch time * * created_time_upper => null|INT Created time upper boundary in epoch time * * modified_time_lower => null|INT Modified time lower boundary in epoch time * * modified_time_upper => null|INT Modified time upper boundary in epoch time * * wheres => array() Additional where clauses to AND together * * joins => array() Additional joins * * @return object[]|false If no tags or error, false * otherwise, array of objects with ->tag and ->total values * @since 1.7.1 */ function elgg_get_tags(array $options = array()) { global $CONFIG; $defaults = array('threshold' => 1, 'tag_names' => array(), 'limit' => 10, 'types' => ELGG_ENTITIES_ANY_VALUE, 'subtypes' => ELGG_ENTITIES_ANY_VALUE, 'type_subtype_pairs' => ELGG_ENTITIES_ANY_VALUE, 'owner_guids' => ELGG_ENTITIES_ANY_VALUE, 'container_guids' => ELGG_ENTITIES_ANY_VALUE, 'site_guids' => $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, 'joins' => array(), 'wheres' => array()); $options = array_merge($defaults, $options); $singulars = array('type', 'subtype', 'owner_guid', 'container_guid', 'site_guid', 'tag_name'); $options = _elgg_normalize_plural_options_array($options, $singulars); $registered_tags = elgg_get_registered_tag_metadata_names(); if (!is_array($options['tag_names'])) { return false; } // empty array so use all registered tag names if (count($options['tag_names']) == 0) { $options['tag_names'] = $registered_tags; } $diff = array_diff($options['tag_names'], $registered_tags); if (count($diff) > 0) { elgg_deprecated_notice('Tag metadata names must be registered by elgg_register_tag_metadata_name()', 1.7); // return false; } $wheres = $options['wheres']; // catch for tags that were spaces $wheres[] = "msv.string != ''"; $sanitised_tags = array(); foreach ($options['tag_names'] as $tag) { $sanitised_tags[] = '"' . sanitise_string($tag) . '"'; } $tags_in = implode(',', $sanitised_tags); $wheres[] = "(msn.string IN ({$tags_in}))"; $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.site_guid', $options['site_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_entity_time_where_sql('e', $options['created_time_upper'], $options['created_time_lower'], $options['modified_time_upper'], $options['modified_time_lower']); // 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]); } } // remove identical where clauses $wheres = array_unique($wheres); $joins = $options['joins']; $joins[] = "JOIN {$CONFIG->dbprefix}metadata md on md.entity_guid = e.guid"; $joins[] = "JOIN {$CONFIG->dbprefix}metastrings msv on msv.id = md.value_id"; $joins[] = "JOIN {$CONFIG->dbprefix}metastrings msn on md.name_id = msn.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]); } } $query = "SELECT msv.string as tag, count(msv.id) as total "; $query .= "FROM {$CONFIG->dbprefix}entities e "; // add joins foreach ($joins as $j) { $query .= " {$j} "; } // add wheres $query .= ' WHERE '; foreach ($wheres as $w) { $query .= " {$w} AND "; } // Add access controls $query .= _elgg_get_access_where_sql(); $threshold = sanitise_int($options['threshold']); $query .= " GROUP BY msv.string HAVING total >= {$threshold} "; $query .= " ORDER BY total DESC "; $limit = sanitise_int($options['limit']); $query .= " LIMIT {$limit} "; return get_data($query); }
* */ $user = elgg_extract("user", $vars, elgg_get_logged_in_user_entity()); $group = elgg_extract("group", $vars); $ts_lower = (int) elgg_extract("ts_lower", $vars); $ts_upper = (int) elgg_extract("ts_upper", $vars); $dbprefix = get_config("dbprefix"); $group_guid = $group->getGUID(); $offset = 0; $limit = 25; // retrieve recent group activity $sql = "SELECT r.*"; $sql .= " FROM " . $dbprefix . "river r"; $sql .= " INNER JOIN " . $dbprefix . "entities AS e ON r.object_guid = e.guid"; // river event -> object $sql .= " WHERE (e.container_guid = {$group_guid} OR r.object_guid = {$group_guid})"; // filter by group $sql .= " AND r.posted BETWEEN " . $ts_lower . " AND " . $ts_upper; // filter interval $sql .= " AND " . _elgg_get_access_where_sql(array("table_alias" => "e")); // filter access $sql .= " ORDER BY posted DESC"; $sql .= " LIMIT " . $offset . "," . $limit; $items = get_data($sql, "_elgg_row_to_elgg_river_item"); if (!empty($items)) { $title = elgg_view("output/url", array("text" => elgg_echo("groups:activity"), "href" => $group->getURL(), "is_trusted" => true)); $options = array("list_class" => "elgg-list-river elgg-river", "items" => $items, "pagination" => false); $content = elgg_view("page/components/list", $options); echo elgg_view_module("digest", $title, $content); } unset($items);
/** * Get entities with tags that match the search parameters. * * @param string $hook Hook name * @param string $type Hook type * @param array $value Empty array * @param array $params Search parameters * @return array */ function search_tags_hook($hook, $type, $value, $params) { $params['joins'] = (array) elgg_extract('joins', $params, array()); $params['wheres'] = (array) elgg_extract('wheres', $params, array()); $db_prefix = elgg_get_config('dbprefix'); $valid_tag_names = elgg_get_registered_tag_metadata_names(); // @todo will need to split this up to support searching multiple tags at once. $query = sanitise_string($params['query']); // if passed a tag metadata name, only search on that tag name. // tag_name isn't included in the params because it's specific to // tag searches. if ($tag_names = get_input('tag_names')) { if (is_array($tag_names)) { $search_tag_names = $tag_names; } else { $search_tag_names = array($tag_names); } // check these are valid to avoid arbitrary metadata searches. foreach ($search_tag_names as $i => $tag_name) { if (!in_array($tag_name, $valid_tag_names)) { unset($search_tag_names[$i]); } } } else { $search_tag_names = $valid_tag_names; } if (!$search_tag_names) { return array('entities' => array(), 'count' => $count); } // don't use elgg_get_entities_from_metadata() here because of // performance issues. since we don't care what matches at this point // use an IN clause to grab everything that matches at once and sort // out the matches later. $params['joins'][] = "JOIN {$db_prefix}metadata md on e.guid = md.entity_guid"; $params['joins'][] = "JOIN {$db_prefix}metastrings msn on md.name_id = msn.id"; $params['joins'][] = "JOIN {$db_prefix}metastrings msv on md.value_id = msv.id"; $access = _elgg_get_access_where_sql(array('table_alias' => 'md')); $sanitised_tags = array(); foreach ($search_tag_names as $tag) { $sanitised_tags[] = '"' . sanitise_string($tag) . '"'; } $tags_in = implode(',', $sanitised_tags); $params['wheres'][] = "(msn.string IN ({$tags_in}) AND msv.string = '{$query}' AND {$access})"; $params['count'] = TRUE; $count = elgg_get_entities($params); // no need to continue if nothing here. if (!$count) { return array('entities' => array(), 'count' => $count); } $params['count'] = FALSE; if (isset($params['sort']) || !isset($params['order_by'])) { $params['order_by'] = search_get_order_by_sql('e', null, $params['sort'], $params['order']); } $entities = elgg_get_entities($params); // add the volatile data for why these entities have been returned. foreach ($entities as $entity) { $matched_tags_strs = array(); // get tags for each tag name requested to find which ones matched. foreach ($search_tag_names as $tag_name) { $tags = $entity->getTags($tag_name); // @todo make one long tag string and run this through the highlight // function. This might be confusing as it could chop off // the tag labels. if (in_array(strtolower($query), array_map('strtolower', $tags))) { if (is_array($tags)) { $tag_name_str = elgg_echo("tag_names:{$tag_name}"); $matched_tags_strs[] = "{$tag_name_str}: " . implode(', ', $tags); } } } // different entities have different titles switch ($entity->type) { case 'site': case 'user': case 'group': $title_tmp = $entity->name; break; case 'object': $title_tmp = $entity->title; break; } // Nick told me my idea was dirty, so I'm hard coding the numbers. $title_tmp = strip_tags($title_tmp); if (elgg_strlen($title_tmp) > 297) { $title_str = elgg_substr($title_tmp, 0, 297) . '...'; } else { $title_str = $title_tmp; } $desc_tmp = strip_tags($entity->description); if (elgg_strlen($desc_tmp) > 297) { $desc_str = elgg_substr($desc_tmp, 0, 297) . '...'; } else { $desc_str = $desc_tmp; } $tags_str = implode('. ', $matched_tags_strs); $tags_str = search_get_highlighted_relevant_substrings($tags_str, $params['query'], 30, 300, true); $entity->setVolatileData('search_matched_title', $title_str); $entity->setVolatileData('search_matched_description', $desc_str); $entity->setVolatileData('search_matched_extra', $tags_str); } return array('entities' => $entities, 'count' => $count); }
/** * Can a user access an entity. * * @warning If a logged in user doesn't have access to an entity, the * core engine will not load that entity. * * @tip This is mostly useful for checking if a user other than the logged in * user has access to an entity that is currently loaded. * * @todo This function would be much more useful if we could pass the guid of the * entity to test access for. We need to be able to tell whether the entity exists * and whether the user has access to the entity. * * @param \ElggEntity $entity The entity to check access for. * @param \ElggUser $user Optionally user to check access for. Defaults to * logged in user (which is a useless default). * * @return bool */ function hasAccessToEntity($entity, $user = null) { // See #7159. Must not allow ignore access to affect query $ia = elgg_set_ignore_access(false); if (!isset($user)) { $access_bit = _elgg_get_access_where_sql(); } else { $access_bit = _elgg_get_access_where_sql(array('user_guid' => $user->getGUID())); } elgg_set_ignore_access($ia); $db = _elgg_services()->db; $prefix = $db->getTablePrefix(); $query = "SELECT guid from {$prefix}entities e WHERE e.guid = {$entity->guid}"; // Add access controls $query .= " AND " . $access_bit; if ($db->getData($query)) { return true; } else { return false; } }
$values_where .= ")"; } // excluded tags $excluded_values = string_to_tag_array($widget->excluded_tags); if ($excluded_values) { // and value_id not in $value_ids = array(); foreach ($excluded_values as $excluded_value) { $value_ids += elgg_get_metastring_id($excluded_value, false); } if (!empty($values_where)) { $values_where .= " AND "; } $values_where .= "e.guid NOT IN (SELECT DISTINCT entity_guid FROM " . $dbprefix . "metadata WHERE name_id IN (" . implode(",", $name_ids) . ") AND value_id IN (" . implode(",", $value_ids) . "))"; } $access = _elgg_get_access_where_sql(array("table_alias" => 'n_table')); 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})"; } $options = array("type" => "object", "subtypes" => $content_type, "limit" => $count, "full_view" => false, "pagination" => false, "joins" => $joins, "wheres" => $wheres); // owner_guids if (!empty($widget->owner_guids)) { if (!is_array($widget->owner_guids)) { $owner_guids = string_to_tag_array($widget->owner_guids); } else { $owner_guids = $widget->owner_guids; }
/** * Populate the cache from a set of entities * * @param int|array $guids Array of or single GUIDs * @return void */ public function populateFromEntities($guids) { if (empty($guids)) { return; } $access_key = $this->getAccessKey(); if (!is_array($guids)) { $guids = array($guids); } $guids = array_unique($guids); // could be useful at some point in future //$guids = $this->filterMetadataHeavyEntities($guids); $db_prefix = _elgg_services()->db->getTablePrefix(); $options = array('guids' => $guids, 'limit' => 0, 'callback' => false, 'distinct' => false, 'joins' => array("JOIN {$db_prefix}metastrings v ON n_table.value_id = v.id", "JOIN {$db_prefix}metastrings n ON n_table.name_id = n.id"), 'selects' => array('n.string AS name', 'v.string AS value'), 'order_by' => 'n_table.entity_guid, n_table.time_created ASC, n_table.id ASC', 'wheres' => array(_elgg_get_access_where_sql(array('table_alias' => 'n_table', 'guid_column' => 'entity_guid')))); $data = _elgg_services()->metadataTable->getAll($options); // make sure we show all entities as loaded foreach ($guids as $guid) { $this->values[$access_key][$guid] = null; } // build up metadata for each entity, save when GUID changes (or data ends) $last_guid = null; $metadata = array(); $last_row_idx = count($data) - 1; foreach ($data as $i => $row) { $name = $row->name; $value = $row->value_type === 'text' ? $row->value : (int) $row->value; $guid = $row->entity_guid; if ($guid !== $last_guid) { if ($last_guid) { $this->values[$access_key][$last_guid] = $metadata; } $metadata = array(); } if (isset($metadata[$name])) { $metadata[$name] = (array) $metadata[$name]; $metadata[$name][] = $value; } else { $metadata[$name] = $value; } if ($i == $last_row_idx) { $this->values[$access_key][$guid] = $metadata; } $last_guid = $guid; } }