| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242 | 
							- <?php
 
- namespace Elgg\Database;
 
- use IncompleteEntityException;
 
- /**
 
-  * WARNING: API IN FLUX. DO NOT USE DIRECTLY.
 
-  *
 
-  * @access private
 
-  *
 
-  * @package    Elgg.Core
 
-  * @subpackage Database
 
-  * @since      1.10.0
 
-  */
 
- class EntityTable {
 
- 	/**
 
- 	 * Global Elgg configuration
 
- 	 * 
 
- 	 * @var \stdClass
 
- 	 */
 
- 	private $CONFIG;
 
- 	/**
 
- 	 * Constructor
 
- 	 */
 
- 	public function __construct() {
 
- 		global $CONFIG;
 
- 		$this->CONFIG = $CONFIG;
 
- 	}
 
- 	/**
 
- 	 * Returns a database row from the entities table.
 
- 	 *
 
- 	 * @tip Use get_entity() to return the fully loaded entity.
 
- 	 *
 
- 	 * @warning This will only return results if a) it exists, b) you have access to it.
 
- 	 * see {@link _elgg_get_access_where_sql()}.
 
- 	 *
 
- 	 * @param int $guid The GUID of the object to extract
 
- 	 *
 
- 	 * @return \stdClass|false
 
- 	 * @see entity_row_to_elggstar()
 
- 	 * @access private
 
- 	 */
 
- 	function getRow($guid) {
 
- 		
 
- 	
 
- 		if (!$guid) {
 
- 			return false;
 
- 		}
 
- 	
 
- 		$guid = (int) $guid;
 
- 		$access = _elgg_get_access_where_sql(array('table_alias' => ''));
 
- 	
 
- 		return _elgg_services()->db->getDataRow("SELECT * from {$this->CONFIG->dbprefix}entities where guid=$guid and $access");
 
- 	}
 
- 	
 
- 	/**
 
- 	 * Create an Elgg* object from a given entity row.
 
- 	 *
 
- 	 * Handles loading all tables into the correct class.
 
- 	 *
 
- 	 * @param \stdClass $row The row of the entry in the entities table.
 
- 	 *
 
- 	 * @return \ElggEntity|false
 
- 	 * @see get_entity_as_row()
 
- 	 * @see add_subtype()
 
- 	 * @see get_entity()
 
- 	 * @access private
 
- 	 *
 
- 	 * @throws \ClassException|\InstallationException
 
- 	 */
 
- 	function rowToElggStar($row) {
 
- 		if (!($row instanceof \stdClass)) {
 
- 			return $row;
 
- 		}
 
- 	
 
- 		if ((!isset($row->guid)) || (!isset($row->subtype))) {
 
- 			return $row;
 
- 		}
 
- 	
 
- 		$new_entity = false;
 
- 	
 
- 		// Create a memcache cache if we can
 
- 		static $newentity_cache;
 
- 		if ((!$newentity_cache) && (is_memcache_available())) {
 
- 			$newentity_cache = new \ElggMemcache('new_entity_cache');
 
- 		}
 
- 		if ($newentity_cache) {
 
- 			$new_entity = $newentity_cache->load($row->guid);
 
- 		}
 
- 		if ($new_entity) {
 
- 			return $new_entity;
 
- 		}
 
- 	
 
- 		// load class for entity if one is registered
 
- 		$classname = get_subtype_class_from_id($row->subtype);
 
- 		if ($classname != "") {
 
- 			if (class_exists($classname)) {
 
- 				$new_entity = new $classname($row);
 
- 	
 
- 				if (!($new_entity instanceof \ElggEntity)) {
 
- 					$msg = $classname . " is not a " . '\ElggEntity' . ".";
 
- 					throw new \ClassException($msg);
 
- 				}
 
- 			} else {
 
- 				error_log("Class '" . $classname . "' was not found, missing plugin?");
 
- 			}
 
- 		}
 
- 	
 
- 		if (!$new_entity) {
 
- 			//@todo Make this into a function
 
- 			switch ($row->type) {
 
- 				case 'object' :
 
- 					$new_entity = new \ElggObject($row);
 
- 					break;
 
- 				case 'user' :
 
- 					$new_entity = new \ElggUser($row);
 
- 					break;
 
- 				case 'group' :
 
- 					$new_entity = new \ElggGroup($row);
 
- 					break;
 
- 				case 'site' :
 
- 					$new_entity = new \ElggSite($row);
 
- 					break;
 
- 				default:
 
- 					$msg = "Entity type " . $row->type . " is not supported.";
 
- 					throw new \InstallationException($msg);
 
- 			}
 
- 		}
 
- 	
 
- 		// Cache entity if we have a cache available
 
- 		if (($newentity_cache) && ($new_entity)) {
 
- 			$newentity_cache->save($new_entity->guid, $new_entity);
 
- 		}
 
- 	
 
- 		return $new_entity;
 
- 	}
 
- 	
 
- 	/**
 
- 	 * Loads and returns an entity object from a guid.
 
- 	 *
 
- 	 * @param int    $guid The GUID of the entity
 
- 	 * @param string $type The type of the entity. If given, even an existing entity with the given GUID
 
- 	 *                     will not be returned unless its type matches.
 
- 	 *
 
- 	 * @return \ElggEntity The correct Elgg or custom object based upon entity type and subtype
 
- 	 */
 
- 	function get($guid, $type = '') {
 
- 		// We could also use: if (!(int) $guid) { return false },
 
- 		// but that evaluates to a false positive for $guid = true.
 
- 		// This is a bit slower, but more thorough.
 
- 		if (!is_numeric($guid) || $guid === 0 || $guid === '0') {
 
- 			return false;
 
- 		}
 
- 		
 
- 		// Check local cache first
 
- 		$new_entity = _elgg_retrieve_cached_entity($guid);
 
- 		if ($new_entity) {
 
- 			if ($type) {
 
- 				return elgg_instanceof($new_entity, $type) ? $new_entity : false;
 
- 			}
 
- 			return $new_entity;
 
- 		}
 
- 		$options = [
 
- 			'guid' => $guid,
 
- 			'limit' => 1,
 
- 			'site_guids' => ELGG_ENTITIES_ANY_VALUE, // for BC with get_entity, allow matching any site
 
- 		];
 
- 		if ($type) {
 
- 			$options['type'] = $type;
 
- 		}
 
- 		$entities = $this->getEntities($options);
 
- 		return $entities ? $entities[0] : false;
 
- 	}
 
- 	
 
- 	/**
 
- 	 * Does an entity exist?
 
- 	 *
 
- 	 * This function checks for the existence of an entity independent of access
 
- 	 * permissions. It is useful for situations when a user cannot access an entity
 
- 	 * and it must be determined whether entity has been deleted or the access level
 
- 	 * has changed.
 
- 	 *
 
- 	 * @param int $guid The GUID of the entity
 
- 	 *
 
- 	 * @return bool
 
- 	 */
 
- 	function exists($guid) {
 
- 		
 
- 	
 
- 		$guid = sanitize_int($guid);
 
- 	
 
- 		$query = "SELECT count(*) as total FROM {$this->CONFIG->dbprefix}entities WHERE guid = $guid";
 
- 		$result = _elgg_services()->db->getDataRow($query);
 
- 		if ($result->total == 0) {
 
- 			return false;
 
- 		} else {
 
- 			return true;
 
- 		}
 
- 	}
 
- 	
 
- 	/**
 
- 	 * Enable an entity.
 
- 	 *
 
- 	 * @param int  $guid      GUID of entity to enable
 
- 	 * @param bool $recursive Recursively enable all entities disabled with the entity?
 
- 	 *
 
- 	 * @return bool
 
- 	 */
 
- 	function enable($guid, $recursive = true) {
 
- 	
 
- 		// Override access only visible entities
 
- 		$old_access_status = access_get_show_hidden_status();
 
- 		access_show_hidden_entities(true);
 
- 	
 
- 		$result = false;
 
- 		$entity = get_entity($guid);
 
- 		if ($entity) {
 
- 			$result = $entity->enable($recursive);
 
- 		}
 
- 	
 
- 		access_show_hidden_entities($old_access_status);
 
- 		return $result;
 
- 	}
 
- 	
 
- 	/**
 
- 	 * 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')).
 
- 	 *
 
- 	 * @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
 
- 	 *
 
- 	 * 	site_guids => null (current_site)|ARR Array of site_guid
 
- 	 *
 
- 	 * 	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.
 
- 	 *
 
- 	 * @return mixed If count, int. If not count, array. 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()
 
- 	 */
 
- 	function getEntities(array $options = array()) {
 
- 		
 
- 	
 
- 		$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'			=>	$this->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'					=>	_elgg_services()->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,
 
- 	
 
- 			// private API
 
- 			'__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);
 
- 		$options = $this->autoJoinTables($options);
 
- 		// 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 = $options['distinct'] ? "DISTINCT" : "";
 
- 			$query = "SELECT $distinct e.*{$selects} FROM {$this->CONFIG->dbprefix}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->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']) {
 
- 			$total = _elgg_services()->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 = _elgg_fetch_entities_from_sql($query, $options['__ElggBatch']);
 
- 		} else {
 
- 			$results = _elgg_services()->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) {
 
- 				_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($results);
 
- 		if ($guids) {
 
- 			// there were entities in the result set, preload metadata for them
 
- 			_elgg_services()->metadataCache->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;
 
- 	}
 
- 	/**
 
- 	 * Decorate getEntities() options in order to auto-join secondary tables where it's
 
- 	 * safe to do so.
 
- 	 *
 
- 	 * @param array $options Options array in getEntities() after normalization
 
- 	 * @return array
 
- 	 */
 
- 	protected function autoJoinTables(array $options) {
 
- 		// we must be careful that the query doesn't specify any options that may join
 
- 		// tables or change the selected columns
 
- 		if (!is_array($options['types'])
 
- 				|| count($options['types']) !== 1
 
- 				|| !empty($options['selects'])
 
- 				|| !empty($options['wheres'])
 
- 				|| !empty($options['joins'])
 
- 				|| $options['callback'] !== 'entity_row_to_elggstar'
 
- 				|| $options['count']) {
 
- 			// Too dangerous to auto-join
 
- 			return $options;
 
- 		}
 
- 		$join_types = [
 
- 			// Each class must have a static getExternalAttributes() : array
 
- 			'object' => 'ElggObject',
 
- 			'user' => 'ElggUser',
 
- 			'group' => 'ElggGroup',
 
- 			'site' => 'ElggSite',
 
- 		];
 
- 		// We use reset() because $options['types'] may not have a numeric key
 
- 		$type = reset($options['types']);
 
- 		if (empty($join_types[$type])) {
 
- 			return $options;
 
- 		}
 
- 		// Get the columns we'll need to select. We can't use st.* because the order_by
 
- 		// clause may reference "guid", which MySQL will complain about being ambiguous
 
- 		if (!is_callable([$join_types[$type], 'getExternalAttributes'])) {
 
- 			// for some reason can't get external attributes.
 
- 			return $options;
 
- 		}
 
- 		$attributes = $join_types[$type]::getExternalAttributes();
 
- 		foreach (array_keys($attributes) as $col) {
 
- 			$options['selects'][] = "st.$col";
 
- 		}
 
- 		// join the secondary table
 
- 		$options['joins'][] = "JOIN {$this->CONFIG->dbprefix}{$type}s_entity st ON (e.guid = st.guid)";
 
- 		return $options;
 
- 	}
 
- 	
 
- 	/**
 
- 	 * Return entities from an SQL query generated by elgg_get_entities.
 
- 	 *
 
- 	 * @param string    $sql
 
- 	 * @param \ElggBatch $batch
 
- 	 * @return \ElggEntity[]
 
- 	 *
 
- 	 * @access private
 
- 	 * @throws \LogicException
 
- 	 */
 
- 	function fetchFromSql($sql, \ElggBatch $batch = null) {
 
- 		static $plugin_subtype;
 
- 		if (null === $plugin_subtype) {
 
- 			$plugin_subtype = get_subtype_id('object', 'plugin');
 
- 		}
 
- 	
 
- 		// Keys are types, values are columns that, if present, suggest that the secondary
 
- 		// table is already JOINed. Note it's OK if guess incorrectly because entity load()
 
- 		// will fetch any missing attributes.
 
- 		$types_to_optimize = array(
 
- 			'object' => 'title',
 
- 			'user' => 'password',
 
- 			'group' => 'name',
 
- 			'site' => 'url',
 
- 		);
 
- 	
 
- 		$rows = _elgg_services()->db->getData($sql);
 
- 	
 
- 		// guids to look up in each type
 
- 		$lookup_types = array();
 
- 		// maps GUIDs to the $rows key
 
- 		$guid_to_key = array();
 
- 	
 
- 		if (isset($rows[0]->type, $rows[0]->subtype)
 
- 				&& $rows[0]->type === 'object'
 
- 				&& $rows[0]->subtype == $plugin_subtype) {
 
- 			// Likely the entire resultset is plugins, which have already been optimized
 
- 			// to JOIN the secondary table. In this case we allow retrieving from cache,
 
- 			// but abandon the extra queries.
 
- 			$types_to_optimize = array();
 
- 		}
 
- 	
 
- 		// First pass: use cache where possible, gather GUIDs that we're optimizing
 
- 		foreach ($rows as $i => $row) {
 
- 			if (empty($row->guid) || empty($row->type)) {
 
- 				throw new \LogicException('Entity row missing guid or type');
 
- 			}
 
- 			$entity = _elgg_retrieve_cached_entity($row->guid);
 
- 			if ($entity) {
 
- 				$entity->refresh($row);
 
- 				$rows[$i] = $entity;
 
- 				continue;
 
- 			}
 
- 			if (isset($types_to_optimize[$row->type])) {
 
- 				// check if row already looks JOINed.
 
- 				if (isset($row->{$types_to_optimize[$row->type]})) {
 
- 					// Row probably already contains JOINed secondary table. Don't make another query just
 
- 					// to pull data that's already there
 
- 					continue;
 
- 				}
 
- 				$lookup_types[$row->type][] = $row->guid;
 
- 				$guid_to_key[$row->guid] = $i;
 
- 			}
 
- 		}
 
- 		// Do secondary queries and merge rows
 
- 		if ($lookup_types) {
 
- 			$dbprefix = _elgg_services()->config->get('dbprefix');
 
- 	
 
- 			foreach ($lookup_types as $type => $guids) {
 
- 				$set = "(" . implode(',', $guids) . ")";
 
- 				$sql = "SELECT * FROM {$dbprefix}{$type}s_entity WHERE guid IN $set";
 
- 				$secondary_rows = _elgg_services()->db->getData($sql);
 
- 				if ($secondary_rows) {
 
- 					foreach ($secondary_rows as $secondary_row) {
 
- 						$key = $guid_to_key[$secondary_row->guid];
 
- 						// cast to arrays to merge then cast back
 
- 						$rows[$key] = (object)array_merge((array)$rows[$key], (array)$secondary_row);
 
- 					}
 
- 				}
 
- 			}
 
- 		}
 
- 		// Second pass to finish conversion
 
- 		foreach ($rows as $i => $row) {
 
- 			if ($row instanceof \ElggEntity) {
 
- 				continue;
 
- 			} else {
 
- 				try {
 
- 					$rows[$i] = entity_row_to_elggstar($row);
 
- 				} catch (IncompleteEntityException $e) {
 
- 					// don't let incomplete entities throw fatal errors
 
- 					unset($rows[$i]);
 
- 	
 
- 					// report incompletes to the batch process that spawned this query
 
- 					if ($batch) {
 
- 						$batch->reportIncompleteEntity($row);
 
- 					}
 
- 				}
 
- 			}
 
- 		}
 
- 		return $rows;
 
- 	}
 
- 	
 
- 	/**
 
- 	 * Returns SQL where clause for type and subtype on main entity table
 
- 	 *
 
- 	 * @param string     $table    Entity table prefix as defined in SELECT...FROM entities $table
 
- 	 * @param null|array $types    Array of types or null if none.
 
- 	 * @param null|array $subtypes Array of subtypes or null if none
 
- 	 * @param null|array $pairs    Array of pairs of types and subtypes
 
- 	 *
 
- 	 * @return false|string
 
- 	 * @access private
 
- 	 */
 
- 	function getEntityTypeSubtypeWhereSql($table, $types, $subtypes, $pairs) {
 
- 		// subtype depends upon type.
 
- 		if ($subtypes && !$types) {
 
- 			_elgg_services()->logger->warn("Cannot set subtypes without type.");
 
- 			return false;
 
- 		}
 
- 	
 
- 		// short circuit if nothing is requested
 
- 		if (!$types && !$subtypes && !$pairs) {
 
- 			return '';
 
- 		}
 
- 	
 
- 		// these are the only valid types for entities in elgg
 
- 		$valid_types = _elgg_services()->config->get('entity_types');
 
- 	
 
- 		// pairs override
 
- 		$wheres = array();
 
- 		if (!is_array($pairs)) {
 
- 			if (!is_array($types)) {
 
- 				$types = array($types);
 
- 			}
 
- 	
 
- 			if ($subtypes && !is_array($subtypes)) {
 
- 				$subtypes = array($subtypes);
 
- 			}
 
- 	
 
- 			// decrementer for valid types.  Return false if no valid types
 
- 			$valid_types_count = count($types);
 
- 			$valid_subtypes_count = 0;
 
- 			// remove invalid types to get an accurate count of
 
- 			// valid types for the invalid subtype detection to use
 
- 			// below.
 
- 			// also grab the count of ALL subtypes on valid types to decrement later on
 
- 			// and check against.
 
- 			//
 
- 			// yes this is duplicating a foreach on $types.
 
- 			foreach ($types as $type) {
 
- 				if (!in_array($type, $valid_types)) {
 
- 					$valid_types_count--;
 
- 					unset($types[array_search($type, $types)]);
 
- 				} else {
 
- 					// do the checking (and decrementing) in the subtype section.
 
- 					$valid_subtypes_count += count($subtypes);
 
- 				}
 
- 			}
 
- 	
 
- 			// return false if nothing is valid.
 
- 			if (!$valid_types_count) {
 
- 				return false;
 
- 			}
 
- 	
 
- 			// subtypes are based upon types, so we need to look at each
 
- 			// type individually to get the right subtype id.
 
- 			foreach ($types as $type) {
 
- 				$subtype_ids = array();
 
- 				if ($subtypes) {
 
- 					foreach ($subtypes as $subtype) {
 
- 						// check that the subtype is valid
 
- 						if (!$subtype && ELGG_ENTITIES_NO_VALUE === $subtype) {
 
- 							// subtype value is 0
 
- 							$subtype_ids[] = ELGG_ENTITIES_NO_VALUE;
 
- 						} elseif (!$subtype) {
 
- 							// subtype is ignored.
 
- 							// this handles ELGG_ENTITIES_ANY_VALUE, '', and anything falsy that isn't 0
 
- 							continue;
 
- 						} else {
 
- 							$subtype_id = get_subtype_id($type, $subtype);
 
- 							
 
- 							if ($subtype_id) {
 
- 								$subtype_ids[] = $subtype_id;
 
- 							} else {
 
- 								$valid_subtypes_count--;
 
- 								_elgg_services()->logger->notice("Type-subtype '$type:$subtype' does not exist!");
 
- 								continue;
 
- 							}
 
- 						}
 
- 					}
 
- 	
 
- 					// return false if we're all invalid subtypes in the only valid type
 
- 					if ($valid_subtypes_count <= 0) {
 
- 						return false;
 
- 					}
 
- 				}
 
- 	
 
- 				if (is_array($subtype_ids) && count($subtype_ids)) {
 
- 					$subtype_ids_str = implode(',', $subtype_ids);
 
- 					$wheres[] = "({$table}.type = '$type' AND {$table}.subtype IN ($subtype_ids_str))";
 
- 				} else {
 
- 					$wheres[] = "({$table}.type = '$type')";
 
- 				}
 
- 			}
 
- 		} else {
 
- 			// using type/subtype pairs
 
- 			$valid_pairs_count = count($pairs);
 
- 			$valid_pairs_subtypes_count = 0;
 
- 	
 
- 			// same deal as above--we need to know how many valid types
 
- 			// and subtypes we have before hitting the subtype section.
 
- 			// also normalize the subtypes into arrays here.
 
- 			foreach ($pairs as $paired_type => $paired_subtypes) {
 
- 				if (!in_array($paired_type, $valid_types)) {
 
- 					$valid_pairs_count--;
 
- 					unset($pairs[array_search($paired_type, $pairs)]);
 
- 				} else {
 
- 					if ($paired_subtypes && !is_array($paired_subtypes)) {
 
- 						$pairs[$paired_type] = array($paired_subtypes);
 
- 					}
 
- 					$valid_pairs_subtypes_count += count($paired_subtypes);
 
- 				}
 
- 			}
 
- 	
 
- 			if ($valid_pairs_count <= 0) {
 
- 				return false;
 
- 			}
 
- 			foreach ($pairs as $paired_type => $paired_subtypes) {
 
- 				// this will always be an array because of line 2027, right?
 
- 				// no...some overly clever person can say pair => array('object' => null)
 
- 				if (is_array($paired_subtypes)) {
 
- 					$paired_subtype_ids = array();
 
- 					foreach ($paired_subtypes as $paired_subtype) {
 
- 						if (ELGG_ENTITIES_NO_VALUE === $paired_subtype
 
- 						|| ($paired_subtype_id = get_subtype_id($paired_type, $paired_subtype))) {
 
- 	
 
- 							$paired_subtype_ids[] = (ELGG_ENTITIES_NO_VALUE === $paired_subtype) ?
 
- 								ELGG_ENTITIES_NO_VALUE : $paired_subtype_id;
 
- 						} else {
 
- 							$valid_pairs_subtypes_count--;
 
- 							_elgg_services()->logger->notice("Type-subtype '$paired_type:$paired_subtype' does not exist!");
 
- 							// return false if we're all invalid subtypes in the only valid type
 
- 							continue;
 
- 						}
 
- 					}
 
- 	
 
- 					// return false if there are no valid subtypes.
 
- 					if ($valid_pairs_subtypes_count <= 0) {
 
- 						return false;
 
- 					}
 
- 	
 
- 	
 
- 					if ($paired_subtype_ids_str = implode(',', $paired_subtype_ids)) {
 
- 						$wheres[] = "({$table}.type = '$paired_type'"
 
- 							. " AND {$table}.subtype IN ($paired_subtype_ids_str))";
 
- 					}
 
- 				} else {
 
- 					$wheres[] = "({$table}.type = '$paired_type')";
 
- 				}
 
- 			}
 
- 		}
 
- 	
 
- 		// pairs override the above.  return false if they don't exist.
 
- 		if (is_array($wheres) && count($wheres)) {
 
- 			$where = implode(' OR ', $wheres);
 
- 			return "($where)";
 
- 		}
 
- 	
 
- 		return '';
 
- 	}
 
- 	
 
- 	/**
 
- 	 * Returns SQL where clause for owner and containers.
 
- 	 *
 
- 	 * @param string     $column Column name the guids should be checked against. Usually
 
- 	 *                           best to provide in table.column format.
 
- 	 * @param null|array $guids  Array of GUIDs.
 
- 	 *
 
- 	 * @return false|string
 
- 	 * @access private
 
- 	 */
 
- 	function getGuidBasedWhereSql($column, $guids) {
 
- 		// short circuit if nothing requested
 
- 		// 0 is a valid guid
 
- 		if (!$guids && $guids !== 0) {
 
- 			return '';
 
- 		}
 
- 	
 
- 		// normalize and sanitise owners
 
- 		if (!is_array($guids)) {
 
- 			$guids = array($guids);
 
- 		}
 
- 	
 
- 		$guids_sanitized = array();
 
- 		foreach ($guids as $guid) {
 
- 			if ($guid !== ELGG_ENTITIES_NO_VALUE) {
 
- 				$guid = sanitise_int($guid);
 
- 	
 
- 				if (!$guid) {
 
- 					return false;
 
- 				}
 
- 			}
 
- 			$guids_sanitized[] = $guid;
 
- 		}
 
- 	
 
- 		$where = '';
 
- 		$guid_str = implode(',', $guids_sanitized);
 
- 	
 
- 		// implode(',', 0) returns 0.
 
- 		if ($guid_str !== false && $guid_str !== '') {
 
- 			$where = "($column IN ($guid_str))";
 
- 		}
 
- 	
 
- 		return $where;
 
- 	}
 
- 	
 
- 	/**
 
- 	 * Returns SQL where clause for entity time limits.
 
- 	 *
 
- 	 * @param string   $table              Entity table prefix as defined in
 
- 	 *                                     SELECT...FROM entities $table
 
- 	 * @param null|int $time_created_upper Time created upper limit
 
- 	 * @param null|int $time_created_lower Time created lower limit
 
- 	 * @param null|int $time_updated_upper Time updated upper limit
 
- 	 * @param null|int $time_updated_lower Time updated lower limit
 
- 	 *
 
- 	 * @return false|string false on fail, string on success.
 
- 	 * @access private
 
- 	 */
 
- 	function getEntityTimeWhereSql($table, $time_created_upper = null,
 
- 	$time_created_lower = null, $time_updated_upper = null, $time_updated_lower = null) {
 
- 	
 
- 		$wheres = array();
 
- 	
 
- 		// exploit PHP's loose typing (quack) to check that they are INTs and not str cast to 0
 
- 		if ($time_created_upper && $time_created_upper == sanitise_int($time_created_upper)) {
 
- 			$wheres[] = "{$table}.time_created <= $time_created_upper";
 
- 		}
 
- 	
 
- 		if ($time_created_lower && $time_created_lower == sanitise_int($time_created_lower)) {
 
- 			$wheres[] = "{$table}.time_created >= $time_created_lower";
 
- 		}
 
- 	
 
- 		if ($time_updated_upper && $time_updated_upper == sanitise_int($time_updated_upper)) {
 
- 			$wheres[] = "{$table}.time_updated <= $time_updated_upper";
 
- 		}
 
- 	
 
- 		if ($time_updated_lower && $time_updated_lower == sanitise_int($time_updated_lower)) {
 
- 			$wheres[] = "{$table}.time_updated >= $time_updated_lower";
 
- 		}
 
- 	
 
- 		if (is_array($wheres) && count($wheres) > 0) {
 
- 			$where_str = implode(' AND ', $wheres);
 
- 			return "($where_str)";
 
- 		}
 
- 	
 
- 		return '';
 
- 	}
 
- 	
 
- 	/**
 
- 	 * Gets entities based upon attributes in secondary tables.
 
- 	 * Also accepts all options available to elgg_get_entities(),
 
- 	 * elgg_get_entities_from_metadata(), and elgg_get_entities_from_relationship().
 
- 	 *
 
- 	 * @warning requires that the entity type be specified and there can only be one
 
- 	 * type.
 
- 	 *
 
- 	 * @see elgg_get_entities
 
- 	 * @see elgg_get_entities_from_metadata
 
- 	 * @see elgg_get_entities_from_relationship
 
- 	 *
 
- 	 * @param array $options Array in format:
 
- 	 *
 
- 	 * 	attribute_name_value_pairs => ARR (
 
- 	 *                                   'name' => 'name',
 
- 	 *                                   'value' => 'value',
 
- 	 *                                   'operand' => '=', (optional)
 
- 	 *                                   'case_sensitive' => false (optional)
 
- 	 *                                  )
 
- 	 * 	                             If multiple values are sent via
 
- 	 *                               an array ('value' => array('value1', 'value2')
 
- 	 *                               the pair's operand will be forced to "IN".
 
- 	 *
 
- 	 * 	attribute_name_value_pairs_operator => null|STR The operator to use for combining
 
- 	 *                                        (name = value) OPERATOR (name = value); default is AND
 
- 	 *
 
- 	 * @return \ElggEntity[]|mixed If count, int. If not count, array. false on errors.
 
- 	 * @throws InvalidArgumentException
 
- 	 * @todo Does not support ordering by attributes or using an attribute pair shortcut like this ('title' => 'foo')
 
- 	 */
 
- 	function getEntitiesFromAttributes(array $options = array()) {
 
- 		$defaults = array(
 
- 			'attribute_name_value_pairs' => ELGG_ENTITIES_ANY_VALUE,
 
- 			'attribute_name_value_pairs_operator' => 'AND',
 
- 		);
 
- 	
 
- 		$options = array_merge($defaults, $options);
 
- 	
 
- 		$singulars = array('type', 'attribute_name_value_pair');
 
- 		$options = _elgg_normalize_plural_options_array($options, $singulars);
 
- 	
 
- 		$clauses = _elgg_get_entity_attribute_where_sql($options);
 
- 	
 
- 		if ($clauses) {
 
- 			// merge wheres to pass to elgg_get_entities()
 
- 			if (isset($options['wheres']) && !is_array($options['wheres'])) {
 
- 				$options['wheres'] = array($options['wheres']);
 
- 			} elseif (!isset($options['wheres'])) {
 
- 				$options['wheres'] = array();
 
- 			}
 
- 	
 
- 			$options['wheres'] = array_merge($options['wheres'], $clauses['wheres']);
 
- 	
 
- 			// merge joins to pass to elgg_get_entities()
 
- 			if (isset($options['joins']) && !is_array($options['joins'])) {
 
- 				$options['joins'] = array($options['joins']);
 
- 			} elseif (!isset($options['joins'])) {
 
- 				$options['joins'] = array();
 
- 			}
 
- 	
 
- 			$options['joins'] = array_merge($options['joins'], $clauses['joins']);
 
- 		}
 
- 	
 
- 		return elgg_get_entities_from_relationship($options);
 
- 	}
 
- 	
 
- 	/**
 
- 	 * Get the join and where clauses for working with entity attributes
 
- 	 *
 
- 	 * @return false|array False on fail, array('joins', 'wheres')
 
- 	 * @access private
 
- 	 * @throws InvalidArgumentException
 
- 	 */
 
- 	function getEntityAttributeWhereSql(array $options = array()) {
 
- 	
 
- 		if (!isset($options['types'])) {
 
- 			throw new \InvalidArgumentException("The entity type must be defined for elgg_get_entities_from_attributes()");
 
- 		}
 
- 	
 
- 		if (is_array($options['types']) && count($options['types']) !== 1) {
 
- 			throw new \InvalidArgumentException("Only one type can be passed to elgg_get_entities_from_attributes()");
 
- 		}
 
- 	
 
- 		// type can be passed as string or array
 
- 		$type = $options['types'];
 
- 		if (is_array($type)) {
 
- 			$type = $type[0];
 
- 		}
 
- 	
 
- 		// @todo the types should be defined somewhere (as constant on \ElggEntity?)
 
- 		if (!in_array($type, array('group', 'object', 'site', 'user'))) {
 
- 			throw new \InvalidArgumentException("Invalid type '$type' passed to elgg_get_entities_from_attributes()");
 
- 		}
 
- 	
 
- 		
 
- 		$type_table = "{$this->CONFIG->dbprefix}{$type}s_entity";
 
- 	
 
- 		$return = array(
 
- 			'joins' => array(),
 
- 			'wheres' => array(),
 
- 		);
 
- 	
 
- 		// short circuit if nothing requested
 
- 		if ($options['attribute_name_value_pairs'] == ELGG_ENTITIES_ANY_VALUE) {
 
- 			return $return;
 
- 		}
 
- 	
 
- 		if (!is_array($options['attribute_name_value_pairs'])) {
 
- 			throw new \InvalidArgumentException("attribute_name_value_pairs must be an array for elgg_get_entities_from_attributes()");
 
- 		}
 
- 	
 
- 		$wheres = array();
 
- 	
 
- 		// check if this is an array of pairs or just a single pair.
 
- 		$pairs = $options['attribute_name_value_pairs'];
 
- 		if (isset($pairs['name']) || isset($pairs['value'])) {
 
- 			$pairs = array($pairs);
 
- 		}
 
- 	
 
- 		$pair_wheres = array();
 
- 		foreach ($pairs as $index => $pair) {
 
- 			// must have at least a name and value
 
- 			if (!isset($pair['name']) || !isset($pair['value'])) {
 
- 				continue;
 
- 			}
 
- 	
 
- 			if (isset($pair['operand'])) {
 
- 				$operand = sanitize_string($pair['operand']);
 
- 			} else {
 
- 				$operand = '=';
 
- 			}
 
- 	
 
- 			if (is_numeric($pair['value'])) {
 
- 				$value = sanitize_string($pair['value']);
 
- 			} else if (is_array($pair['value'])) {
 
- 				$values_array = array();
 
- 				foreach ($pair['value'] as $pair_value) {
 
- 					if (is_numeric($pair_value)) {
 
- 						$values_array[] = sanitize_string($pair_value);
 
- 					} else {
 
- 						$values_array[] = "'" . sanitize_string($pair_value) . "'";
 
- 					}
 
- 				}
 
- 	
 
- 				$operand = 'IN';
 
- 				if ($values_array) {
 
- 					$value = '(' . implode(', ', $values_array) . ')';
 
- 				}
 
- 	
 
- 			} else {
 
- 				$value = "'" . sanitize_string($pair['value']) . "'";
 
- 			}
 
- 	
 
- 			$name = sanitize_string($pair['name']);
 
- 	
 
- 			// case sensitivity can be specified per pair
 
- 			$pair_binary = '';
 
- 			if (isset($pair['case_sensitive'])) {
 
- 				$pair_binary = ($pair['case_sensitive']) ? 'BINARY ' : '';
 
- 			}
 
- 	
 
- 			$pair_wheres[] = "({$pair_binary}type_table.$name $operand $value)";
 
- 		}
 
- 	
 
- 		if ($where = implode(" {$options['attribute_name_value_pairs_operator']} ", $pair_wheres)) {
 
- 			$return['wheres'][] = "($where)";
 
- 	
 
- 			$return['joins'][] = "JOIN $type_table type_table ON e.guid = type_table.guid";
 
- 		}
 
- 	
 
- 		return $return;
 
- 	}
 
- 	
 
- 	/**
 
- 	 * 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
 
- 			FROM {$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;
 
- 	}
 
- 	
 
- 	/**
 
- 	 * Update the last_action column in the entities table for $guid.
 
- 	 *
 
- 	 * @warning This is different to time_updated.  Time_updated is automatically set,
 
- 	 * while last_action is only set when explicitly called.
 
- 	 *
 
- 	 * @param int $guid   Entity annotation|relationship action carried out on
 
- 	 * @param int $posted Timestamp of last action
 
- 	 *
 
- 	 * @return bool
 
- 	 * @access private
 
- 	 */
 
- 	function updateLastAction($guid, $posted = null) {
 
- 		
 
- 		$guid = (int)$guid;
 
- 		$posted = (int)$posted;
 
- 	
 
- 		if (!$posted) {
 
- 			$posted = time();
 
- 		}
 
- 	
 
- 		if ($guid) {
 
- 			//now add to the river updated table
 
- 			$query = "UPDATE {$this->CONFIG->dbprefix}entities SET last_action = {$posted} WHERE guid = {$guid}";
 
- 			$result = _elgg_services()->db->updateData($query);
 
- 			if ($result) {
 
- 				return true;
 
- 			} else {
 
- 				return false;
 
- 			}
 
- 		} else {
 
- 			return false;
 
- 		}
 
- 	}
 
- }
 
 
  |