Search form

Drupal: A Client-Server Data Model

While working for an administrative unit in a public university, I was directed to convert a people management system from an old Zope-Plone server to Drupal. The idea was that individuals within the unit -- staff, faculty, students -- could log into a central Drupal site (the campus used CAS for authentication), update their contact information, CV, or other data; and then this would then be saved in custom tables in Drupal's underlying database to be displayed either in reports run by the administrative staff or on the web sites of individual departments within the unit. This particular unit oversaw a dozen or so individual departments, so it was necessary to filter listings of, say, professors or graduate students by department -- Spanish, French, German, and so forth. The central system would be the "server" module.

The department web sites needed to show up-to-date listings of individual faculty/students/staff in that department. This is the "client" part: the department web site can "log in" to to the server over port 80, run a query based on a unique department code, at which point the server encodes and returns a blob of JSON data, which the client then decodes and displays in a preset template. To do all this, the "server" module had to be installed on the central/server Drupal instance, and then the "people" (client) module had to be installed on each Drupal instance representing an individual department web site.

This depended on Drupal 7's Services 3.x module. With Drupal 8, REST transactions are available in core, so the Services module is no longer necessary to do something like this.

Over time, the system acquired some additional capabilities, like the ability to search the database by people or department, and a fairly granular permissions system for viewing or altering data. The server component also makes use of the Features, Strongarm, and Ctools modules to export styles and settings, override default settings in the variables table, and create exportable field groups for the admin forms using the field_group API. Later TCPDF was added so the administrative staff could generate department rosters in a convenient format.

To make this even more fun, a second PostgreSQL database running on a different server needed to be updated in tandem with changes to the people information in Drupal's MySQL database. Thus the code referencing the PHP Postgres driver below.

I'm intentionally excluding some of the support files, like the features.inc export and the admin.inc admin menu -- the point here is to show the query and display systems.

File people_server.module, the core of the server module:

/**
 * @file
 * Code for the UCD LNL People Server feature.
 */

include_once('ucd_lnl_people_server.features.inc');

/*
 * Implementation of hook_menu()
 */
function ucd_lnl_people_server_menu() {
  $items = array();

  $items['myhome/people'] = array(
    'title' => 'People',
    'description' => t('People database tasks.'),
    'page callback' => 'ucd_lnl_homes_myhome',
    'page arguments' => array('myhome/people'),
    'access arguments' => array('administer ucd people profiles'),
    'expanded' => TRUE,
    'menu_name' => 'myhome',
    'weight' => 0,
  );
  $items['myhome/people/add'] = array(
    'title' => t('Add Person'),
    'description' => t('Add a person to the database'),
    'page callback' => 'drupal_get_form',
    'page arguments' => array('user_register_form'),
    'access arguments' => array('administer ucd people profiles'),
    'weight' => -45,
  );
  $items['myhome/people/search'] = array(
    'title' => t('Search by Group'),
    'description' => t('Search for groups of people and then select what you want to do to their database records.'),
    'page callback' => 'drupal_get_form',
    'page arguments' => (array('ucd_lnl_people_server_search', 3)),
    'access arguments' => array('administer ucd people profiles'),
    'weight' => -40,
  );
  $items['myhome/people/search/results'] = array(
    'type' => MENU_CALLBACK,
    'title' => t('Results'),
    'page callback' => 'ucd_lnl_people_server_search_results',
    'page arguments' => array(4, 5, 6, 7),
    'access arguments' => array('administer ucd people profiles'),
    'weight' => -30,
  );
  $items['myhome/people/%/print'] = array(
    'type' => MENU_CALLBACK,
    'title' => t('Phone PDF Test'),
    'page callback' => 'ucd_lnl_people_server_phonepdf',
    'page arguments' => array(2, 4, 5, 6),
    'access arguments' => array('administer ucd people profiles'),
    'weight' => -40,
  );
  $items['myhome/people/%/print/%/pdf_settings'] = array(
    'title' => t('PDF print settings'),
    'description' => t('Select title and color of phone list to generate'),
    'page callback' => 'ucd_lnl_people_server_PDF_settings',
    'page arguments' => array(2, 4),
	'access arguments' => array('administer ucd people profiles'),
    'type' => MENU_NORMAL_ITEM,
  );

  return $items;
}

/**
 * Implements hook_features_export_alter().
 *
 * Alter the final export array just prior to the rendering of
 * defaults.
 * FORBID the hook_views_api, we are going to add that ourselves.
 *
 * @param array &$export
 *   By reference. An array of all components to be exported with a given
 *   feature.
 * @param array $module_name
 *   The name of the feature module to be generated.
 */
function ucd_lnl_people_server_features_export_alter(&$export, $module_name) {
  if ($module_name == 'ucd_lnl_people_server' && !empty($export['features']['ctools']['views:views_default:3.0'])) {
    unset($export['features']['ctools']['views:views_default:3.0']);
  }
}

/**
 * Implements hook_views_api().
 * See hook_features_export_alter above.
 * This allows adding of template path via hook_views_api that default features
 * export doesn't include.
 */
function ucd_lnl_people_server_views_api() {
  return array("version" => "3.0", 'template path' => drupal_get_path('module', 'ucd_lnl_people_server'));
}


/**
 * Add the user/add path to the admin overlay.
 */
function ucd_lnl_people_server_admin_paths_alter(&$paths) {
  $paths['myhome/people/add'] = TRUE;
}

/*
 * Implementation of hook_permission()
 */
function ucd_lnl_people_server_permission() {
  return array(
    'administer ucd people profiles' => array(
      'title' => t('Administer UCD LNL people profiles'),
      'description' => t('Add and edit UCD LNL people and profiles.'),
    ),
  );
}

/**
 * Implementation of hook_theme
 */
function ucd_lnl_people_server_theme() {
  $theme['render_ucd_lnl_people_server_office_hours_form'] = array(
    'render element' => 'form',
  );
  
  return $theme;
}

/**
 * Suggest a module-provided tpl.php file for views as necessary.
 *  Normally this should be done via hook_views_api but features already declares it
 *  in the myfeature.features.inc file so I modified it there.
 */
/*
function ucd_lnl_people_server_views_api() {
  return array(
    'api' => 3.0,
    'template path' => drupal_get_path('module', 'ucd_lnl_people_server'),
  );
}
*/

/**
 * Search for people by group function
 */
function ucd_lnl_people_server_search($form, &$form_state, $operation = NULL) {
  //prepare the dept selection boxes
  $depts = views_get_view('dept_list');
  $depts->preview();
  foreach ($depts->result as $dept) {
    $depts_array[$dept->nid] = $dept->node_title;
  }

  //prepare the admin_group selection options
  $admin_groups_field = field_read_field('field_admin_group');
  $admin_groups = list_allowed_values($admin_groups_field);

  //define the available operations
  $operations = array(
    'summary' => t('List - Summary: View or download a summary of information in the database with links to edit links'),
    'comprehensive' => t('List - Comprehensive: View or download all information in the database with edit links'),
    'conf' => t('List - Confidential Information: View or download home/mobile phone and non-campus email information'),
    'grad' => t('List - Grad Supplemental: View or download supplemental information for graduate students'),
    'phone_public' => t('Phone List - Public: Create a public phone list'),
    'phone_confidential' => t('Phone List - Confidential: Create a confidential phone list'),
    'email' => t('Email List: Create an email list'),
    'office_hours' => t('Office Hours - Bulk Update: Bulk update office hours'),
    'office_hours_clear' => t('Office Hours - Clear: Clear office hours'),
  );

  //pre-select the operation if given
  if ($operation) {
    if (isset($operations[$operation])) {
      $operations_default_value = $operation;
    }
  }

  //define the available search options
  $search_options = array(
    'include_inactive' => t('Include people currently marked as inactive in the search'),
    'exclude_affiliated' => t('Exclude the "affiliated" people from search results'),
  );

  //the Drupal form elements
  $form['dept_selection'] = array(
    '#title' => t('Search by Department'),
    '#type' => 'checkboxes',
    '#options' => $depts_array,
    '#description' => t('If no boxes are checked, all departments will be included.'),
  );
  $form['admin_group_selection'] = array(
    '#title' => t('Search by Administrative Group'),
    '#type' => 'checkboxes',
    '#options' => $admin_groups,
    '#description' => t('If no boxes are checked, all administrative groups will be included.'),
  );
  $form['operation'] = array(
    '#title' => t('Operations'),
    '#type' => 'radios',
    '#options' => $operations,
    '#required' => TRUE,
    '#description' => t('Please select what you would like to do to the database records that result from this search.'),
    '#default_value' => isset($operations_default_value) ? $operations_default_value : 'summary',
  );
  $form['search_options'] = array(
    '#title' => t('Search Options'),
    '#type' => 'checkboxes',
    '#options' => $search_options,
  );
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Search'),
  );

  return $form;
}

/**
 * Clean up the form output and pass to ucd_lnl_people_server_search_results.
 */
