* @file
* Allows admins to create implied relationships (eg: Manager implies Coworker)
*/
/**
* Public API to load an implied relationship
*
* @param $riid
* integer of the implied relationship ID
*
* @return
* object with the relationship_type object and implied relationship_type object
*/
function user_relationship_implication_load($param = array()) {
$implied_relationships = user_relationship_implications_load();
if (is_numeric($param)) {
return $implied_relationships[$param];
}
foreach ($implied_relationships as $implied) {
$found = TRUE;
foreach($param as $column => $value) {
$column = strtolower($column);
if ($column == 'name' || $column == 'plural_name') {
$value = strtolower($value);
$col_val = strtolower($implied->$column);
}
else {
$col_val = $implied->$column;
}
// mismatch, move to the next type
if ($col_val != $value) {
$found = FALSE;
break;
}
}
if ($found) {
return $type;
}
}
}
/**
* Public API to load all implied relationships
*
* @return
* array of relationship implications
*/
function user_relationship_implications_load($reset = FALSE) {
static $implications = array();
if ($reset || !$implications) {
$results = db_query("SELECT * FROM {user_relationship_implications}");
while ($implication = db_fetch_object($results)) {
$implication->relationship_type = user_relationships_type_load($implication->rtid);
$implication->implies_relationship_type = user_relationships_type_load($implication->implies_rtid);
$implications[$implication->riid] = $implication;
}
}
return $implications;
}
/**
* hook_form_alter()
*/
function user_relationship_implications_form_alter($form_id, &$form) {
switch ($form_id) {
case 'user_relationships_type_edit':
$rtid = $form['rtid']['#value'];
$relationship_type = user_relationships_type_load($rtid);
$relationship_types = user_relationships_types_load();
$implied_by = array();
if ($relationship_type) {
foreach ($relationship_type->implies as $rtid => $implies) {
$values[$rtid]['strict'] = $implies->strict;
$values[$rtid]['reverse'] = $implies->reverse;
}
foreach ($relationship_type->implied_by as $implied) {
if(!$implied->reverse) {
$implied_by[] = $implied->rtid;
}
}
}
$form['implications'] = array(
'#title' => t('This relationship implies'),
'#type' => 'fieldset',
'#weight' => 0,
'#tree' => TRUE,
'#theme' => 'user_relationship_implications_form_table',
'#description' => t('
- Users will automatically have these relationships created between them when the implying relationship is created. (ex: Manager implies Coworker).
- When the implied relationship is removed the implying relationship will not be removed. (ex: removing Coworker WILL NOT remove Manager)
- If "strict" is set the implying relationship will be removed when the implied relationship is removed. (ex: removing Coworker WILL remove Manager)
- Reverse is really only useful for one-way relationships. It allows things like Parent implies Offspring to work in the right direction
'),
);
$list = FALSE;
foreach ($relationship_types as $type) {
if ($type->rtid != $relationship_type->rtid && !in_array($type->rtid, $implied_by)) {
$imp_name = "implies_{$type->rtid}";
$form['implications']['opts'][$type->rtid][$imp_name] = array(
'#title' => t($type->name),
'#type' => 'checkbox',
'#return_value' => $type->rtid,
'#default_value' => isset($form['#post'][$imp_name]) || isset($values[$type->rtid]),
);
$strict_name = "implied_{$type->rtid}_strict";
$form['implications']['opts'][$type->rtid][$strict_name] = array(
'#type' => 'checkbox',
'#return_value' => $type->rtid,
'#default_value' => isset($form['#post'][$strict_name]) || $values[$type->rtid]['strict'],
);
$opp_name = "implied_{$type->rtid}_reverse";
$form['implications']['opts'][$type->rtid][$opp_name] = array(
'#type' => 'checkbox',
'#return_value' => $type->rtid,
'#default_value' => isset($form['#post'][$opp_name]) || $values[$type->rtid]['reverse'],
);
$list = TRUE;
}
}
if ($list) {
$form['#submit']['user_relationship_implications_edit_submit'] = array();
}
else {
unset($form['implications']);
}
break;
}
}
/**
* Edit relationship type submission processor
*/
function user_relationship_implications_edit_submit($form_id, &$form_values) {
// the rtid is in a different place when adding a new type vs. editing an existing type
if (isset($form_values['relationship_type']) && !is_null($form_values['relationship_type'])) {
// editing an existing relationship type
$rtid = $form_values['relationship_type']->rtid;
}
else {
// adding a new relationship type - go figure
$rtid = $form_values['rtid'];
}
db_query("DELETE FROM {user_relationship_implications} WHERE rtid = %d", $rtid);
foreach ($form_values['implications']['opts'] as $implied_rtid => $elements) {
if ($elements["implies_{$implied_rtid}"]) {
$strict = $elements["implied_{$implied_rtid}_strict"] ? 1 : 0;
$reverse = $elements["implied_{$implied_rtid}_reverse"] ? 1 : 0;
db_query(
"INSERT INTO {user_relationship_implications} (riid, rtid, implies_rtid, strict, reverse) VALUES (%d, %d, %d, %d, %d)",
db_next_id('{user_relationship_implications}_id'), $rtid, $implied_rtid, $strict, $reverse
);
}
}
}
/**
* hook_user_relationships()
*/
function user_relationship_implications_user_relationships($type, &$relationship, $category = NULL) {
switch ($type) {
case 'load':
if ($category == 'type' && $relationship->rtid) {
static $loaded_relationship_implications = array();
if (!is_array($loaded_relationship_implications[$relationship->rtid])) {
$loaded_relationship_implications[$relationship->rtid] = array();
$results = db_query(
"SELECT * FROM {user_relationship_implications} WHERE rtid = %d OR implies_rtid = %d",
$relationship->rtid, $relationship->rtid
);
while ($implication = db_fetch_object($results)) {
$loaded_relationship_implications[$relationship->rtid][] = $implication;
}
}
$relationship->implies = array();
$relationship->implied_by = array();
foreach ($loaded_relationship_implications[$relationship->rtid] as $implication) {
if ($implication->rtid == $relationship->rtid) {
$relationship->implies[$implication->implies_rtid] = $implication;
}
else {
$relationship->implied_by[$implication->rtid] = $implication;
}
}
}
break;
case 'delete':
if ($category == 'type') {
if (!$relationship->rtid) { break; }
$results = db_query(
"DELETE FROM {user_relationship_implications} WHERE rtid = %d OR implies_rtid = %d",
$relationship->rtid, $relationship->rtid
);
// clean out the implications cache
static $loaded_relationship_implications;
unset($loaded_relationship_implications);
}
else if ($category != 'type') {
$current_type = user_relationships_type_load($relationship->rtid);
// nothing else matters if there aren't implications involved
$reversed = array_filter($current_type->implies, '_user_relationship_implications_filter_for_reverse');
if (!$current_type->implied_by && !$reversed) { break; }
// load relationships that imply this relationship
$rids = array_merge(array_keys($current_type->implied_by), array_keys($reversed));
$relationships = user_relationships_load(array(
'between' => array($relationship->requester_id, $relationship->requestee_id),
'rtid' => $rids
), FALSE, 'rtid');
foreach ($relationships as $rtid => $relationship) {
$relationship = array_shift($relationship);
// the relationship being deleted (current_type) is implied by this relationship (only matters if "strict" is set)
if ($current_type->implied_by[$rtid]->strict || $reversed[$rtid]->strict) {
user_relationships_delete_relationship($relationship, $current_type->deleted_by, $category);
drupal_set_message(user_relationships_get_message($category, $relationship));
}
}
}
break;
case 'post-save':
$type = user_relationships_type_load($relationship->rtid);
if ($type->implies) {
// if the type of the relationship we're inserting or updating implies other relationship type(s),
// loop through the implied relationship types and do the right thing
foreach ($type->implies as $implied) {
// load all the pre-existing relationships between these two users of the implied relationship type
$relationships = user_relationships_load(array(
'between' => array($relationship->requester_id, $relationship->requestee_id),
'rtid' => $implied->implies_rtid,
));
// if there aren't any, create one with the same approved status as the relationship we're inserting/updateing
if (sizeof($relationships) == 0) {
$users = array($relationship->requester_id, $relationship->requestee_id);
if ($implied->reverse) { $users = array_reverse($users); }
$implied = user_relationships_type_load($implied->implies_rtid);
user_relationships_request_relationship($users[0], $users[1], $implied, $relationship->approved);
}
// if there are some, then if we're approving this relationship, approve the pre-existing one(s) too
else {
foreach ($relationships as $existing) {
if ($relationship->approved && !$existing->approved) {
// approve the relationship
$approved = $existing;
$approved->approved = TRUE;
user_relationships_update_relationship($existing, $approved);
// set the message informing the user (use requester and requestee from original relationship)
drupal_set_message(user_relationships_get_message('accepted', $approved));
}
}
}
}
}
break;
}
}
/**
* hook_user_relationships_page_alter()
*/
function user_relationship_implications_user_relationships_page_alter($page_id, &$page, &$table) {
switch ($page_id) {
case 'types list':
array_splice($table['headers'], 2, 0, t('Implies'));
foreach ($table['data'] as $key => $relationship) {
$relationship = user_relationships_type_load($relationship->rtid);
array_splice($table['rows'][$key], 2, 0, ' ');
$names = array();
if (is_array($relationship->implies)) {
foreach ($relationship->implies as $implied) {
$implied = user_relationship_implication_load($implied->riid);
$names[] = $implied->implies_relationship_type->name;
}
}
$table['rows'][$key][2] = implode(', ', $names);
}
break;
}
}
/**
* Categorized list of relationships for a given user
*/
function theme_user_relationship_implications_page($uid = NULL, $relationship = NULL) {
global $user;
if (empty($uid)) {
$viewed_user =& $user;
}
else {
$viewed_user = user_load(array('uid' => $uid));
}
// Check that the uid is valid, not the anonymous user, and the user exists
if ($viewed_user->uid == 0) {
drupal_not_found();
exit();
}
$params = array('user' => $viewed_user->uid);
if (isset($relationship->rtid)) {
$params['rtid'] = $relationship->rtid;
}
$query = _user_relationships_generate_query($params);
if ($relationships_per_page = variable_get('user_relationships_relationships_per_page', 16)) {
$results = pager_query($query['query'], $relationships_per_page, 0, $query['count'], $query['arguments']);
}
else {
$results = db_query($query['query'], $query['arguments']);
}
if (db_num_rows($results)) {
$edit_access = ($user->uid == $uid && user_access('maintain relationships')) || user_access('administer users');
$online_interval = time() - variable_get('user_block_seconds_online', 180);
while ($relation = db_fetch_object($results)) {
$this_user = $viewed_user->uid == $relation->requestee_id ? 'requester_id' : 'requestee_id';
$this_user = user_load(array('uid' => $relation->$this_user));
$relations = array();
$this_users_relationships = user_relationships_load(array('user' => $this_user->uid));
$rows[] = array(
theme('username', $this_user),
theme('item_list', _user_relationship_implications_load_relationship_names($this_users_relationships, $viewed_user->uid)),
$this_user->access > $online_interval ? t('online') : t('not online'),
$edit_access ? theme('user_relationships_remove_link', $viewed_user->uid, $relation) : ' ',
);
}
$output .= theme('table', array(), $rows);
}
else {
$output .= t('No relationships found');
}
$output .= theme('pager', NULL, $relationships_per_page);
drupal_set_title(t("%username's %relationships", array(
'%username' => $viewed_user->name,
'%relationships' => $relationship->plural_name ? $relationship->plural_name : t('relationships')
)));
return $output;
}
/**
* Theme function to create a table of checkboxes for the implications
*/
function theme_user_relationship_implications_form_table(&$form) {
$headers = array(t('Relationship Type'), t('Strict'), t('Reverse'));
$rows = array();
foreach ($form['opts'] as $rtid => $elements) {
if (!is_numeric($rtid)) { continue; }
$rows[$rtid] = array(
drupal_render(array_shift($elements)),
drupal_render(array_shift($elements)),
drupal_render(array_shift($elements)),
);
}
return theme('table', $headers, $rows);
}
/**
* Helper functions (not for general use!!)
*/
function _user_relationship_implications_load_relationship_names($relationships, $uid) {
$output = array();
foreach ($relationships as $relationship) {
if ($relationship->requester_id == $uid || $relationship->requestee_id == $uid) {
$output[] = $relationship->name;
}
}
return $output;
}
function _user_relationship_implications_filter_for_reverse($implication) {
$implication = (array)$implication;
return $implication['reverse'];
}