Similar to {@link \Elgg\Database::getData()} but returns only the first row
matched. If a callback function $callback is specified, the row will be passed
as the only argument to $callback.
public getDataRow ( string $query, callable $callback = null, array $params = [] ) : mixed | ||
$query | string | The query to execute. |
$callback | callable | A callback function to apply to the row |
$params | array | Query params. E.g. [1, 'steve'] or [':id' => 1, ':name' => 'steve'] |
return | mixed | A single database result object or the result of the callback function. |
/** * {@inheritDoc} */ public function read($session_id) { $id = sanitize_string($session_id); $query = "SELECT * FROM {$this->db->getTablePrefix()}users_sessions WHERE session='{$id}'"; $result = $this->db->getDataRow($query); if ($result) { return (string) $result->data; } else { return false; } }
/** * Get the value of a datalist element. * * Plugin authors should use elgg_get_config() and pass null for the site GUID. * * @internal Datalists are stored in the datalist table. * * @tip Use datalists to store information common to a full installation. * * @param string $name The name of the datalist * @return string|null|false String if value exists, null if doesn't, false on error * @access private */ function get($name) { $name = trim($name); if (!$this->validateName($name)) { return false; } return $this->cache->get($name, function () use($name) { $escaped_name = $this->db->sanitizeString($name); $result = $this->db->getDataRow("SELECT * FROM {$this->table} WHERE name = '{$escaped_name}'"); return $result ? $result->value : null; }); }
/** * Get the value of a datalist element. * * Plugin authors should use elgg_get_config() and pass null for the site GUID. * * @internal Datalists are stored in the datalist table. * * @tip Use datalists to store information common to a full installation. * * @param string $name The name of the datalist * @return string|null|false String if value exists, null if doesn't, false on error * @access private */ function get($name) { $name = trim($name); // cannot store anything longer than 255 characters in db, so catch here if (elgg_strlen($name) > 255) { $this->logger->error("The name length for configuration variables cannot be greater than 255"); return false; } return $this->cache->get($name, function () use($name) { $escaped_name = $this->db->sanitizeString($name); $result = $this->db->getDataRow("SELECT * FROM {$this->table} WHERE name = '{$escaped_name}'"); return $result ? $result->value : null; }); }
/** * Gets a configuration value * * Plugin authors should use elgg_get_config(). * * @note Internal: These settings are stored in the dbprefix_config table and read * during system boot into $CONFIG. * * @param string $name The name of the config value * * @return mixed|null */ function get($name) { $name = trim($name); // check for deprecated values. // @todo might be a better spot to define this? $new_name = false; switch ($name) { case 'pluginspath': $new_name = 'plugins_path'; break; case 'sitename': $new_name = 'site_name'; break; } // @todo these haven't really been implemented in Elgg 1.8. Complete in 1.9. // show dep message if ($new_name) { // $msg = "Config value $name has been renamed as $new_name"; $name = $new_name; // elgg_deprecated_notice($msg, $dep_version); } // decide from where to return the value if (isset($this->CONFIG->{$name})) { return $this->CONFIG->{$name}; } $sql = "\n\t\t\tSELECT value\n\t\t\tFROM {$this->CONFIG->dbprefix}config\n\t\t\tWHERE name = :name\n\t\t"; $params[':name'] = $name; $result = $this->db->getDataRow($sql, null, $params); if ($result) { $result = unserialize($result->value); $this->CONFIG->{$name} = $result; return $result; } return null; }
/** * Check to see if a user has already created an annotation on an object * * @param int $entity_guid Entity guid * @param string $annotation_type Type of annotation * @param int $owner_guid Defaults to logged in user. * * @return bool */ function exists($entity_guid, $annotation_type, $owner_guid = null) { if (!$owner_guid && !($owner_guid = $this->session->getLoggedInUserGuid())) { return false; } $sql = "SELECT id FROM {$this->db->prefix}annotations\n\t\t\t\tWHERE owner_guid = :owner_guid\n\t\t\t\tAND entity_guid = :entity_guid\n\t\t\t\tAND name = :annotation_type"; $result = $this->db->getDataRow($sql, null, [':owner_guid' => (int) $owner_guid, ':entity_guid' => (int) $entity_guid, ':annotation_type' => $annotation_type]); return (bool) $result; }
/** * Check if a relationship exists between two entities. If so, the relationship object is returned. * * This function lets you ask "Is $guid_one a $relationship of $guid_two?" * * @param int $guid_one GUID of the subject entity of the relationship * @param string $relationship Type of the relationship * @param int $guid_two GUID of the target entity of the relationship * * @return \ElggRelationship|false Depending on success */ public function check($guid_one, $relationship, $guid_two) { $query = "\n\t\t\tSELECT * FROM {$this->db->prefix}entity_relationships\n\t\t\tWHERE guid_one = :guid1\n\t\t\t AND relationship = :relationship\n\t\t\t AND guid_two = :guid2\n\t\t\tLIMIT 1\n\t\t"; $params = [':guid1' => (int) $guid_one, ':guid2' => (int) $guid_two, ':relationship' => $relationship]; $row = $this->rowToElggRelationship($this->db->getDataRow($query, null, $params)); if ($row) { return $row; } return false; }
/** * Check if a relationship exists between two entities. If so, the relationship object is returned. * * This function lets you ask "Is $guid_one a $relationship of $guid_two?" * * @param int $guid_one GUID of the subject entity of the relationship * @param string $relationship Type of the relationship * @param int $guid_two GUID of the target entity of the relationship * * @return \ElggRelationship|false Depending on success */ public function check($guid_one, $relationship, $guid_two) { $guid_one = (int) $guid_one; $relationship = $this->db->sanitizeString($relationship); $guid_two = (int) $guid_two; $query = "\n\t\t\tSELECT * FROM {$this->db->getTablePrefix()}entity_relationships\n\t\t\tWHERE guid_one = {$guid_one}\n\t\t\t AND relationship = '{$relationship}'\n\t\t\t AND guid_two = {$guid_two}\n\t\t\tLIMIT 1\n\t\t"; $row = $this->rowToElggRelationship($this->db->getDataRow($query)); if ($row) { return $row; } return false; }
/** * Create a new metadata object, or update an existing one. * * Metadata can be an array by setting allow_multiple to true, but it is an * indexed array with no control over the indexing. * * @param int $entity_guid The entity to attach the metadata to * @param string $name Name of the metadata * @param string $value Value of the metadata * @param string $value_type 'text', 'integer', or '' for automatic detection * @param int $owner_guid GUID of entity that owns the metadata. Default is logged in user. * @param int $access_id Default is ACCESS_PRIVATE * @param bool $allow_multiple Allow multiple values for one key. Default is false * * @return int|false id of metadata or false if failure */ function create($entity_guid, $name, $value, $value_type = '', $owner_guid = 0, $access_id = ACCESS_PRIVATE, $allow_multiple = false) { $entity_guid = (int) $entity_guid; // name and value are encoded in add_metastring() $value_type = detect_extender_valuetype($value, $this->db->sanitizeString(trim($value_type))); $time = time(); $owner_guid = (int) $owner_guid; $allow_multiple = (bool) $allow_multiple; if (!isset($value)) { return false; } if ($owner_guid == 0) { $owner_guid = $this->session->getLoggedInUserGuid(); } $access_id = (int) $access_id; $query = "SELECT * from {$this->table}" . " WHERE entity_guid = {$entity_guid} and name_id=" . $this->metastringsTable->getId($name) . " limit 1"; $existing = $this->db->getDataRow($query); if ($existing && !$allow_multiple) { $id = (int) $existing->id; $result = $this->update($id, $name, $value, $value_type, $owner_guid, $access_id); if (!$result) { return false; } } else { // Support boolean types if (is_bool($value)) { $value = (int) $value; } // Add the metastrings $value_id = $this->metastringsTable->getId($value); if (!$value_id) { return false; } $name_id = $this->metastringsTable->getId($name); if (!$name_id) { return false; } // If ok then add it $query = "INSERT into {$this->table}" . " (entity_guid, name_id, value_id, value_type, owner_guid, time_created, access_id)" . " VALUES ({$entity_guid}, '{$name_id}','{$value_id}','{$value_type}', {$owner_guid}, {$time}, {$access_id})"; $id = $this->db->insertData($query); if ($id !== false) { $obj = $this->get($id); if ($this->events->trigger('create', 'metadata', $obj)) { $this->cache->save($entity_guid, $name, $value, $allow_multiple); return $id; } else { $this->delete($id); } } } return $id; }
/** * Gets a private setting for an entity * * Plugin authors can set private data on entities. By default private * data will not be searched or exported. * * @param int $entity_guid The entity GUID * @param string $name The name of the setting * * @return mixed The setting value, or null if does not exist */ public function get($entity_guid, $name) { $entity_guid = (int) $entity_guid; $name = $this->db->sanitizeString($name); $entity = $this->entities->get($entity_guid); if (!$entity instanceof \ElggEntity) { return null; } $query = "SELECT value FROM {$this->table}\n\t\t\twhere name = '{$name}' and entity_guid = {$entity_guid}"; $setting = $this->db->getDataRow($query); if ($setting) { return $setting->value; } return null; }
/** * Gets a private setting for an entity * * Plugin authors can set private data on entities. By default private * data will not be searched or exported. * * @param int $entity_guid The entity GUID * @param string $name The name of the setting * * @return mixed The setting value, or null if does not exist */ public function get($entity_guid, $name) { $values = $this->cache->getAll($entity_guid); if (isset($values[$name])) { return $values[$name]; } if (!$this->entities->exists($entity_guid)) { return false; } $query = "\n\t\t\tSELECT value FROM {$this->table}\n\t\t\tWHERE name = :name\n\t\t\tAND entity_guid = :entity_guid\n\t\t"; $params = [':entity_guid' => (int) $entity_guid, ':name' => (string) $name]; $setting = $this->db->getDataRow($query, null, $params); if ($setting) { return $setting->value; } return null; }
/** * Create a new metadata object, or update an existing one. * * Metadata can be an array by setting allow_multiple to true, but it is an * indexed array with no control over the indexing. * * @param int $entity_guid The entity to attach the metadata to * @param string $name Name of the metadata * @param string $value Value of the metadata * @param string $value_type 'text', 'integer', or '' for automatic detection * @param int $owner_guid GUID of entity that owns the metadata. Default is logged in user. * @param int $access_id Default is ACCESS_PRIVATE * @param bool $allow_multiple Allow multiple values for one key. Default is false * * @return int|false id of metadata or false if failure */ function create($entity_guid, $name, $value, $value_type = '', $owner_guid = 0, $access_id = ACCESS_PRIVATE, $allow_multiple = false) { $entity_guid = (int) $entity_guid; $value_type = detect_extender_valuetype($value, $this->db->sanitizeString(trim($value_type))); $owner_guid = (int) $owner_guid; $allow_multiple = (bool) $allow_multiple; if (!isset($value)) { return false; } if ($owner_guid == 0) { $owner_guid = $this->session->getLoggedInUserGuid(); } $access_id = (int) $access_id; $query = "SELECT * FROM {$this->table}\n\t\t\tWHERE entity_guid = :entity_guid and name = :name LIMIT 1"; $existing = $this->db->getDataRow($query, null, [':entity_guid' => $entity_guid, ':name' => $name]); if ($existing && !$allow_multiple) { $id = (int) $existing->id; $result = $this->update($id, $name, $value, $value_type, $owner_guid, $access_id); if (!$result) { return false; } } else { // Support boolean types if (is_bool($value)) { $value = (int) $value; } // If ok then add it $query = "INSERT INTO {$this->table}\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)"; $id = $this->db->insertData($query, [':entity_guid' => $entity_guid, ':name' => $name, ':value' => $value, ':value_type' => $value_type, ':owner_guid' => (int) $owner_guid, ':time_created' => $this->getCurrentTime()->getTimestamp(), ':access_id' => $access_id]); if ($id !== false) { $obj = $this->get($id); if ($this->events->trigger('create', 'metadata', $obj)) { $this->cache->clear($entity_guid); return $id; } else { $this->delete($id); } } } return $id; }
/** * Return the user specific details of a user by a row. * * @param int $guid The \ElggUser guid * * @return mixed * @access private */ public function getRow($guid) { $sql = "\n\t\t\tSELECT * FROM {$this->table}\n\t\t\tWHERE guid = :guid\n\t\t"; $params = [':guid' => $guid]; return $this->db->getDataRow($sql, null, $params); }
/** * {@inheritdoc} */ public function getDataRow($query, $callback = '', array $params = []) { return $this->db->getDataRow($query, $callback, $params); }
/** * Returns an array of entities with optional filtering. * * Entities are the basic unit of storage in Elgg. This function * provides the simplest way to get an array of entities. There * are many options available that can be passed to filter * what sorts of entities are returned. * * @tip To output formatted strings of entities, use {@link elgg_list_entities()} and * its cousins. * * @tip Plural arguments can be written as singular if only specifying a * single element. ('type' => 'object' vs 'types' => array('object')). * * @see elgg_get_entities_from_metadata() * @see elgg_get_entities_from_relationship() * @see elgg_get_entities_from_access_id() * @see elgg_get_entities_from_annotations() * @see elgg_list_entities() * * @param array $options Array in format: * * types => null|STR entity type (type IN ('type1', 'type2') * Joined with subtypes by AND. See below) * * subtypes => null|STR entity subtype (SQL: subtype IN ('subtype1', 'subtype2)) * Use ELGG_ENTITIES_NO_VALUE to match the default subtype. * Use ELGG_ENTITIES_ANY_VALUE to match any subtype. * * type_subtype_pairs => null|ARR (array('type' => 'subtype')) * array( * 'object' => array('blog', 'file'), // All objects with subtype of 'blog' or 'file' * 'user' => ELGG_ENTITY_ANY_VALUE, // All users irrespective of subtype * ); * * guids => null|ARR Array of entity guids * * owner_guids => null|ARR Array of owner guids * * container_guids => null|ARR Array of container_guids * * order_by => null (time_created desc)|STR SQL order by clause * * reverse_order_by => BOOL Reverse the default order by clause * * limit => null (10)|INT SQL limit clause (0 means no limit) * * offset => null (0)|INT SQL offset clause * * 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 * * count => true|false return a count instead of entities * * wheres => array() Additional where clauses to AND together * * joins => array() Additional joins * * preload_owners => bool (false) If set to true, this function will preload * all the owners of the returned entities resulting in better * performance if those owners need to be displayed * * preload_containers => bool (false) If set to true, this function will preload * all the containers of the returned entities resulting in better * performance if those containers need to be displayed * * * callback => string A callback function to pass each row through * * distinct => bool (true) 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. * * batch => bool (false) If set to true, an Elgg\BatchResult object will be returned instead of an array. * Since 2.3 * * batch_inc_offset => bool (true) If "batch" is used, this tells the batch to increment the offset * on each fetch. This must be set to false if you delete the batched results. * * batch_size => int (25) If "batch" is used, this is the number of entities/rows to pull in before * requesting more. * * @return \ElggEntity[]|int|mixed If count, int. Otherwise an array or an Elgg\BatchResult. false on errors. * * @see elgg_get_entities_from_metadata() * @see elgg_get_entities_from_relationship() * @see elgg_get_entities_from_access_id() * @see elgg_get_entities_from_annotations() * @see elgg_list_entities() */ public function getEntities(array $options = array()) { _elgg_check_unsupported_site_guid($options); $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, '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' => $this->config->get('default_limit'), 'offset' => 0, 'count' => false, 'selects' => array(), 'wheres' => array(), 'joins' => array(), 'preload_owners' => false, 'preload_containers' => false, 'callback' => 'entity_row_to_elggstar', 'distinct' => true, 'batch' => false, 'batch_inc_offset' => true, 'batch_size' => 25, '__ElggBatch' => null); $options = array_merge($defaults, $options); if ($options['batch'] && !$options['count']) { $batch_size = $options['batch_size']; $batch_inc_offset = $options['batch_inc_offset']; // clean batch keys from $options. unset($options['batch'], $options['batch_size'], $options['batch_inc_offset']); return new \ElggBatch([$this, 'getEntities'], $options, null, $batch_size, $batch_inc_offset); } // 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'); $options = _elgg_normalize_plural_options_array($options, $singulars); $options = $this->autoJoinTables($options); // evaluate where clauses if (!is_array($options['wheres'])) { $options['wheres'] = array($options['wheres']); } $wheres = $options['wheres']; $wheres[] = $this->getEntityTypeSubtypeWhereSql('e', $options['types'], $options['subtypes'], $options['type_subtype_pairs']); $wheres[] = $this->getGuidBasedWhereSql('e.guid', $options['guids']); $wheres[] = $this->getGuidBasedWhereSql('e.owner_guid', $options['owner_guids']); $wheres[] = $this->getGuidBasedWhereSql('e.container_guid', $options['container_guids']); $wheres[] = $this->getEntityTimeWhereSql('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 = $options['distinct'] ? "DISTINCT" : ""; $query = "SELECT {$distinct} e.*{$selects} FROM {$this->db->prefix}entities e "; } else { // note: when DISTINCT unneeded, it's slightly faster to compute COUNT(*) than GUIDs $count_expr = $options['distinct'] ? "DISTINCT e.guid" : "*"; $query = "SELECT COUNT({$count_expr}) as total FROM {$this->db->prefix}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']) { $total = $this->db->getDataRow($query); return (int) $total->total; } 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') { $results = $this->fetchFromSql($query, $options['__ElggBatch']); } else { $results = $this->db->getData($query, $options['callback']); } if (!$results) { // no results, no preloading return $results; } // populate entity and metadata caches, and prepare $entities for preloader $guids = array(); foreach ($results as $item) { // A custom callback could result in items that aren't \ElggEntity's, so check for them if ($item instanceof ElggEntity) { $this->entity_cache->set($item); // plugins usually have only settings if (!$item instanceof ElggPlugin) { $guids[] = $item->guid; } } } // @todo Without this, recursive delete fails. See #4568 reset($results); if ($guids) { // there were entities in the result set, preload metadata for them $this->metadata_cache->populateFromEntities($guids); } if (count($results) > 1) { $props_to_preload = []; if ($options['preload_owners']) { $props_to_preload[] = 'owner_guid'; } if ($options['preload_containers']) { $props_to_preload[] = 'container_guid'; } if ($props_to_preload) { // note, ElggEntityPreloaderIntegrationTest assumes it can swap out // the preloader after boot. If you inject this component at construction // time that unit test will break. :/ _elgg_services()->entityPreloader->preload($results, $props_to_preload); } } return $results; }