function ucd_lnl_people_server_search_submit($form_id, &$form_state) {
  $depts = $form_state['values']['dept_selection'];
  $admin_groups = $form_state['values']['admin_group_selection'];
  $operation = $form_state['values']['operation'];
  $search_options = $form_state['values']['search_options'];

  //remove the not-selected choices from the values array entirely
  foreach ($depts as $key => $value) {
    if (!$value) {
      unset($depts[$key]);
    }
  }
  foreach ($admin_groups as $key => $value) {
    if (!$value) {
      unset($admin_groups[$key]);
    }
  }
  foreach ($search_options as $key => $value) {
    if (!$value) {
      unset($search_options[$key]);
    }
  }

  //add "all" to the url if no filters were selected
  if (!count($depts)) {
    $depts[] = 'all';
  }
  if (!count($admin_groups)) {
    $admin_groups[] = 'all';
  }

  //add "none" to the url if no options were selected
  if (!count($search_options)) {
    $search_options[] = 'none';
  }

  //prepare the depts and admin_groups for inserting into URL
  $depts_url = implode($depts, '+');
  $admin_groups_url = implode($admin_groups, '+');
  $search_options_url = implode($search_options, '+');

  drupal_goto('myhome/people/search/results/' . $depts_url . '/' . $admin_groups_url . '/' . $operation . '/' . $search_options_url);
}

/**
 * Run the search query for user IDs and redirect to the appropriate 
 * function or view for the operation desired.  Ideally, one would use
 * a Drupal view for this but currently views does not allow multiple
 * string arguments separated by + like it does numerical arguments, so
 * I build the query manually (and painfully).
 */
