$value) { $column = strtolower($column); if ($column == 'name' || $column == 'plural_name') { $value = strtolower($value); $col_val = strtolower($type->$column); } else { $col_val = $type->$column; } // mismatch, move to the next type if ($col_val != $value) { $found = FALSE; break; } } if ($found) { return $type; } } } /** * Public API for loading the full list of relationship types * * @return * array of relationship_type objects */ function user_relationships_types_load($reset = FALSE) { static $relationship_types_list = array(); if ($reset || !sizeof($relationship_types_list)) { $results = db_query("SELECT * FROM {user_relationship_types}"); while ($relationship = db_fetch_object($results)) { $relationship_types_list[$relationship->rtid] = $relationship; } } _user_relationships_invoke('load', $relationship_types_list, TRUE); return $relationship_types_list; } /** * Create or Update a User Relationship Type * * @param $rtype * A User Relationship type object */ function user_relationships_type_save(&$rtype) { _user_relationships_invoke('presave', $rtype, TRUE); $op = $rtype->rtid ? 'update' : 'insert'; // find a relationship type with the name we're trying to save // if it's an update action check to see that the rtypes match // otherwise it's just invalid if ( ($found_rt = user_relationships_type_load(array('name' => $rtype->name))) && ($op == 'update' ? $found_rt->rtid != $rtype->rtid : TRUE) ) { return FALSE; } // ensure "expires_val" is numeric and not negative if (!is_numeric($rtype->expires_val) || $rtype->expires_val < 0) { $rtype->expires_val = 0; } if ($op == 'update') { db_query( "UPDATE {user_relationship_types} SET name = '%s', plural_name = '%s', is_oneway = %d, requires_approval = %d, expires_val = %d WHERE rtid = %d", $rtype->name, $rtype->plural_name, ($rtype->is_oneway ? 1 : 0), ($rtype->requires_approval ? 1 : 0), $rtype->expires_val, $rtype->rtid ); } else { $rtype->rtid = db_next_id('{user_relationship_types}_id'); db_query( "INSERT INTO {user_relationship_types} (rtid, name, plural_name, is_oneway, requires_approval, expires_val) VALUES(%d, '%s', '%s', %d, %d, %d)", $rtype->rtid, $rtype->name, $rtype->plural_name, ($rtype->is_oneway ? 1 : 0), ($rtype->requires_approval ? 1 : 0), $rtype->expires_val ); } _user_relationships_invoke($op, $rtype, TRUE); } /** * Delete a User Relationship Type * * @param $rtid * A User Relationship type ID */ function user_relationships_type_delete($rtid) { $rtype = user_relationships_type_load($rtid); db_query('DELETE FROM {user_relationship_types} WHERE rtid = %d', $rtid); db_query('DELETE FROM {user_relationships} WHERE rtid = %d', $rtid); _user_relationships_invoke('delete', $rtype, TRUE); } /** * Public API for creating a relationship. * * @param $requester * object or ID of the requester * @param $requestee * object or ID of the requestee * @param $type * object or ID of the relationship type * @param $approved * boolean status of the relationship * * @return * object of the newly created relationship */ function user_relationships_request_relationship($requester, $requestee, $type, $approved = FALSE) { // translate an ID into an object foreach (array('requester' => $requester, 'requestee' => $requestee, 'type' => $type) as $key => $value) { if (!is_object($value)) { $$key = $key == 'type' ? user_relationships_type_load($value) : user_load($value); } } if (!user_relationships_load(array('between' => array($requester->uid, $requestee->uid), 'rtid' => $type->rtid), array('count' => TRUE))) { $relationship = (object)array( 'requester_id' => $requester->uid, 'requestee_id' => $requestee->uid, 'approved' => $approved || !$type->requires_approval, 'rtid' => $type->rtid, ); return user_relationships_save_relationship($relationship); } } /** * Create or update a user relationship. * * @param $relationship * object of the current relationship * @param $op * the reason for the update * * @return * object of the updated relationship * or * false if the relationship wasn't able to save */ function user_relationships_save_relationship(&$relationship, $op = 'request') { //set basic info if it doesn't already exist !isset($relationship->flags) ? $relationship->flags = UR_OK : NULL; !isset($relationship->created_at) ? $relationship->created_at = time() : NULL; $relationship->updated_at = time(); _user_relationships_invoke('presave', $relationship); if ($relationship->rid) { db_query("DELETE FROM {user_relationships} WHERE rid = %d", $relationship->rid); // Delete possible requests coming the other direction $relationship_type = user_relationships_type_load($relationship->rtid); if (!$relationship_type->is_oneway) { db_query( 'DELETE FROM {user_relationships} WHERE rtid = %d AND requester_id = %d AND requestee_id = %d', $relationship->rtid, $relationship->requestee_id, $relationship->requester_id ); } } else { $relationship->rid = db_next_id('{user_relationships}_id'); } $queries = array(); $relationship_type = user_relationships_type_load($relationship->rtid); $query = 'INSERT INTO {user_relationships} (rid, requester_id, requestee_id, rtid, approved, created_at, updated_at, flags) VALUES'; $insertions = '(%d, %d, %d, %d, %d, %d, %d, %d)'; $arguments = array( $relationship->rid, $relationship->requester_id, $relationship->requestee_id, $relationship->rtid, $relationship->approved, $relationship->created_at, time(), $relationship->flags, ); $queries["{$query} {$insertions}"] = $arguments; // Relationship is two-way so we need to do a double entry // This keeps db SELECTs fast if ($relationship->approved && !$relationship_type->is_oneway) { // flip-flop the requester/requestee $query = str_replace('requester_id, requestee_id', 'requestee_id, requester_id', $query); $queries["{$query} {$insertions}"] = $arguments; } $valid = TRUE; foreach ($queries as $query => $arguments) { if (db_query($query, $arguments) === FALSE) { $valid = FALSE; break; } } if (!$valid) { // hopefully we never get here cause it means big problems // but let's be gracefull about the failure db_query('DELETE FROM {user_relationships} WHERE rid = %d', $relationship->rid); unset($relationship->rid); return FALSE; } else { _user_relationships_invoke($op, $relationship); return $relationship; } } /** * Public API for deleting a relationship. * * @param $relationship * object of the relationship * @param $deleted_by * object of the user that initiated the delete command * @param $op * string reason for removal ('cancel','disapprove','remove') */ function user_relationships_delete_relationship(&$relationship, &$deleted_by, $op = 'remove') { $relationship->deleted_by = $deleted_by; db_query("DELETE FROM {user_relationships} WHERE rid = %d", $relationship->rid); _user_relationships_invoke($op, $relationship); } /** * Load relationship objects from the database. * * @param $param * an array of parameters with the key being the column. columns from both the user_relationships and user_relationship_types tables will work * columns from user_relationships: rid, requester_id, requestee_id, rtid, approved, created_at, updated_at, flags * columns from user_relationship_types: name, plural_name, is_oneway, requires_approval, expires_val * There are two special keys: * 1) array("between" => array($uid1, $uid2)) will return all relationships between the two user ids. * 2) array("user" => $uid) will return all relationships for the specified uid * * arguments will process operators as well using the syntax: array(col => '> {value}'). * example: show all relationships created in 2007 * $start_time = mktime(0,0,0,0,0,2007); * $end_time = mktime(0,0,0,0,0,2008); * user_relationships_load(array('created_at' => ">= {$start_time}", 'created_at' => '< {$end_time'})); * * @param @options * An array keyed by the option * count * a boolean stating whether or not the return value should be the number of relationships found * * sort * a string containing a valid column name which will become the key for the returned array of relationships * * order * a string containing SQL stating the column and direction of the sort (ex. "requester_id ASC, rtid DESC") * * limit * a string containing SQL stating the limit (ex "10" or "10, 5") * * include_user_info * a boolean that will load basic user info without having to call user_load * columns: uid, name, mail, data, picture * * @param $reset * a boolean that will reset the internal static $relationships variable to ensure programatic relationship insertion works * * @return * an array of relationships * if the key is "rid" the array will be a single dimention: array($rid => $relationship, $rid => $relationship) * otherwise it'll be multidimentional: array($rtid => array($relationship, $relationship)) * * each relationship will have the user's name, mail, and data attached as requester_name, requester_mail, requester_data * or requestee_name, requestee_mail, requestee_data */ function user_relationships_load($param = array(), $options = array(), $reset = FALSE) { static $relationships = array(); $default_options = array( 'sort' => 'rid', ); $options = array_merge($default_options, $options); extract($options, EXTR_SKIP); $arguments = array(); if (is_numeric($param)) { if (!$reset && isset($relationships[$param])) { return is_object($relationships[$param]) ? drupal_clone($relationships[$param]) : $relationships[$param]; } $rid = $param; $param = array('rid' => $param); } $query = _user_relationships_generate_query($param, $options); $results = db_query($query[($count ? 'count' : 'query')], $query['arguments']); if ($count) { return (int)db_result($results); } $relationships = array(); while ($relationship = db_fetch_object($results)) { if ($include_user_info) { user_relationships_api_translate_user_info($relationship); } if ($sort == 'rid') { $relationships[$relationship->{$sort}] = $relationship; } else { $relationships[$relationship->{$sort}][] = $relationship; } } $return = $rid ? $relationships[$rid] : $relationships; _user_relationships_invoke('load', $return); return $return; } /** * Used when the "include_user_info" option is set on user_relationships_load * to translate the retrieved user fields into actual user objects. This allows us * to pull the basic user data without having to run user_load * * @param $relationship * The relationship object with pulled user info */ function user_relationships_api_translate_user_info(&$relationship) { if ($relationship->requester_name) { foreach (array('requester', 'requestee') as $user_type) { $relationship->{$user_type} = new stdClass(); foreach (array('name', 'mail', 'data', 'picture') as $field) { $db_field = "{$user_type}_{$field}"; $relationship->{$user_type}->{$field} = $relationship->{$db_field}; unset($relationship->{$db_field}); } $user_type_id = "{$user_type}_id"; $relationship->{$user_type}->uid = $relationship->{$user_type_id}; $relationship->{$user_type}->data = unserialize($relationship->{$user_type}->data); } } }