* @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(' '), ); $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']; }