function ucd_lnl_people_server_search_results($depts = 'all', $admin_groups = 'all', $operation = 'summary', $search_options = 'none') {
  //for some annoying reason if no arguments are passed, Drupal still 
  //passes a blank string value rather than no value at all.
  $depts ? "" : $depts = "all";
  $admin_groups ? "" : $admin_groups = "all";
  $operation ? "" : $operation = 'summary';
  $search_options ? "" : $search_options = 'none';

  //re-expand multiple filters/options into arrays, ignore the all/none values and validate arguments
  $depts = explode('+', $depts);
  if ($depts[0] == 'all') {
    unset($depts[0]);
  };
  foreach ($depts as $key => $value) {
    if(!(is_numeric($value))) {
      unset($depts[$key]);
    }
  }

  $admin_groups = explode('+', $admin_groups);
  $admin_groups_field = field_read_field('field_admin_group');
  $admin_groups_allowed = list_allowed_values($admin_groups_field);
  foreach ($admin_groups as $key => $value) {
    if (!(isset($admin_groups_allowed[$value]))) {
      unset($admin_groups[$key]);
    }
  }

  $search_options = explode('+', $search_options);
  if ($search_options[0] == 'none') {
    unset($search_options[0]);
  }
  foreach($search_options as $key => $value) {
    $search_options_new[$value] = TRUE;
  }
  if (isset($search_options_new)) {
    $search_options = $search_options_new;
  }

  //prepare the depts options for inserting into SQL
  if (count($depts)) {
    if (!(isset($search_options['exclude_affiliated']))) {
        $depts_join_sql = "\nLEFT JOIN {field_data_field_depts} field_data_field_depts ON users.uid = field_data_field_depts.entity_id AND (field_data_field_depts.entity_type = 'user' AND field_data_field_depts.deleted = '0')";
    } else {
       $depts_join_sql = "\nLEFT JOIN {field_data_field_home_dept} field_data_field_home_dept ON users.uid = field_data_field_home_dept.entity_id AND (field_data_field_home_dept.entity_type = 'user' AND field_data_field_home_dept.deleted = '0')";    }    
    $depts_list = '\'' . implode($depts, '\',\'') . '\'';
  }

  //prepare the admin groups options for inserting into SQL

  if (count($admin_groups)) {
    $admin_groups_join_sql = "\nLEFT JOIN {field_data_field_admin_group} field_data_field_admin_group ON users.uid = field_data_field_admin_group.entity_id AND (field_data_field_admin_group.entity_type = 'user' AND field_data_field_admin_group.deleted = '0')";
    $admin_groups_list = '\'' . implode($admin_groups, '\',\'') . '\'';
  }

  //process any search options
  if (!(isset($search_options['include_inactive']))) {
    $status_sql = "(( (users.status <> '0') )) ";
  }

  //build the "WHERE" SQL clause
  if (isset($admin_groups_list)) {
    $admin_groups_sql = " (field_data_field_admin_group.field_admin_group_value IN ($admin_groups_list)) ";
  }
  if (isset($depts_list)) {
    if (!(isset($search_options['exclude_affiliated']))) {
       $depts_list_sql = " (field_data_field_depts.field_depts_target_id IN ($depts_list)) ";
    } else {
       $depts_list_sql = " (field_data_field_home_dept.field_home_dept_target_id IN ($depts_list)) ";
    }
  }

  if (isset($depts_list) || isset($admin_groups_list)) {
    $depts_admin_sql = "(";
    if (isset($admin_groups_list)) {
      $depts_admin_sql .= $admin_groups_sql;
    }
    if (isset($admin_groups_list) && isset($depts_list)) {
      $depts_admin_sql .= "\n AND ";
    }
    if (isset($depts_list)) {
      $depts_admin_sql .= $depts_list_sql;
    }
    $depts_admin_sql .= ")";
  }
  if (isset($depts_list) || isset($admin_groups_list) || isset($status_sql)) {
    $where = "\nWHERE (";
    if (isset($depts_admin_sql)) {
      $where .= $depts_admin_sql;
    }
    if (isset($status_sql)) {
      if (isset($depts_admin_sql)) {
        $status_sql = "\n AND " . $status_sql;
      }
      else {
        $status_sql = "\n" . $status_sql;
      }
      $where .= $status_sql;
    }
    $where .= ")";
  }

  $query = "SELECT users.name AS users_name, 
                   users.uid AS uid, 
                   users.created AS users_created
            FROM   {users} users";

  if (isset($admin_groups_join_sql)) {
    $query .= $admin_groups_join_sql;
  }
  if (isset($depts_join_sql)) {
    $query .= $depts_join_sql;
  }
  if (isset($where)) {
    $query .= $where;
  }

  //dsm($query);
  $result = db_query($query);

  //return an array of user ids (uids) to pass into other views and functions
  $user_list = array();
  while ($record = $result->fetchObject()) {
    $user_list[] = $record->uid;
  }

  if (!count($user_list)) {
    $message = "

" . t("There were no users returned by this search. Please go back and try again.") . "

"; return $message; } //redirect to appropriate function as specified by the operation selected by the user switch ($operation) { case 'summary': $output = ucd_lnl_people_server_summary($user_list); break; case 'comprehensive': $output = ucd_lnl_people_server_comprehensive($user_list); break; case 'conf': $output = ucd_lnl_people_server_conf($user_list); break; case 'grad': $output = ucd_lnl_people_server_grad($user_list); break; case 'phone_public': $output = ucd_lnl_people_server_phone_public($user_list); break; case 'phone_confidential': $output = ucd_lnl_people_server_phone_confidential($user_list); break; case 'email': $output = ucd_lnl_people_server_email($user_list); break; case 'office_hours': $output = ucd_lnl_people_server_office_hours($user_list); break; case 'office_hours_clear': $output = ucd_lnl_people_server_office_hours_clear($user_list); break; } return $output; } /** * Builds the summary view given a list of users. */ function ucd_lnl_people_server_summary($user_list) { $user_list_argument = implode($user_list, '+'); $view = views_embed_view('people_admin_summary', 'attachment_1', $user_list_argument); return $view; } /** * Builds the comprehensive view given a list of users. */ function ucd_lnl_people_server_comprehensive($user_list) { $user_list_argument = implode($user_list, '+'); $view = views_embed_view('people_admin_comprehensive', 'attachment_1', $user_list_argument); return $view; } /** * Builds the grad supplemental view given a list of users. */ function ucd_lnl_people_server_grad($user_list) { $user_list_argument = implode($user_list, '+'); $view = views_embed_view('people_admin_grad_supplemental', 'attachment_1', $user_list_argument); return $view; } /** * Builds the people supplemental view given a list of users. */ function ucd_lnl_people_server_conf($user_list) { $user_list_argument = implode($user_list, '+'); $view = views_embed_view('people_admin_supplemental', 'attachment_1', $user_list_argument); return $view; } /** * Builds the public phone list given a list of users. * See also: * - hook preprocess_views_view (can override view title) * - The theme's templates/print.tpl.php file * - The module-provided template files that override some of the default output settings. */ function ucd_lnl_people_server_phone_public($user_list) { $user_list_argument = implode($user_list, '+'); $view = views_embed_view('people_admin_phone_list', 'default', $user_list_argument); return $view; } /** * Builds the confidential phone list given a list of users. * See the above public phone list for more notes. */ function ucd_lnl_people_server_phone_confidential($user_list) { $user_list_argument = implode($user_list, '+'); $view = views_embed_view('people_admin_phone_list_conf', 'default', $user_list_argument); return $view; } /** * Builds an email list given a list of users. */ function ucd_lnl_people_server_email($user_list) { global $user; $user_list_argument = implode($user_list, '+'); $email_view = views_get_view('people_admin_email'); $email_view->set_arguments(array($user_list_argument)); $email_view->preview(); $email_link = "mail . "?bcc="; $list_output = ""; foreach($email_view->result as $result) { $email_link .= $result->users_mail . ";"; $list_output .= $result->users_mail . ","; } $email_link = substr($email_link, 0, -1); $list_output = substr($list_output, 0, -1); $email_link .= "\">Click this link to create a new message to the below recipients."; $output = "

You may cut and paste the list into the email program of your choice or " . "you can click the link below to bring up a new blank message to this list of recipients " . "in your default email program.

"; $output .= "

" . $email_link . "

"; $output .= "

If you choose to copy and paste the list below, please remember to BCC for privacy reasons.

"; $output .= "

" . $list_output . "

"; return $output; } /** * Office hours bulk edit form. * This function retrieves the office hours from a view. */ function ucd_lnl_people_server_office_hours($user_list) { $user_list_argument = implode($user_list, '+'); $view = views_get_view('people_admin_office_hours_bulk'); $view->set_arguments(array($user_list_argument)); $view->preview(); return drupal_get_form('ucd_lnl_people_server_office_hours_form', $view->result); } /** * This builds the office hours bulk edit Drupal forms array given a * list of people and office hours returned from the * people_admin_office_hours_bulk view. */ function ucd_lnl_people_server_office_hours_form($form, &$form_state, $people) { $i = 0; foreach ($people as $person) { $faculty_oh = isset($person->field_field_faculty_officehours[0]['raw']['value']) ? $person->field_field_faculty_officehours[0]['raw']['value'] : ""; $staff_oh = isset($person->field_field_staff_advisinghours[0]['raw']['value']) ? $person->field_field_staff_advisinghours[0]['raw']['value'] : ""; $ta_oh = isset($person->field_field_ta_officehours[0]['raw']['value']) ? $person->field_field_ta_officehours[0]['raw']['value'] : ""; $tutor_oh = isset($person->field_field_tutor_officehours[0]['raw']['value']) ? $person->field_field_tutor_officehours[0]['raw']['value'] : ""; $form['uid_' . $i] = array( '#type' => 'value', '#value' => $person->uid, ); $form['name_' . $i] = array( '#markup' => $person->field_field_first[0]['rendered']['#markup'] . ' ' . $person->field_field_last[0]['rendered']['#markup'], ); $form['faculty_oh_' . $i] = array( '#type' => 'textfield', '#default_value' => $faculty_oh, '#size' => 15, ); $form['staff_oh_' . $i] = array( '#type' => 'textfield', '#default_value' => $staff_oh, '#size' => 15, ); $form['ta_oh_' . $i] = array( '#type' => 'textfield', '#default_value' => $ta_oh, '#size' => 15, ); $form['tutor_oh_' . $i] = array( '#type' => 'textfield', '#default_value' => $tutor_oh, '#size' => 15, ); $i++; } $form['num_people'] = array( '#type' => 'value', '#value' => $i, ); $form['submit'] = array( '#type' => 'submit', '#value' => t("Submit"), ); $form['#theme'] = 'render_ucd_lnl_people_server_office_hours_form'; return $form; } /** * Themes the office hours bulk update form. * Drupal knows to use it because $form['#theme'] is set above. */ function theme_render_ucd_lnl_people_server_office_hours_form($variables) { $head = array( 'Person', 'Faculty OH', 'Staff Advising', 'TA OH', 'Tutor OH', ); $form = $variables['form']; for ($i=0; $i<$form['num_people']['#value']; $i++) { $data[] = array( 'data' => array( drupal_render($form['name_' . $i]), drupal_render($form['faculty_oh_' . $i]), drupal_render($form['staff_oh_' . $i]), drupal_render($form['ta_oh_' . $i]), drupal_render($form['tutor_oh_' . $i]), ) ); } $output = theme('table', array('header' => $head, 'rows' => $data)); $output .= drupal_render_children($form); return $output; } function ucd_lnl_people_server_office_hours_form_submit($form, &$form_state) { //Potentially could be updating a large number of people which may //cause PHP to time out. Use Drupal's Batch API for ($i=0; $i<$form_state['values']['num_people']; $i++) { $values = array( 'current' => $i, 'uid' => $form_state['values']['uid_' . $i], 'faculty_officehours' => $form_state['values']['faculty_oh_' . $i], 'staff_advisinghours' => $form_state['values']['staff_oh_' . $i], 'ta_officehours' => $form_state['values']['ta_oh_' . $i], 'tutor_officehours' => $form_state['values']['tutor_oh_' . $i], ); $operations[] = array( 'ucd_lnl_people_server_office_hours_save', array($values), ); } $batch = array( 'title' => t('Saving office hours...'), 'operations' => $operations, 'finished' => 'ucd_lnl_people_server_office_hours_save_finished', ); batch_set($batch); } /** * Called by batch API to save one person's office hours. */ function ucd_lnl_people_server_office_hours_save($values, &$context) { $current = $values['current']; $user = user_load($values['uid']); unset($values['current']); unset($values['uid']); $change = FALSE; foreach ($values as $key => $value) { $fieldname = 'field_' . $key; if (isset($user->{$fieldname}[LANGUAGE_NONE])) { //a value was set before modifications if ($user->{$fieldname}[LANGUAGE_NONE][0]['value'] != $value) { $change = TRUE; if ($value == "") { //the user deleted the office hours altogether unset($user->{$fieldname}[LANGUAGE_NONE][0]); } else { $user->{$fieldname}[LANGUAGE_NONE][0]['value'] = $value; } } } else { //a value was not set before modifications if ($value) { $change = TRUE; $user->{$fieldname}[LANGUAGE_NONE][0]['value'] = $value; } } } $context['message'] = t('Saving user ' . ($current + 1)); if ($change) { user_save($user); } } function ucd_lnl_people_server_office_hours_save_finished($success, $results, $operations) { drupal_set_message(t('The office hours were saved successfully.')); } /** * Bulk clear office hours. */ function ucd_lnl_people_server_office_hours_clear($user_list) { $user_list_argument = implode($user_list, '+'); $view = views_get_view('people_admin_office_hours_bulk'); $view->set_arguments(array($user_list_argument)); $view->preview(); return drupal_get_form('ucd_lnl_people_server_office_hours_clear_form', $view->result); } function ucd_lnl_people_server_office_hours_clear_form($form, &$form_state, $people) { $i=0; foreach ($people as $person) { $name = $person->field_field_first[0]['rendered']['#markup'] . ' ' . $person->field_field_last[0]['rendered']['#markup']; $faculty_oh = isset($person->field_field_faculty_officehours[0]['raw']['value']) ? $person->field_field_faculty_officehours[0]['raw']['value'] : ""; $staff_oh = isset($person->field_field_staff_advisinghours[0]['raw']['value']) ? $person->field_field_staff_advisinghours[0]['raw']['value'] : ""; $ta_oh = isset($person->field_field_ta_officehours[0]['raw']['value']) ? $person->field_field_ta_officehours[0]['raw']['value'] : ""; $tutor_oh = isset($person->field_field_tutor_officehours[0]['raw']['value']) ? $person->field_field_tutor_officehours[0]['raw']['value'] : ""; $form['uid_' . $i] = array( '#type' => 'value', '#value' => $person->uid, ); $data[] = array( $name, $faculty_oh, $ta_oh, $tutor_oh, ); $i++; } $header = array('name', 'Faculty Office Hours', 'TA Office Hours', 'Tutor Office Hours'); $table = array( '#theme' => 'table', '#header' => $header, '#rows' => $data, ); $table_output = drupal_render($table); $form['confirmprompt'] = array( '#markup' => '

This will delete all of the office hours in the following table!

', ); $form['table'] = array( '#markup' => $table_output, ); $form['num_people'] = array( '#type' => 'value', '#value' => $i, ); return confirm_form($form, t('Are you sure?'), 'myhome/people'); } /** * Clear the office hours with the batch API. Actual save function is the same * as for the bulk office hours update. */ function ucd_lnl_people_server_office_hours_clear_form_submit($form, &$form_state) { //Potentially could be updating a large number of people which may //cause PHP to time out. Use Drupal's Batch API for ($i=0; $i<$form_state['values']['num_people']; $i++) { $values = array( 'current' => $i, 'uid' => $form_state['values']['uid_' . $i], 'faculty_officehours' => "", 'ta_officehours' => "", 'tutor_officehours' => "", ); $operations[] = array( 'ucd_lnl_people_server_office_hours_save', array($values), ); } $batch = array( 'title' => t('Saving office hours...'), 'operations' => $operations, 'finished' => 'ucd_lnl_people_server_office_hours_save_finished', ); batch_set($batch); } /** * Generates PDF for printing phone lists using TCPDF */ /** * Generic function to generate a PDF table, * given header color, column headers, widths, and data array, */ function generate_pdf_table($header_color, $column_specs, $table_data){ //add libraries for TCPDF require_once(libraries_get_path('tcpdf') . '/config/lang/eng.php'); require_once(libraries_get_path('tcpdf') . '/tcpdf.php'); // create new PDF document $pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false); // set document information $pdf->SetCreator(PDF_CREATOR); $pdf->SetAuthor('langlit-web'); $pdf->SetTitle('Phone List'); $pdf->SetSubject('TCPDF Tutorial'); $pdf->SetKeywords('TCPDF, PDF, example, test, guide'); ///////////////////////////////////////////////////////////// // remove default header/footer $pdf->setPrintHeader(false); $pdf->setPrintFooter(false); // set default monospaced font $pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED); //set margins $pdf->SetMargins(PDF_MARGIN_LEFT, 10, PDF_MARGIN_RIGHT); //set auto page breaks $pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM); //set image scale factor $pdf->setImageScale(PDF_IMAGE_SCALE_RATIO); // --------------------------------------------------------- // set font $pdf->SetFont('helvetica', '', 12); // add a page $pdf->AddPage(); // set cell margins $pdf->setCellPaddings(2, 2, 2, 2); //Column titles $pdf->SetFillColor($header_color[0],$header_color[1],$header_color[2]); //create a second PDF for size testing $temp_pdf = clone $pdf; //********************* //Should be removed from this function and added as parameter $title = '' . variable_get('phone_list_title') . ''; //print title of table $pdf->writeHTML($title . '

', true, false, false, false, 'L'); //print table header $pdf = print_header($column_specs, $pdf); //print data to table row by row foreach ($table_data as $row) { $max_row_height = 0; $i = 0; $last = 0; //add a new page in test PDF $temp_pdf->AddPage(); //print row cell-by-cell to temp PDF, find max cell height foreach ($row as $cell) { $cell = nl2br($cell); if ($i == count($column_specs) - 1) { $last = 1; } $temp_pdf->WriteHTMLCell($column_specs[$i]['width'], 1, '', '', $cell, 1, $last, false, true, 'L', true); $i++; $max_row_height = max($max_row_height, $temp_pdf->getLastH()); } //clear temp PDF $temp_pdf->deletePage($temp_pdf->getPage()); //check if row will fit on current page if ($pdf->GetY() + $max_row_height > $pdf->getPageHeight() - PDF_MARGIN_BOTTOM) { //if not, add page and print table header $pdf->AddPage(); //$pdf->writeHTML($title, true, false, false, false, 'L'); $pdf = print_header($column_specs, $pdf); } //print row to actual PDF $i = 0; $last = 0; foreach ($row as $cell) { $cell = nl2br($cell); //if cell is last in row, reset cursor to next line if ($i == count($column_specs) - 1) { $last = 1; } $pdf->WriteHTMLCell($column_specs[$i]['width'], $max_row_height, '', '', $cell, 1, $last, false, true, 'L', true); $i++; } } //output complete pdf $pdf->Output('example_011.pdf', 'I'); } /** * Generic function to print the header row for the table */ function print_header($column_specs, $pdf){ $len = count($column_specs); $i = 0; $last = 0; //print each column one-by-one foreach ($column_specs as $column){ //when we reach the last column, move cursor to next row if ($i == $len-1) { $last = 1; } $pdf->MultiCell($column['width'], 10, $column['title'], 1, 'L', true, $last, '', '', true, 0, false, true, 0, 'M'); $i++; } return $pdf; } /** * Function for generating phone list PDF */ function ucd_lnl_people_server_phonepdf($list_type, $user_list = NULL) { //add libraries for tcpdf require_once(libraries_get_path('tcpdf') . '/config/lang/eng.php'); require_once(libraries_get_path('tcpdf') . '/tcpdf.php'); //public list or confidential list if ($list_type == 'phone_public') { $view = views_get_view('people_admin_phone_list'); } elseif ($list_type == 'phone_conf') { $view = views_get_view('people_admin_phone_list_conf'); } //get people data given list of uid's $view->set_arguments(array($user_list)); $view->preview(); $people_list = $view->result; //initialize widths and titles of table columns $column_specs = array( array( 'width' => 63, 'title' => "Person"), array( 'width' => 30, 'title' => "Office"), array( 'width' => 50, 'title' => "Office Phone"), array( 'width' => 40, 'title' => "Office Hours")); $table_data = array(); $i = 0; //parse data for each person and store in an array to pass to PDF function foreach ($people_list as $person_data){ //add each field to $row array. 1 row = 1 person. $row = array(); //name, titles, email $person = "" . $person_data->field_field_first[0]['raw']['value'] . " " . $person_data->field_field_last[0]['raw']['value'] . "\n"; foreach ($person_data->field_field_titles as $title) { $person .= $title['raw']['value'] . "\n"; }//foreach $person .= ""; if (strlen($person_data->users_mail) > 27) { $person .= '' . $person_data->users_mail . ''; } else { $person .= $person_data->users_mail; } $row[0] = $person; //office building + room number $office = count($person_data->field_field_office2[0]) > 1 ? $person_data->field_field_office2[0]['rendered']['entity']['field_collection_item'][$person_data->field_field_office2[0]['raw']['value']]['field_office2_room'][0]['#markup'] . " " . $person_data->field_field_office2[0]['rendered']['entity']['field_collection_item'][$person_data->field_field_office2[0]['raw']['value']]['field_office2_building'][0]['#markup'] : ""; $row[1] = $office; //phone numbers $phone_number = $person_data->field_field_phone ? $person_data->field_field_phone[0]['raw']['value'] : ""; //if confidential list, add additional phone numbers if ($list_type == 'phone_conf') { $column_specs[2]['title'] = "Phone Numbers"; if ($person_data->field_field_phone) { $phone_number = "Office: " . $phone_number . "
"; } if ($person_data->field_field_person_conf_homephone) { $phone_number .= "Home: " . str_replace("1 ", "", $person_data->field_field_person_conf_homephone[0]['raw']['value']) . "
"; } if ($person_data->field_field_person_conf_mobilephone) { $phone_number .= "Mobile: " . str_replace("1 ", "", $person_data->field_field_person_conf_mobilephone[0]['raw']['value']); } } $row[2] = $phone_number; //office hours if ($person_data->field_field_faculty_officehours) { $office_hours = $person_data->field_field_faculty_officehours[0]['raw']['value']; }//if elseif ($person_data->field_field_ta_officehours) { $office_hours = $person_data->field_field_ta_officehours[0]['raw']['value']; }//elseif elseif ($person_data->field_field_tutor_officehours) { $office_hours = $person_data->field_field_tutor_officehours[0]['raw']['value']; }//elseif elseif ($person_data->field_field_staff_schedule) { $office_hours = $person_data->field_field_staff_schedule[0]['raw']['value']; if ($person_data->field_field_staff_advisinghours) { $office_hours = "Regular Schedule:
" . $office_hours . "Advising Schedule:
" . $person_data->field_field_staff_advisinghours[0]['raw']['value']; }//if }//elseif else { $office_hours = ""; } $row[3] = $office_hours; //add person/row to table data $table_data[$i] = $row; $i++; }//foreach //Assign rgb triplet to color for header $color_name = variable_get('phone_list_color'); switch ($color_name) { case 0: $rgb_color = array(135,206,250); break; case 1: $rgb_color = array(153,255,153); break; case 2: $rgb_color = array(255,102,102); break; case 3: $rgb_color = array(192,192,192); break; case 4: $rgb_color = array(218,165,32); break; } //generate table from given data generate_pdf_table($rgb_color, $column_specs, $table_data); }//function function ucd_lnl_people_server_PDF_settings($type, $user_list) { return drupal_get_form('ucd_lnl_people_server_PDF_settings_form', $type, $user_list); } function ucd_lnl_people_server_PDF_settings_form($form, &$form_state, $type, $user_list) { $form = array(); $form['title'] = array( '#type' => 'textfield', '#title' => t('Enter the title of the phone list (required) e.g \'Spanish Confidential Phone List\''), '#size' => 60, '#maxlength' => 128, '#required' => TRUE, ); $colors = array('Blue', 'Green', 'Red', 'Gray', 'Gold'); $form['color'] = array( '#type' => 'radios', '#title' => t('Select a color for the PDF if printing'), '#default_value' => 'Blue', '#options' => $colors, ); $form['storage1'] = array( '#type' => 'value', '#value' => $type, ); $form['storage2'] = array( '#type' => 'value', '#value' => $user_list, ); $form['submit'] = array( '#type' => 'submit', '#value' => t('Submit'), ); return $form; } function ucd_lnl_people_server_PDF_settings_form_submit($form, &$form_state) { variable_set('phone_list_title', $form_state['values']['title']); variable_set('phone_list_color', $form_state['values']['color']); drupal_goto('myhome/people/' . $form_state['values']['storage1'] . '/print/' . $form_state['values']['storage2']);// . '/' . $form_state['values']['title'] . '/' . $form_state['values']['color']); } /** * Override the view's default title */ /* This approach no longer works because the view can return any people rather than just a single department. Will add a place for the user to set the title of the result later. function ucd_lnl_people_server_preprocess_views_view(&$variables) { $view = $variables['view']; if ($view->name == 'people_admin_phone_list' && $view->current_display == 'print') { if (isset($view->args[0])) { $dept_node = node_load($view->args[0]); $variables['view']->build_info['title'] = ucfirst($dept_node->title) . ' Dept/Program Contact List'; } } if ($view->name == 'people_admin_phone_list_conf' && $view->current_display == 'print') { if (isset($view->args[0])) { $dept_node = node_load($view->args[0]); $variables['view']->build_info['title'] = ucfirst($dept_node->title) . ' Dept/Program Confidential Contact List'; } } } */ /** * Saves new user information to the old GAPS database. Once all sites are * converted, this function should be removed. */ /* function ucd_lnl_people_server_user_insert(&$edit, $account, $category) { ucd_lnl_people_server_gaps_update($account); } */ /** * Saves changes on user edit to the old GAPS database. Once all sites are * converted, this function should be removed. */ /* function ucd_lnl_people_server_user_update(&$edit, $account, $category) { ucd_lnl_people_server_gaps_update($account); } */ /* * Prepares the data to be inserted or updated in GAPS */ /* function ucd_lnl_people_server_gaps_update($account) { //prep variables //required fields $dept_node = node_load($account->field_home_dept[LANGUAGE_NONE][0]['target_id']); $depts_lookup = array_flip(ucd_lnl_people_server_depts()); $dept_site = $dept_node->field_dept_website[LANGUAGE_NONE][0]['url']; $home_dept = $depts_lookup[$dept_site]; $main_title = $account->field_titles[LANGUAGE_NONE][0]['value']; $person_name = $account->field_last[LANGUAGE_NONE][0]['value'] . ", " . $account->field_first[LANGUAGE_NONE][0]['value']; $email_array = explode('@', $account->mail); if ($email_array[1] == 'college.edu') { $campus_email = strtolower($email_array[0]) . '@'; $noncampus_email = ""; } else { $noncampus_email = strtolower($account->mail); $campus_email = ""; } */ //office hours //precedence: faculty > staff advising hours > staff regular schedule > ta > tutor /*isset($account->field_tutor_officehours[LANGUAGE_NONE][0]['value']) ? $office_hours = $account->field_tutor_officehours[LANGUAGE_NONE][0]['value'] : ""; isset($account->field_ta_officehours[LANGUAGE_NONE][0]['value']) ? $office_hours = $account->field_ta_officehours[LANGUAGE_NONE][0]['value'] : ""; isset($account->field_staff_schedule[LANGUAGE_NONE][0]['value']) ? $office_hours = $account->field_staff_schedule[LANGUAGE_NONE][0]['value'] : ""; isset($account->field_staff_advisinghours[LANGUAGE_NONE][0]['value']) ? $office_hours = $account->field_staff_advisinghours[LANGUAGE_NONE][0]['value'] : ""; isset($account->field_faculty_officehours[LANGUAGE_NONE][0]['value']) ? $office_hours = $account->field_faculty_officehours[LANGUAGE_NONE][0]['value'] : ""; if (!isset($office_hours)) { $office_hours = ""; } //other optional fields $office = isset($account->field_office[LANGUAGE_NONE][0]['value']) ? $account->field_office[LANGUAGE_NONE][0]['value'] : ""; $campus_phone = isset($account->field_phone[LANGUAGE_NONE][0]['value']) ? $account->field_phone[LANGUAGE_NONE][0]['value'] : ""; $active = $account->status; //connect to GAPS database $table = "people"; $db = pg_connect('user=postgres dbname=directory host=169.169.xxx.xxx password=some_password'); if (!$db) { die("Unable to connect to postgres database"); } if ($account->is_new) { //build the query $sql = sprintf("INSERT INTO $table ( home_dept, main_title, person_name, office_hours, office, campus_email, noncampus_email, campus_phone, active) VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%d')", pg_escape_string($home_dept), pg_escape_string($main_title), pg_escape_string($person_name), pg_escape_string($office_hours), pg_escape_string($office), pg_escape_string($campus_email), pg_escape_string($noncampus_email), pg_escape_string($campus_phone), $active); } else { //this is an update if ($person_id = _ucd_lnl_people_server_gaps_lookup($account, $db, $table)) { $sql = sprintf("UPDATE $table SET home_dept = '%s', main_title = '%s', person_name = '%s', office_hours = '%s', office = '%s', campus_email = '%s', noncampus_email = '%s', campus_phone = '%s', active = '%d' WHERE person_id = '%d'", pg_escape_string($home_dept), pg_escape_string($main_title), pg_escape_string($person_name), pg_escape_string($office_hours), pg_escape_string($office), pg_escape_string($campus_email), pg_escape_string($noncampus_email), pg_escape_string($campus_phone), $active, $person_id); } } //execute the insert/update query if (isset($sql) && !$result = pg_query($db, $sql)) { drupal_set_message("The update to the old GAPS database failed. You will need to manually create the changes in GAPS. The query was: $sql
The error was: " . pg_last_error(), 'error'); return FALSE; } else { return TRUE; } } */ /** * This helper function returns a GAPS person_id if it can find a record * associted with an email address. Returns false otherwise. * @params * account: A fully populated Drupal account object * db: An open PostGres db connection * table: String with the name of the table */ /*function _ucd_lnl_people_server_gaps_lookup($account, $db, $table) { //we have no unique data, so we have to use either campus email or noncampus email //search for the person in GAPS $old_email_array = explode('@', $account->original->mail); if ($old_email_array[1] == 'college.edu') { $old_email = strtolower($old_email_array[0]) . '@'; $person_id_sql = sprintf("SELECT person_id FROM $table WHERE campus_email = '%s'", $old_email); } else { $person_id_sql = sprintf("SELECT person_id FROM $table WHERE noncampus_email = '%s'", strtolower($account->original->mail)); //dsm($person_id_sql); } if ($person_result = pg_fetch_assoc(pg_query($db, $person_id_sql))) { return $person_result['person_id']; } else { return FALSE; } } */ /** * Implementation of hook_user_delete * * This removes the people_conf and grad_conf content associated with a user * if their account is deleted entirely to prevent orphaned data. */ function ucd_lnl_people_server_user_delete($account) { $uid = $account->uid; $grad_supplementals = views_get_view('grad_supplemental_for_user'); $grad_supplementals->set_arguments(array($uid)); $grad_supplementals->preview(); $grad_supplementals_results = $grad_supplementals->result; foreach ($grad_supplementals_results as $grad_supplementals_result) { node_delete($grad_supplementals_result->nid); } $people_supplementals = views_get_view('people_supplemental_for_user'); $people_supplementals->set_arguments(array($uid)); $people_supplementals->preview(); $people_supplementals_results = $people_supplementals->result; foreach ($people_supplementals_results as $people_supplementals_result) { node_delete($people_supplementals_result->nid); } } /** * Alter the new user register form to make the password box optional and auto-generate * the user name based on the first and last name fields (via the validate function). */ function ucd_lnl_people_server_form_user_register_form_alter(&$form, &$form_state, $form_id) { global $user; if ($user->uid != 1) { $form['account']['name']['#type'] = 'value'; $form['account']['name']['#required'] = false; } $form['account']['pass']['#required'] = false; $form['account']['pass']['#description'] .= t(' If no password is provided, a random one will be generated. Useful for adding CAS users where users do not use this password to log in.'); //Make the CAS ID required unless the user is root - if no CAS ID, people won't be able to log in. if ($user->uid != 1) { $form['account']['cas_name']['#required'] = TRUE; } //this ensures that the below validate function (which alters values) get called before the Drupal default array_unshift($form['#validate'], 'ucd_lnl_people_server_form_user_register_form_validate'); } function ucd_lnl_people_server_form_user_register_form_validate(&$form, &$form_state) { //the following should be true for everyone except user 1 who can still see the user name field if ($form_state['values']['name'] == "") { $form_state['values']['name'] = $form_state['values']['field_first'][LANGUAGE_NONE][0]['value'] . " " . $form_state['values']['field_last'][LANGUAGE_NONE][0]['value']; } if ($form_state['values']['pass'] == "") { $form_state['values']['pass'] = user_password(); } } /** * Alters the user edit form based on what permissions the person has. * Some things affect everyone (system wide) and some only take affect if the person * does not have the Administer UCD profiles permission. */ function ucd_lnl_people_server_form_user_profile_form_alter(&$form, &$form_state, $form_id) { /* User form modifications that apply to users without the 'administer ucd people profiles' permission */ global $user; if (!user_access('administer ucd people profiles')) { //remove the change password options $form['account']['pass']['#access'] = FALSE; $form['account']['current_pass']['#access'] = FALSE; //remove the option for the user to change their overlay settings. $form['overlay_control']['#access'] = FALSE; //hide all of the below fields $form['account']['mail']['#access'] = FALSE; $form['field_admin_group']['#access'] = FALSE; $form['field_depts']['#access'] = FALSE; $form['field_home_dept']['#access'] = FALSE; //$form['field_titles'] = FALSE; /* this may be needed later if people start randomly changing their titles */ } } /* * All of the below code exposes json data for department lists * and profiles that is used by the ucd_lnl_people module. */ /* * Implements hook_services_resources(). * (depends on Services module - see a good tutorial here: http://drupal.org/node/783460) */ function ucd_lnl_people_server_services_resources() { return array( 'profile' => array( 'retrieve' => array( 'help' => t('Retrieves a user profile'), 'callback' => '_ucd_lnl_people_server_get_profile', 'access callback' => 'user_access', 'access arguments' => array('access user profiles'), 'args' => array( array( 'name' => 'uid', 'type' => 'int', 'description' => t('The uid of the profile to retrieve'), 'source' => array('path' => '0'), 'optional' => FALSE, 'default value' => 0, ), ), ), 'actions' => array( 'list' => array( 'help' => t('Retrieves a listing of users in a department'), 'callback' => '_ucd_lnl_people_server_dept_list', 'access arguments' => array('access user profiles'), 'args' => array( array( 'name' => 'dept', 'optional' => TRUE, 'type' => 'string', 'description' => t('Short name of the department.'), 'default value' => '', 'source' => array('param' => 'dept'), ), ), ), ), ), ); } /* * Retrieves a profile (and services takes care of the JSON conversion). * @params * $uid - the first argument returned by services (unsafe value). */ function _ucd_lnl_people_server_get_profile ($uid) { //dd is really helpful for logging when you don't get any visual output. //it is supplied by devel and logs to /tmp/drupal_debug.txt //dd(get_defined_vars()); if(!(int) $uid) { return services_error('Missing profile id.', 406); } $profile = user_load($uid); unset($profile->pass); //casting the profile to array makes it easier to work with. $profile_array = (array) $profile; //dd($profile_array); //field_collection_items only show an entity ID for the value //so we need to load these entities and pump them into the array. $field_collections = field_info_instances(); foreach(array_keys($field_collections['field_collection_item']) AS $field_collection_key) { if ($profile_array[$field_collection_key] != NULL) { $lang_array = $profile_array[$field_collection_key]; foreach($lang_array[LANGUAGE_NONE] AS $key => $field_collection_value) { $entity = entity_load('field_collection_item', array($field_collection_value['value'])); $profile_array[$field_collection_key][LANGUAGE_NONE][$key] = (array) $entity[$field_collection_value['value']]; } } } //the user reference field only shows the uid of the referenced person so we need //to replace this with a name. if (isset($profile_array['field_depts'])) { for ($i=0; $i < count($profile_array['field_depts'][LANGUAGE_NONE]); $i++) { $dept_node = node_load($profile_array['field_depts'][LANGUAGE_NONE][$i]['target_id']); $profile_array['field_depts'][LANGUAGE_NONE][$i]['value'] = $dept_node->title; } } //the field_office2_building is a node reference that also doesn't get pumped in if (isset($profile_array['field_office2'])) { foreach ($profile_array['field_office2'][LANGUAGE_NONE] AS $key => $office) { $nid = $office['field_office2_building'][LANGUAGE_NONE][0]['target_id']; $bldg_node = node_load($nid); $profile_array['field_office2'][LANGUAGE_NONE][$key]['field_office2_building'] = $bldg_node; } } return $profile_array; } /* * Retrieves a list of people in a department (and services provides the JSON etc). * @params * $dept: the website of the department (minus the http://) */ function _ucd_lnl_people_server_dept_list ($dept) { $dept_list = views_get_view('people_in_dept'); $dept_list->set_arguments(array($dept)); $dept_list->preview(); //dd(get_defined_vars()); $results = $dept_list->result; foreach($results AS $result) { //remove the user object from the results before sending unset($result->_field_data); } return $results; } /* * Provides an array of departments matching old department codes * to new websites. After all websites have been converted, this function * should be removed. * * Redacted, obviously. */ function ucd_lnl_people_server_depts() { $departments = array( "AAA" => "website1.college.edu", "BBB" => "website2.college.edu" ); return $departments; }

The client module:

/**
 * @file
 * UCD LNL People Client Module
 * Pulls people from the UCD Langlit database and
 * displays them.
 */

/*
 * Implementation of hook_menu().
 */
function ucd_lnl_people_menu() {
  $items = array();

  $items['people/profile/%'] = array(
    'title' => t('Profile'),
    'description' => t('Profile'),
    'page callback' => 'ucd_lnl_people_profile',
    'page arguments' => array(2),
    'access arguments' => array('access content'),
  );
  $items['admin/config/people/ucd_lnl_people'] = array(
    'title' => t('UCD LNL People Settings'),
    'description' => t('Configure server, data, and display settings for the UCD LNL People client module'),
    'file' => 'ucd_lnl_people.admin.inc',
    'page callback' => 'ucd_lnl_people_admin',
    'access arguments' => array('administer ucd_lnl_people'),
    'type' => MENU_NORMAL_ITEM,
  );
  $items['admin/config/people/ucd_lnl_people/display/add'] = array(
    'title' => t('Add Display'),
    'description' => t('Add a ucd_lnl_people display'),
    'file' => 'ucd_lnl_people.admin.inc',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('ucd_lnl_people_admin_display_form'),
    'access arguments' => array('administer ucd_lnl_people'),
    'type' => MENU_NORMAL_ITEM,
  );
  $items['admin/config/people/ucd_lnl_people/display/%/edit'] = array(
    'title' => t('Edit Display'),
    'description' => t('Edit a ucd_lnl_people display'),
    'file' => 'ucd_lnl_people.admin.inc',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('ucd_lnl_people_admin_display_form', 5),
    'access arguments' => array('administer ucd_lnl_people'),
    'type' => MENU_NORMAL_ITEM,
  );
  $items['admin/config/people/ucd_lnl_people/display/%/del'] = array(
    'title' => t('Delete'),
    'description' => t('Delete a ucd_lnl_people display'),
    'file' => 'ucd_lnl_people.admin.inc',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('ucd_lnl_people_admin_display_del_form', 5),
    'access arguments' => array('administer ucd_lnl_people'),
    'type' => MENU_NORMAL_ITEM,
  );
  $items['admin/config/people/ucd_lnl_people/display/%/group/add'] = array(
    'title' => t('Add Display Group'),
    'description' => t('Add a ucd_lnl_people display group'),
    'file' => 'ucd_lnl_people.admin.inc',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('ucd_lnl_people_admin_group_form', 5),
    'access arguments' => array('administer ucd_lnl_people'),
    'type' => MENU_NORMAL_ITEM,
  );
  $items['admin/config/people/ucd_lnl_people/display/%/group/%/edit'] = array(
    'title' => t('Edit Display Group'),
    'description' => t('Edit a ucd_lnl_people display group'),
    'file' => 'ucd_lnl_people.admin.inc',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('ucd_lnl_people_admin_group_form', 5, 7),
    'access arguments' => array('administer ucd_lnl_people'),
    'type' => MENU_NORMAL_ITEM,
  );
  $items['admin/config/people/ucd_lnl_people/display/%/group/%/del'] = array(
    'title' => t('Delete Display Group'),
    'description' => t('Delete a ucd_lnl_people display group'),
    'file' => 'ucd_lnl_people.admin.inc',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('ucd_lnl_people_admin_group_del_form', 5, 7),
    'access arguments' => array('administer ucd_lnl_people'),
    'type' => MENU_NORMAL_ITEM,
  );

  return $items;
}

/*
 * Implementation of hook_permission()
 */
function ucd_lnl_people_permission() {
  return array(
    'administer ucd_lnl_people' => array(
      'title' => t('Administer the UCD LNL People module'),
      'description' => t('Configure server, data and display settings for the UCD LNL People client module.'),
    ),
  );
}

/*
 * Login a user to the UCD LNL People Server.
 * This user must have permission to view profiles.
 */
function ucd_lnl_people_login() {
  $services_endpoint_url = variable_get('ucd_lnl_people_server') . '/services/ucd_lnl_people';
  if (!valid_url($services_endpoint_url, TRUE)) {
    drupal_set_message(t("The UCD LNL People Server URL is invalid.  Please correct and try again."), 'error');
    return false;
  }
  $data = array(
    'username' => variable_get('ucd_lnl_people_server_user'),
    'password' => variable_get('ucd_lnl_people_server_pass'),
  );

  $data = http_build_query($data, '', '&');
  $headers = array();
  $options = array(
    'headers' => array(
      'Accept' => 'application/json',
    ),
    'method' => 'POST',
    'data' => $data,
  );

  $response = drupal_http_request($services_endpoint_url . '/user/login', $options);
  $data = json_decode($response->data);

  if ($response->code == 200) {
    return $data;
  }
  else {
    drupal_set_message(t("Unable to log into the UCD LNL People Server.  Please check your settings."), 'error');
    //dsm($response);
    return FALSE;
  }
}

/*
 * Queries the server for a list of people in a department and displays it.
 * @params
 *   $dept: URL of the site minus http:// (e.g. website1.colleg.edu).  
 *   If not specified, defaults to the current site.
 */
function ucd_lnl_people_list($display = NULL) {
  //If no display is defined, return not found.
  if ($display) {
    $query = db_select('ucd_lnl_people_displays', 'd');
    $query->fields('d');
    $query->condition('d.name', $display, '=');
    $result = $query->execute();
    $result = $result->fetchAssoc();
  }
  if (!isset($result['did'])) {
    drupal_set_message(t('Display ' . check_plain($display) . ' was not found'), 'error');
    drupal_access_denied();
    drupal_goto('');
  }
  else {
    $dept = $result['depts'];
  
    //get the list of people from the server
    $data = _ucd_lnl_people_list_retrieve($dept);
  
    if (!$data) {
      drupal_set_message(t('No data received from the UCD LNL People Server. Check your settings ') . l('here.', 'admin/config/people/ucd_lnl_people'), 'error');
      return "No data received from the server.";
    }
    else {
      $output = "";
  
      //retrieve the display groups for this display from the database
      $groups = db_select('ucd_lnl_people_display_groups', 'g')
        ->fields('g')
        ->condition('g.did', $result['did'], '=')
        ->orderBy('weight', 'ASC')
        ->execute();

      while($group = $groups->fetchAssoc()) {
        $group_admin_groups = unserialize($group['admin_groups']);
        $group_people = array();
        foreach ($data as $person) {
          foreach ($person['field_field_admin_group'] as $person_admin_group) {
            if (isset($group_admin_groups[$person_admin_group['raw']['value']])) {
              if ($group_admin_groups[$person_admin_group['raw']['value']]) {
                $group_people[$person['uid']] = $person;
              }
            }
          }
        }

        if (count($group_people)) {
          $output .= _ucd_lnl_people_list_display_table($group['title'], $group_people);
        }
      }
  
      return $output;
    }
  }
}

/**
 * Retrieves the list of people in the department from the server
 *  @return
 *    An array of people in the department
 */
function _ucd_lnl_people_list_retrieve($dept = null) {
  //Log in
  $login_response = ucd_lnl_people_login();

  $ucd_lnl_people_server = variable_get('ucd_lnl_people_server');
  $raw_ucd_lnl_people_server = str_replace("http://", "", $ucd_lnl_people_server); //without the http://

  //if dept isn't specified use the site URL
  if (!$dept) {
    global $base_url;
    $site = str_replace("http://", "", $base_url);
    $site = str_replace("https://", "", $site);
    $site = str_replace("-dev", "", $site);
  }
  else {
    $site = $dept;
  }

  $list_url = $ucd_lnl_people_server . '/services/ucd_lnl_people/profile/list?dept=' . $site;
  $options = array(
    'headers' => array(
      'Content-Type' => 'multipart/form-data; boundary=----------1234567890',
      'Cookie' => $login_response->session_name . '=' . $login_response->sessid,
    ),
    'method' => 'POST',
    'data' => '----------1234567890',
  );

  $response = drupal_http_request($list_url, $options);
  $data = drupal_json_decode($response->data);

  return $data;
}

/**
 * Displays a single people table (multiple may be displayed if
 * the department has opted to separate them by admin groups via settings page.)
 */
function _ucd_lnl_people_list_display_table($table_title, $data) {
  //dsm($data);
  $ucd_lnl_people_server = variable_get('ucd_lnl_people_server');

  $people_header = array(
    array('data' => 'Photo'),
    array('data' => 'Person'),
    array('data' => 'Contact Information'),
  );
  foreach($data AS $person) {
    //display the photo if available, otherwise display no photo available.
    if(isset($person['field_field_photo'][0]['raw']['uri'])) {
      $photos_sub_dir = '/sites/default/files/styles/person_profile_list/public/';
      
      //$person['field_field_photo'][0]['raw']['uri'] = '/sites/default/files/styles/' . image_style_url('person_profile_list', $person['field_field_photo'][0]['raw']['uri']);

      $person['field_field_photo'][0]['raw']['uri'] = str_replace("public://", $ucd_lnl_people_server . $photos_sub_dir, $person['field_field_photo'][0]['raw']['uri']);

      $photo_output = "";
    }
    else {
      $photo_output = "No photo.";
    }

    //display name and titles
    $name_output = "

" . l($person['field_data_field_first_field_first_value'] . " " . $person['field_data_field_last_field_last_value'], 'people/profile/' . $person['uid']) . "
"; foreach ($person['field_field_titles'] AS $title) { $name_output .= $title['raw']['safe_value'] . "
"; } $name_output .= "

"; //display contact info $info_output = "

"; $info_output .= "Email: " . $person['users_mail']; if(isset($person['field_field_phone'][0]['raw']['value'])) { $info_output .= "
Phone: " . $person['field_field_phone'][0]['raw']['value']; } if(isset($person['field_field_office2'][0]['raw'])) { $info_output .= "
Office(s): "; $links = array(); foreach ($person['field_field_office2'] as $key => $value) { $id = $value['raw']['value']; $data = $value['rendered']['entity']['field_collection_item'][$id]; $bldg_name = $data['field_office2_building'][0]['#markup']; $map_link = $data['#entity']['field_office2_building'][LANGUAGE_NONE][0]['entity']['field_bldg_map_link'][LANGUAGE_NONE][0]['url']; $office_num = $data['field_office2_room'][0]['#markup']; $links[] = "" . $office_num . " " . $bldg_name . ""; } $info_output .= implode(", ", $links); } if(isset($person['field_field_faculty_officehours'][0]['raw']['safe_value'])) { $info_output .= "
Office Hours: " . $person['field_field_faculty_officehours'][0]['raw']['safe_value'] . ""; } if(isset($person['field_field_ta_officehours'][0]['raw']['safe_value'])) { $info_output .= "
Office Hours: " . $person['field_field_ta_officehours'][0]['raw']['safe_value'] . ""; } if(isset($person['field_field_tutor_officehours'][0]['raw']['safe_value'])) { $info_output .= "
Office Hours: " . $person['field_field_tutor_officehours'][0]['raw']['safe_value'] . ""; } if(isset($person['field_field_staff_advisinghours'][0]['raw']['safe_value'])) { $info_output .= "
Advising Hours: " . $person['field_field_staff_advisinghours'][0]['raw']['safe_value'] . ""; } if(isset($person['field_field_staff_schedule'][0]['raw']['safe_value'])) { $info_output .= "
Regular Schedule: " . $person['field_field_staff_schedule'][0]['raw']['safe_value'] . ""; } $info_output .= "

"; $people_data[] = array( 'data' => array( array('data' => $photo_output, 'class' => 'photo'), array('data' => $name_output, 'class' => 'person_info'), array('data' => $info_output, 'class' => 'contact_info'), ), ); } $table_output = theme('table', array( 'header' => $people_header, 'rows' => $people_data, 'attributes' => array('class' => array('people_list')), )); $title_output = "

" . $table_title . "

\n"; return $title_output . $table_output; } /* * Implementation of hook_theme(). */ function ucd_lnl_people_theme() { return array( 'ucd_lnl_profile' => array( 'variables' => array('profile' => NULL), 'template' => 'ucd_lnl_profile', ), 'multiple_text_field' => array( 'variables' => array('field_name' => NULL, 'field_values' => NULL), 'function' => 'ucd_lnl_people_theme_mtext', ), 'multiple_text_area' => array( 'variables' => array('field_name' => NULL, 'field_values' => NULL), 'function' => 'ucd_lnl_people_theme_mtextarea', ), 'field_education' => array( 'variables' => array('field_name' => NULL, 'field_values' => NULL, 'type' => 'faculty'), 'function' => 'ucd_lnl_people_theme_education', ), 'field_office2' => array( 'variables' => array('field_name' => NULL, 'field_values' => NULL), 'function' => 'ucd_lnl_people_theme_office2', ), 'ucd_lnl_people_admin_display_form' => array( 'render element' => 'form', ), ); } /* * Process the unsightly profile array to make the variables easier to access * in ucd_lnl_profile.tpl.php. */ function ucd_lnl_people_preprocess_ucd_lnl_profile(&$variables) { $lang = LANGUAGE_NONE; $profile = $variables['profile']; //add the variables to the root level variables without the nesting foreach($profile as $key => $value) { if (substr($key, 0, 6) == "field_") { if(isset($value[$lang])) { $variables[$key] = array_merge($value[$lang]); } } else { $variables[$key] = $value; } } //this is a required field so it should always exist $variables['field_titles'] = theme('multiple_text_field', array('field_name' => 'field_titles', 'field_values' => $variables['field_titles'])); //the rest of these fields are optional and thus may or may not exist if (isset($variables['field_staff_departments'])) { $variables['field_depts'] = theme('multiple_text_field', array('field_name' => 'field_depts', 'field_values' => $variables['field_depts'])); } if (isset($variables['field_office2'])) { $variables['field_office2'] = theme('field_office2', array('field_name' => 'field_office2', 'field_values' => $variables['field_office2'])); } //faculty fields if (isset($variables['field_staff_departments'])) { $variables['field_staff_departments'] = theme('multiple_text_field', array('field_name' => 'field_staff_departments', 'field_values' => $variables['field_staff_departments'])); } if (isset($variables['field_faculty_education'])) { $variables['field_faculty_education'] = theme('field_education', array('field_name' => 'field_faculty_education', 'field_values' => $variables['field_faculty_education'], 'type' => 'faculty')); } if (isset($variables['field_faculty_research'])) { $variables['field_faculty_research'] = theme('multiple_text_field', array('field_name' => 'field_faculty_research', 'field_values' => $variables['field_faculty_research'])); } if (isset($variables['field_faculty_courses'])) { $variables['field_faculty_courses'] = theme('multiple_text_field', array('field_name' => 'field_faculty_courses', 'field_values' => $variables['field_faculty_courses'])); } if (isset($variables['field_faculty_service'])) { $variables['field_faculty_service'] = theme('multiple_text_field', array('field_name' => 'field_faculty_service', 'field_values' => $variables['field_faculty_service'])); } if (isset($variables['field_faculty_honors2'])) { $variables['field_faculty_honors2'] = theme('multiple_text_field', array('field_name' => 'field_faculty_honors2', 'field_values' => $variables['field_faculty_honors2'])); } if (isset($variables['field_faculty_publications'])) { $variables['field_faculty_publications'] = theme('multiple_text_area', array('field_name' => 'field_faculty_publications', 'field_values' => $variables['field_faculty_publications'])); } //grad student fields if (isset($variables['field_grad_education'])) { $variables['field_grad_education'] = theme('field_education', array('field_name' => 'field_grad_education', 'field_values' => $variables['field_grad_education'], 'type' => 'grad')); } if (isset($variables['field_grad_research'])) { $variables['field_grad_research'] = theme('multiple_text_field', array('field_name' => 'field_grad_research', 'field_values' => $variables['field_grad_research'])); } if (isset($variables['field_grad_honors2'])) { $variables['field_grad_honors2'] = theme('multiple_text_field', array('field_name' => 'field_grad_honors2', 'field_values' => $variables['field_grad_honors2'])); } if (isset($variables['field_grad_courses'])) { $variables['field_grad_courses'] = theme('multiple_text_field', array('field_name' => 'field_grad_courses', 'field_values' => $variables['field_grad_courses'])); } if (isset($variables['field_grad_publications'])) { $variables['field_grad_publications'] = theme('multiple_text_area', array('field_name' => 'field_grad_publications', 'field_values' => $variables['field_grad_publications'])); } //ta fields if (isset($variables['field_ta_courses'])) { $variables['field_ta_courses'] = theme('multiple_text_field', array('field_name' => 'field_ta_courses', 'field_values' => $variables['field_ta_courses'])); } } /* * Queries for a profile from the server, passes to theme function for rendering and displays it. * To theme the output (other than CSS theming), copy ucd_lnl_profile.tpl.php from this module's * directory, place into theme's directory and modify. * * @param $uid * The remote site's uid for the user to be displayed. */ function ucd_lnl_people_profile($uid) { $ucd_lnl_people_server = variable_get('ucd_lnl_people_server'); $raw_ucd_lnl_people_server = str_replace("http://", "", $ucd_lnl_people_server); //without the http:// if (!$uid || !is_numeric($uid)) { drupal_access_denied(); } $login_response = ucd_lnl_people_login(); $profile_url = $ucd_lnl_people_server . '/services/ucd_lnl_people/profile/' . $uid; $options = array( 'headers' => array( 'Content-Type' => 'multipart/form-data; boundary=----------1234567890', 'Cookie' => $login_response->session_name . '=' . $login_response->sessid, ), 'method' => 'GET', 'data' => '----------1234567890', ); $response = drupal_http_request($profile_url, $options); $profile_array = drupal_json_decode($response->data); //dsm($profile_array); if (!$profile_array) { return "Profile not found."; } //replace a few public:// urls with the URL of the external server site if (isset($profile_array['field_photo'][LANGUAGE_NONE][0]['uri'])) { $photos_sub_dir = '/sites/default/files/styles/person_profile/public/'; //$profile_array['field_photo'][LANGUAGE_NONE][0]['uri'] = image_style_url('person_profile', $profile_array['field_photo'][LANGUAGE_NONE][0]['uri']); $profile_array['field_photo'][LANGUAGE_NONE][0]['uri'] = str_replace("public://", $ucd_lnl_people_server . $photos_sub_dir, $profile_array['field_photo'][LANGUAGE_NONE][0]['uri']); } //The link type doesn't standardize adding the http, so adding it here if (isset($profile_array['field_website'][LANGUAGE_NONE][0]['url'])) { if (substr($profile_array['field_website'][LANGUAGE_NONE][0]['url'], 0, 7) != 'http://') { $profile_array['field_website'][LANGUAGE_NONE][0]['url'] = 'http://' . $profile_array['field_website'][LANGUAGE_NONE][0]['url']; } } drupal_set_title($profile_array['field_first'][LANGUAGE_NONE][0]['safe_value'] . " " . $profile_array['field_last'][LANGUAGE_NONE][0]['safe_value']); $output = theme('ucd_lnl_profile', array('profile' => $profile_array)); return $output; } /* * Themes multiple textfield fields as unordered lists. */ function ucd_lnl_people_theme_mtext(&$variables) { $output = "
    \n"; foreach($variables['field_values'] AS $value) { if (isset($value['safe_value'])) { $output .= "
  • " . $value['safe_value'] . "
  • \n"; } else { $output .= "
  • " . $value['value'] . "
  • \n"; } } $output .= "
\n"; return $output; } /* * Themes multiple text area fields as unordered lists. */ function ucd_lnl_people_theme_mtextarea(&$variables) { $output = ""; foreach($variables['field_values'] AS $value) { if (isset($value['safe_value'])) { $output .= $value['safe_value'] . "\n"; } else { $output .= $value['value'] . "\n"; } } return $output; } /* * Themes the education fields */ function ucd_lnl_people_theme_education(&$variables) { $degree_field_name = 'field_' . $variables['type'] . '_degree'; $institution_field_name = 'field_' . $variables['type'] . '_institution'; $output = "
    \n"; foreach($variables['field_values'] AS $value) { $output .= "
  • " . $value[$degree_field_name][LANGUAGE_NONE][0]['safe_value'] . ", " . $value[$institution_field_name][LANGUAGE_NONE][0]['safe_value'] . "
  • \n"; } $output .= "
\n"; return $output; } /** * Themes the office field */ function ucd_lnl_people_theme_office2(&$variables) { $output = "
    "; foreach ($variables['field_values'] as $office) { $room = $office['field_office2_room'][LANGUAGE_NONE][0]['safe_value']; $building = $office['field_office2_building']['title']; $link = $office['field_office2_building']['field_bldg_map_link'][LANGUAGE_NONE][0]['url']; $output .= "
  • " . $room . " " . $building . "
  • "; } $output .= "
"; return $output; } /** * Really these should be pulled from the server but I'm not sure * of the best way to do this. * This is significantly faster at the moment. */ function ucd_lnl_people_admin_groups() { return array( 'faculty_emerit' =>' Faculty - Emerita/Emeritus', 'faculty_nonsenate' => 'Faculty - Non-Senate', 'faculty_nonsenate_parttime' => 'Faculty - Non-Senate - Part time', 'faculty_senate' => 'Faculty - Senate', 'faculty_affiliated' => 'Faculty - Affiliated Only', 'grad' => 'Grad Student', 'grad_gsr' => 'Grad Student - GSR', 'grad_instructor' => 'Grad Student - Instructor', 'grad_reader' => 'Grad Student - Reader', 'grad_ta' => 'Grad Student - TA', 'staff' => 'Staff', 'undergrad_pa' => 'Undergraduate - Peer Adviser', 'undergrad_reader' => 'Undergraduate - Reader', 'undergrad_asst' => 'Undergraduate - Student Assistant', 'undergrad_tutor' => 'Undergraduate - Tutor', 'visiting' => 'Visiting', ); }

A sample of the ucd_lnl_profile.tpl.php display template:

/*
 * @file
 *   Template for displaying a UCD LNL people Profile.  Can be overridden by the theme.
 */

//dsm(get_defined_vars());
<?php if (isset($field_photo)): ?>
<?php endif; ?>

<?php print $field_first[0]['safe_value'] . " " . $field_last[0]['safe_value']; ?>

...

Categories: