diff options
Diffstat (limited to 'engine/lib/river.php')
| -rw-r--r-- | engine/lib/river.php | 1125 |
1 files changed, 689 insertions, 436 deletions
diff --git a/engine/lib/river.php b/engine/lib/river.php index 39be91d0d..e92040eb7 100644 --- a/engine/lib/river.php +++ b/engine/lib/river.php @@ -1,450 +1,703 @@ <?php - /** - * Elgg river. - * Functions for listening for and generating the river out of the system log. - * - * @package Elgg - * @subpackage Core - * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html GNU Public License version 2 - * @author Curverider Ltd - * @copyright Curverider Ltd 2008 - * @link http://elgg.org/ - */ - - /** - * @class ElggRiverComponent Component passed to river views. - * This class represents all the necessary information for constructing a river article - this includes: - * - The user who performed the action - * - The object the action was performed on - * - The event performed - * - Any related objects - * - * @author Curverider Ltd - */ - class ElggRiverStatement - { - /** - * Object in question (may be a relationship event or a metadata event). In the case of a relationship this is an array containing - * the objects that the relationship is established between. in the case of metadata it consists of - */ - private $object; - - /** - * The log event (create / update etc). - */ - private $log_event; - - /** - * The subject who created this event (the user). - */ - private $subject; +/** + * Elgg river. + * Activity stream functions. + * + * @package Elgg.Core + * @subpackage SocialModel.River + */ + +/** + * Adds an item to the river. + * + * @param string $view The view that will handle the river item (must exist) + * @param string $action_type An arbitrary string to define the action (eg 'comment', 'create') + * @param int $subject_guid The GUID of the entity doing the action + * @param int $object_guid The GUID of the entity being acted upon + * @param int $access_id The access ID of the river item (default: same as the object) + * @param int $posted The UNIX epoch timestamp of the river item (default: now) + * @param int $annotation_id The annotation ID associated with this river entry + * + * @return int/bool River ID or false on failure + */ +function add_to_river($view, $action_type, $subject_guid, $object_guid, $access_id = "", +$posted = 0, $annotation_id = 0) { + + global $CONFIG; + + // use default viewtype for when called from web services api + if (!elgg_view_exists($view, 'default')) { + return false; + } + if (!($subject = get_entity($subject_guid))) { + return false; + } + if (!($object = get_entity($object_guid))) { + return false; + } + if (empty($action_type)) { + return false; + } + if ($posted == 0) { + $posted = time(); + } + if ($access_id === "") { + $access_id = $object->access_id; + } + $type = $object->getType(); + $subtype = $object->getSubtype(); + + $view = sanitise_string($view); + $action_type = sanitise_string($action_type); + $subject_guid = sanitise_int($subject_guid); + $object_guid = sanitise_int($object_guid); + $access_id = sanitise_int($access_id); + $posted = sanitise_int($posted); + $annotation_id = sanitise_int($annotation_id); + + $values = array( + 'type' => $type, + 'subtype' => $subtype, + 'action_type' => $action_type, + 'access_id' => $access_id, + 'view' => $view, + 'subject_guid' => $subject_guid, + 'object_guid' => $object_guid, + 'annotation_id' => $annotation_id, + 'posted' => $posted, + ); + + // return false to stop insert + $values = elgg_trigger_plugin_hook('creating', 'river', null, $values); + if ($values == false) { + // inserting did not fail - it was just prevented + return true; + } + + extract($values); + + // Attempt to save river item; return success status + $id = insert_data("insert into {$CONFIG->dbprefix}river " . + " set type = '$type', " . + " subtype = '$subtype', " . + " action_type = '$action_type', " . + " access_id = $access_id, " . + " view = '$view', " . + " subject_guid = $subject_guid, " . + " object_guid = $object_guid, " . + " annotation_id = $annotation_id, " . + " posted = $posted"); + + // update the entities which had the action carried out on it + // @todo shouldn't this be down elsewhere? Like when an annotation is saved? + if ($id) { + update_entity_last_action($object_guid, $posted); - /** - * Create the statement. - * - * @param ElggUser $subject The subject (the user who created this) - * @param string $event The event. - * @param mixed $object The object, either an ElggEntity or an associated array - * ('subject' => ElggEntity, 'relationship' => relationship, 'object' => ElggEntity) or - * ('subject' => ElggEntity, 'object' => ElggEntity) - */ - public function __construct(ElggUser $subject, $event, $object) - { - $this->setSubject($subject); - $this->setEvent($event); - $this->setObject($object); + $river_items = elgg_get_river(array('id' => $id)); + if ($river_items) { + elgg_trigger_event('created', 'river', $river_items[0]); } - - /** - * Set the subject. - * - * @param ElggEntity $subject The subject. - */ - public function setSubject(ElggEntity $subject) { $this->subject = $subject; } - - /** - * Return the user that created this event - the subject of the statement. - * @return ElggUser - */ - public function getSubject() { return $this->subject; } - - /** - * Return the user who initiated this event (an alias of getSubject(); - * @return ElggUser - */ - public function getByUser() { return $this->getSubject(); } - - /** - * Set the object. - * - * @param mixed $object ElggEntity or array. - * @return bool - */ - public function setObject($object) - { - if (is_array($object)) - { - /*if ( - (!isset($object['subject'])) || - ( - (!($object['subject'] instanceof ElggEntity)) || - (!($object['subject'] instanceof ElggExtender)) - ) - ) - return false; - - if ( (!isset($object['object'])) || (!($object['object'] instanceof ElggEntity)) ) - return false; - */ - $this->object = $object; - - return true; - } - else if ($object instanceof ElggEntity) - { - $this->object = $object; - - return true; - } - - return false; + return $id; + } else { + return false; + } +} + +/** + * Delete river items + * + * @warning not checking access (should we?) + * + * @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) + * annotation_ids => INT|ARR The identifier of the annotation(s) + * action_types => STR|ARR The river action type(s) identifier + * views => STR|ARR River view(s) + * + * 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 + * + * posted_time_lower => INT The lower bound on the time posted + * posted_time_upper => INT The upper bound on the time posted + * + * @return bool + * @since 1.8.0 + */ +function elgg_delete_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, + 'annotation_ids' => ELGG_ENTITIES_ANY_VALUE, + + 'views' => ELGG_ENTITIES_ANY_VALUE, + 'action_types' => ELGG_ENTITIES_ANY_VALUE, + + '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, + + 'wheres' => array(), + 'joins' => array(), + + ); + + $options = array_merge($defaults, $options); + + $singulars = array('id', 'subject_guid', 'object_guid', 'annotation_id', 'action_type', 'view', 'type', 'subtype'); + $options = elgg_normalise_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.annotation_id', $options['annotation_ids']); + $wheres[] = elgg_river_get_action_where_sql($options['action_types']); + $wheres[] = elgg_river_get_view_where_sql($options['views']); + $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']}"; + } + + // 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]); } - - /** - * Return the accusitive object of the statement. This is either an object in isolation, or an array containing - * the parts of the statement. - * - * E.g. - * - * For the statement "User X created object Y", this function will return object Y. - * - * However, for a statement "User X is now friends with User Y" you are essentially making the system level statement - * "User X has created a relationship of type friend between Y and Z" (where X is almost always going to be the same as Y).. therefore - * this function will return a three element array associative containing the relationship type, plus the elements the relationship - * is between ['subject', 'relationship', 'object']. - * - * Also, if you are updating a bit of metadata about an object this a two element array: ['subject', 'object']. - * Which is making the statement "User X updated some Metadata (subject) about object (object) Y - * - * @return mixed - */ - public function getObject() { return $this->object; } - - /** - * Set the log event. - * - * @param string $event The event - e.g. "update". - */ - public function setEvent($event) { $this->log_event = $event; } - - /** - * Return the event in the system log that this action relates to (eg, "create", "update"). - * @return string - */ - public function getEvent() { return $this->log_event; } - } - - /** - * Extract a list of river events from the current system log. - * This function retrieves the objects from the system log and will attempt to render - * the view "river/CLASSNAME/EVENT" where CLASSNAME is the class of the object the system event is referring to, - * and EVENT is the event (create, update, delete etc). - * - * This view will be passed the log entry (as 'log_entry') and the object (as 'object') which will be accessable - * through the $vars[] array. - * - * It returns an array of the result of each of these views. - * - * \TODO: Limit to just one user or just one user's friends - * \TODO: Make this more efficient / reduce DB queries. - * - * @param int $by_user The user who initiated the event. - * @param string $relationship Limit return results to only those users who $by_user has $relationship with. - * @param int $limit Maximum number of events to show - * @param int $offset An offset - * @return array of river entities rendered with the appropriate view. - */ - function get_river_entries($by_user = "", $relationship = "", $limit = 10, $offset = 0) - { - // set start limit and offset - $cnt = $limit; // Didn' cast to int here deliberately - $off = $offset; // here too
-
- if (is_array($by_user) && sizeof($by_user) > 0) {
- foreach($by_user as $key => $val) {
- $by_user[$key] = (int) $val;
- }
- } else {
- $by_user = (int)$by_user;
- }
-
- $exit = false; - - // River objects - $river = array(); + } + + // remove identical where clauses + $wheres = array_unique($wheres); + + $query = "DELETE rv.* FROM {$CONFIG->dbprefix}river rv "; + + // remove identical join clauses + $joins = array_unique($options['joins']); - do - { - $log_events = get_system_log($by_user, "","", $cnt, $off); - - if (!$log_events) - $exit = true; - else - { - - foreach ($log_events as $log) - { - // See if we have access to the object we're talking about - $event = $log->event; - $class = $log->object_class; - $tmp = new $class(); - $object = $tmp->getObjectFromID($log->object_id); - - // Exists and we have access to it - // if (is_a($object, $class))
- if ($object instanceof $class) - { - // If no relationship defined or it matches $relationship - if ( - (!$relationship) || - ( - ($relationship) && - (check_entity_relationship($by_user, $relationship, $tmp->getObjectOwnerGUID())) - ) - ) - { - // See if anything can handle it - $tam = ""; - - // Construct the statement - $by_user_obj = get_entity($log->performed_by_guid); - $statement_object = $object; - if ($object instanceof ElggRelationship) { - - $statement_object = array( - 'subject' => get_entity($object->guid_one), - 'relationship' => $object->relationship, - 'object' => get_entity($object->guid_two) - ); - } else if ($object instanceof ElggExtender) { - $statement_object = array( - 'subject' => $object, - 'object' => get_entity($object->entity_guid) - ); - } - $statement = new ElggRiverStatement($by_user_obj, $event, $statement_object); -
-
- if ($object instanceof ElggEntity) {
- $subtype = $object->getSubtype();
- } else {
- $subtype = "";
- }
- if ($subtype == "widget") {
- $subtype = "widget/" . $object->handler;
- }
-
- if (!empty($subtype) && elgg_view_exists("river/{$subtype}/{$event}")) {
- $tam = elgg_view("river/{$subtype}/$event", array( - 'statement' => $statement
- ));
- } else if (elgg_view_exists("river/$class/$event")) { - $tam = elgg_view("river/$class/$event", array( - 'statement' => $statement - ));
- }
-
- if (!empty($tam)) {
- $tam = elgg_view("river/wrapper",array(
- 'entry' => $tam, - 'time' => $log->time_created, - 'event' => $event, - 'statement' => $statement - ));
- } - - if ($tam) - { - $river[] = $tam; - $cnt--; - } - } - } - - // Increase offset - $off++; - } - } - - } while ( - ($cnt > 0) && - (!$exit) - ); - - return $river; + // add joins + foreach ($joins as $j) { + $query .= " $j "; + } + + // add wheres + $query .= ' WHERE '; + + foreach ($wheres as $w) { + $query .= " $w AND "; + } + $query .= "1=1"; + + return delete_data($query); +} + +/** + * 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) + * 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 + * + * @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, + '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, + + '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', 'annotation_id', 'action_type', 'type', 'subtype'); + $options = elgg_normalise_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.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']}"; + } + + $joins = $options['joins']; + + 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']) { + $query = "SELECT DISTINCT rv.* FROM {$CONFIG->dbprefix}river rv "; + } else { + $query = "SELECT count(DISTINCT rv.id) 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 "; + } + + $query .= elgg_river_get_access_sql(); + + 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; + } +} + +/** + * Prefetch entities that will be displayed in the river. + * + * @param ElggRiverItem[] $river_items + * @access private + */ +function _elgg_prefetch_river_entities(array $river_items) { + // prefetch objects and subjects + $guids = array(); + foreach ($river_items as $item) { + if ($item->subject_guid && !_elgg_retrieve_cached_entity($item->subject_guid)) { + $guids[$item->subject_guid] = true; + } + if ($item->object_guid && !_elgg_retrieve_cached_entity($item->object_guid)) { + $guids[$item->object_guid] = true; + } + } + if ($guids) { + // avoid creating oversized query + // @todo how to better handle this? + $guids = array_slice($guids, 0, 300, true); + // return value unneeded, just priming cache + elgg_get_entities(array( + 'guids' => array_keys($guids), + 'limit' => 0, + )); + } + + // prefetch object containers + $guids = array(); + foreach ($river_items as $item) { + $object = $item->getObjectEntity(); + if ($object->container_guid && !_elgg_retrieve_cached_entity($object->container_guid)) { + $guids[$object->container_guid] = true; + } + } + if ($guids) { + $guids = array_slice($guids, 0, 300, true); + elgg_get_entities(array( + 'guids' => array_keys($guids), + 'limit' => 0, + )); } +} + +/** + * List river items + * + * @param array $options Any options from elgg_get_river() plus: + * pagination => BOOL Display pagination links (true) + * + * @return string + * @since 1.8.0 + */ +function elgg_list_river(array $options = array()) { + global $autofeed; + $autofeed = true; + + $defaults = array( + 'offset' => (int) max(get_input('offset', 0), 0), + 'limit' => (int) max(get_input('limit', 20), 0), + 'pagination' => TRUE, + 'list_class' => 'elgg-list-river elgg-river', // @todo remove elgg-river in Elgg 1.9 + ); - /** - * Extract entities from the system log and produce them as an OpenDD stream. - * This stream can be subscribed to and reconstructed on another system as an activity stream. - * - * @param int $by_user The user who initiated the event. - * @param string $relationship Limit return results to only those users who $by_user has $relationship with. - * @param int $limit Maximum number of events to show - * @param int $offset An offset - * @return ODDDocument - */ - function get_river_entries_as_opendd($by_user = "", $relationship = "", $limit = 10, $offset = 0) - { - // set start limit and offset - $cnt = $limit; // Didn' cast to int here deliberately - $off = $offset; // here too - - if (is_array($by_user) && sizeof($by_user) > 0) { - foreach($by_user as $key => $val) { - $by_user[$key] = (int) $val; + $options = array_merge($defaults, $options); + + if (!$options["limit"] && !$options["offset"]) {
+ // no need for pagination if listing is unlimited
+ $options["pagination"] = false;
+ } + + $options['count'] = TRUE; + $count = elgg_get_river($options); + + $options['count'] = FALSE; + $items = elgg_get_river($options); + + $options['count'] = $count; + $options['items'] = $items; + + return elgg_view('page/components/list', $options); +} + +/** + * Convert a database row to a new ElggRiverItem + * + * @param stdClass $row Database row from the river table + * + * @return ElggRiverItem + * @since 1.8.0 + * @access private + */ +function elgg_row_to_elgg_river_item($row) { + if (!($row instanceof stdClass)) { + return NULL; + } + + return new ElggRiverItem($row); +} + +/** + * Get the river's access where clause + * + * @return string + * @since 1.8.0 + * @access private + */ +function elgg_river_get_access_sql() { + // rewrite default access where clause to work with river table + return str_replace("and enabled='yes'", '', + str_replace('owner_guid', 'rv.subject_guid', + str_replace('access_id', 'rv.access_id', get_access_sql_suffix()))); +} + +/** + * Returns SQL where clause for type and subtype on river table + * + * @internal This is a simplified version of elgg_get_entity_type_subtype_where_sql() + * which could be used for all queries once the subtypes have been denormalized. + * + * @param string $table 'rv' + * @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 string + * @since 1.8.0 + * @access private + */ +function elgg_get_river_type_subtype_where_sql($table, $types, $subtypes, $pairs) { + // short circuit if nothing is requested + if (!$types && !$subtypes && !$pairs) { + return ''; + } + + $wheres = array(); + $types_wheres = array(); + $subtypes_wheres = array(); + + // if no pairs, use types and subtypes + if (!is_array($pairs)) { + if ($types) { + if (!is_array($types)) { + $types = array($types); + } + foreach ($types as $type) { + $type = sanitise_string($type); + $types_wheres[] = "({$table}.type = '$type')"; } - } else { - $by_user = (int)$by_user; } - - $exit = false; - - // River objects - $river = new ODDDocument(); - - do - { - $log_events = get_system_log($by_user, "","", $cnt, $off); - - if (!$log_events) - $exit = true; - else - { - - foreach ($log_events as $log) - { - // See if we have access to the object we're talking about - $event = $log->event; - $class = $log->object_class; - $tmp = new $class(); - $object = $tmp->getObjectFromID($log->object_id); - - // Exists and we have access to it - // if (is_a($object, $class)) - if ($object instanceof $class) - { - // If no relationship defined or it matches $relationship - if ( - (!$relationship) || - ( - ($relationship) && - (check_entity_relationship($by_user, $relationship, $tmp->getObjectOwnerGUID())) - ) - ) - { - $relationship_obj = NULL; - - // Handle updates of entities - if ($object instanceof ElggEntity) - { - $relationship_obj = new ODDRelationship( - guid_to_uuid($log->performed_by_guid), - $log->event, - guid_to_uuid($log->object_id) - ); - } - - // Handle updates of metadata - if ($object instanceof ElggExtender) - { - $odd = $object->export(); - $relationship_obj = new ODDRelationship( - guid_to_uuid($log->performed_by_guid), - $log->event, - $odd->getAttribute('uuid') - ); - } - - // Handle updates of relationships - if ($object instanceof ElggRelationship) - { - $odd = $object->export(); - $relationship_obj = new ODDRelationship( - guid_to_uuid($log->performed_by_guid), - $log->event, - $odd->getAttribute('uuid') - ); - //$relationship_obj = $object->export(); // I figure this is what you're actually interested in in this instance. - } - - // If we have handled it then add it to the document - if ($relationship_obj) { - $relationship_obj->setPublished($log->time_created); - $river->addElement($relationship_obj); - } - - } - } - - // Increase offset - $off++; + + if ($subtypes) { + if (!is_array($subtypes)) { + $subtypes = array($subtypes); + } + foreach ($subtypes as $subtype) { + $subtype = sanitise_string($subtype); + $subtypes_wheres[] = "({$table}.subtype = '$subtype')"; + } + } + + if (is_array($types_wheres) && count($types_wheres)) { + $types_wheres = array(implode(' OR ', $types_wheres)); + } + + if (is_array($subtypes_wheres) && count($subtypes_wheres)) { + $subtypes_wheres = array('(' . implode(' OR ', $subtypes_wheres) . ')'); + } + + $wheres = array(implode(' AND ', array_merge($types_wheres, $subtypes_wheres))); + + } else { + // using type/subtype pairs + foreach ($pairs as $paired_type => $paired_subtypes) { + $paired_type = sanitise_string($paired_type); + if (is_array($paired_subtypes)) { + $paired_subtypes = array_map('sanitise_string', $paired_subtypes); + $paired_subtype_str = implode("','", $paired_subtypes); + if ($paired_subtype_str) { + $wheres[] = "({$table}.type = '$paired_type'" + . " AND {$table}.subtype IN ('$paired_subtype_str'))"; } + } else { + $paired_subtype = sanitise_string($paired_subtypes); + $wheres[] = "({$table}.type = '$paired_type'" + . " AND {$table}.subtype = '$paired_subtype')"; } - - } while ( - ($cnt > 0) && - (!$exit) - ); - - return $river; - - }
-
- /**
- * Extract a list of river events from the current system log, from a given user's friends.
- *
- * @seeget_river_entries
- * @param int $by_user The user whose friends we're checking for.
- * @param int $limit Maximum number of events to show
- * @param int $offset An offset
- * @return array of river entities rendered with the appropriate view.
- */
- function get_river_entries_friends($by_user, $limit = 10, $offset = 0) { - $friendsarray = "";
- if ($friends = get_user_friends($by_user, "", 9999)) {
- $friendsarray = array();
- foreach($friends as $friend) {
- $friendsarray[] = $friend->getGUID();
- }
} -
- return get_river_entries($friendsarray,"",$limit,$offset);
- } - - /** - * Simplify drawing a river for a given user. - * - * @param int $guid The user - * @param unknown_type $limit Limit - * @param unknown_type $offset Offset - * @param string $view Optional view to use to display the river (dashboard is assumed) - */ - function elgg_view_river($guid, $limit = 10, $offset = 0, $view = 'river/dashboard') - { - return elgg_view($view, array('river' => get_river_entries($guid,"", $limit, $offset))); } + + if (is_array($wheres) && count($wheres)) { + $where = implode(' OR ', $wheres); + return "($where)"; + } + + return ''; +} + +/** + * Get the where clause based on river action type strings + * + * @param array $types Array of action type strings + * + * @return string + * @since 1.8.0 + * @access private + */ +function elgg_river_get_action_where_sql($types) { + if (!$types) { + return ''; + } + + if (!is_array($types)) { + $types = sanitise_string($types); + return "(rv.action_type = '$types')"; + } + + // sanitize types array + $types_sanitized = array(); + foreach ($types as $type) { + $types_sanitized[] = sanitise_string($type); + } + + $type_str = implode("','", $types_sanitized); + return "(rv.action_type IN ('$type_str'))"; +} + +/** + * Get the where clause based on river view strings + * + * @param array $views Array of view strings + * + * @return string + * @since 1.8.0 + * @access private + */ +function elgg_river_get_view_where_sql($views) { + if (!$views) { + return ''; + } + + if (!is_array($views)) { + $views = sanitise_string($views); + return "(rv.view = '$views')"; + } + + // sanitize views array + $views_sanitized = array(); + foreach ($views as $view) { + $views_sanitized[] = sanitise_string($view); + } + + $view_str = implode("','", $views_sanitized); + return "(rv.view IN ('$view_str'))"; +} + +/** + * Sets the access ID on river items for a particular object + * + * @param int $object_guid The GUID of the entity + * @param int $access_id The access ID + * + * @return bool Depending on success + */ +function update_river_access_by_object($object_guid, $access_id) { + // Sanitise + $object_guid = (int) $object_guid; + $access_id = (int) $access_id; + + // Load config + global $CONFIG; + + // Remove + $query = "update {$CONFIG->dbprefix}river + set access_id = {$access_id} + where object_guid = {$object_guid}"; + return update_data($query); +} + +/** + * Page handler for activity + * + * @param array $page + * @return bool + * @access private + */ +function elgg_river_page_handler($page) { + global $CONFIG; + + elgg_set_page_owner_guid(elgg_get_logged_in_user_guid()); + + // make a URL segment available in page handler script + $page_type = elgg_extract(0, $page, 'all'); + $page_type = preg_replace('[\W]', '', $page_type); + if ($page_type == 'owner') { + $page_type = 'mine'; + } + set_input('page_type', $page_type); + + require_once("{$CONFIG->path}pages/river.php"); + return true; +} + +/** + * Register river unit tests + * @access private + */ +function elgg_river_test($hook, $type, $value) { + global $CONFIG; + $value[] = $CONFIG->path . 'engine/tests/api/river.php'; + return $value; +} + +/** + * Initialize river library + * @access private + */ +function elgg_river_init() { + elgg_register_page_handler('activity', 'elgg_river_page_handler'); + $item = new ElggMenuItem('activity', elgg_echo('activity'), 'activity'); + elgg_register_menu_item('site', $item); - /** - * Simplify drawing a river for a given user, showing their friend's activity - * - * @param int $guid The user - * @param unknown_type $limit Limit - * @param unknown_type $offset Offset - * @param string $view Optional view to use to display the river (dashboard is assumed) - */ - function elgg_view_friend_river($guid, $limit = 10, $offset = 0, $view = 'river/dashboard') - { - return elgg_view($view, array('river' => get_river_entries_friends($guid, $limit, $offset))); - } -?>
\ No newline at end of file + elgg_register_widget_type('river_widget', elgg_echo('river:widget:title'), elgg_echo('river:widget:description')); + + elgg_register_action('river/delete', '', 'admin'); + + elgg_register_plugin_hook_handler('unit_test', 'system', 'elgg_river_test'); +} + +elgg_register_event_handler('init', 'system', 'elgg_river_init'); |
