pcp.module in Profile Complete Percent 7
Same filename and directory in other branches
Allows users with valid permissions to tag profile fields (core fields or Profile2 fields) for a users profile to be considered complete.
File
pcp.moduleView source
<?php
/**
* @file
* Allows users with valid permissions to tag profile fields (core fields or
* Profile2 fields) for a users profile to be considered complete.
*/
/**
* Implements hook_theme().
*/
function pcp_theme($existing, $type, $theme, $path) {
return array(
'pcp_template' => array(
'template' => 'pcp-template',
'variables' => array(
'complete_data' => NULL,
),
),
);
}
/**
* Implements hook_permission().
*/
function pcp_permission() {
return array(
'administer pcp' => array(
'title' => t('Administer Profile Complete Percentages'),
'description' => t('Allows a user to configure which fields to be considered complete.'),
),
);
}
/**
* Implements hook_menu().
*/
function pcp_menu() {
$items['admin/config/people/pcp'] = array(
'title' => 'Profile Complete Percentages',
'description' => 'Tag profile fields as required for percent complete handling.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'pcp_admin_settings',
),
'access arguments' => array(
'administer pcp',
),
'file' => 'pcp.admin.inc',
'file path' => drupal_get_path('module', 'pcp') . '/includes',
'weight' => 10,
);
return $items;
}
/**
* Implements hook_views_api().
*/
function pcp_views_api() {
return array(
'api' => 3,
'path' => drupal_get_path('module', 'pcp') . '/includes',
);
}
/**
* Implements hook_block_info().
*/
function pcp_block_info() {
// Create block for core user profiles.
$blocks['pcp_profile_percent_complete'] = array(
'info' => t('Profile Complete Percentage - Core Profile'),
'cache' => DRUPAL_NO_CACHE,
);
// Create a block for each profile2 profile type.
if ($profile2_entity = entity_get_info('profile2')) {
foreach ($profile2_entity['bundles'] as $bundle => $values) {
$block_name = _pcp_block_identifier($bundle);
$blocks[$block_name] = array(
'info' => t('Profile Complete Percentage - ' . $values['label']),
'cache' => DRUPAL_NO_CACHE,
);
}
}
return $blocks;
}
/**
* Helper function to retrieve the block identifier.
* Because block names cannot be longer than 32 characters, we
* make a md5 string if it's longer.
*/
function _pcp_block_identifier($bundle) {
$block_name = 'pcp_profile2_' . $bundle;
if (strlen($block_name) > 32) {
$block_name = md5($block_name);
}
return $block_name;
}
/**
* Implements hook_block_view().
*/
function pcp_block_view($delta = '') {
global $user;
$block = array();
// No need to render a block for anonymous users.
if (user_is_anonymous()) {
return;
}
//The $delta parameter tells us which block is being requested.
switch ($delta) {
case 'pcp_profile_percent_complete':
$out = pcp_get_complete_percentage_data('user', 'user', $user);
$hide = variable_get('pcp_hide_block_on_complete', 0);
$out['field_link_option'] = array(
'attributes' => array(
'target' => variable_get('pcp_fields_open_option', '_self'),
),
);
if ($hide && $out['incomplete'] == 0 || empty($out)) {
$subject = '';
$content = '';
}
else {
drupal_add_css(drupal_get_path('module', 'pcp') . '/css/pcp.theme.css');
$subject = t('Profile Complete');
$content = theme('pcp_template', $out);
}
$block['subject'] = $subject;
$block['content'] = $content;
break;
// Generate content for each profile2 profile type's pcp block.
default:
if ($profile2_entity = entity_get_info('profile2')) {
foreach ($profile2_entity['bundles'] as $bundle => $values) {
if ($delta == _pcp_block_identifier($bundle)) {
$out = pcp_get_complete_percentage_data('profile2', $bundle, $user);
$hide = variable_get('pcp_profile2_' . $bundle . '_hide_block_on_complete', 0);
$out['field_link_option'] = array(
'attributes' => array(
'target' => variable_get('pcp_fields_open_option', '_self'),
),
);
// If the block should be hidden, hide it.
if ($hide && $out['incomplete'] == 0 || empty($out)) {
$content = '';
}
else {
drupal_add_css(drupal_get_path('module', 'pcp') . '/css/pcp.theme.css');
$content = theme('pcp_template', $out);
}
$block['subject'] = t('Profile Complete Percentage - @label', array(
'@label' => $values['label'],
));
$block['content'] = $content;
}
}
}
break;
}
return $block;
}
/**
* Get the profile complete percentage data for a given user.
*
* @param $user
* User object
*
* @return
* PCP data array.
*/
function pcp_get_complete_percentage_data($entity_type, $bundle, $user) {
$entity_fields = field_info_instances($entity_type, $bundle);
// Determine which fields have been tagged for evaluation.
$profile_fields = pcp_get_tagged_profile_fields($entity_type, $bundle, NULL);
$additional_fields = pcp_get_additional_tagged_fields(NULL, $entity_type, $bundle);
$fields = $profile_fields + $additional_fields;
// Restrict profile completeness for fields the user don't have access to.
// Access rules are provided by user role field module.
if (module_exists('user_role_field')) {
$user_roles = array_keys($user->roles);
$fields = _pcp_check_user_field_access($fields, $user_roles);
}
// We need to define these values here in case $data is returned early.
$data = array();
$data['entity_type'] = $entity_type;
$data['bundle'] = $bundle;
$data['uid'] = $user->uid;
// If no fields have been tagged, indicate that the profile is complete.
if (!$fields) {
$data['current_percent'] = 100;
$data['incomplete'] = 0;
return $data;
}
// Gather all profile values for this user.
$user_profile_values = pcp_get_user_profile_values($user->uid, $entity_type, $bundle);
$user_additional_values = pcp_get_user_additional_values($user->uid, $entity_type, $bundle);
$user_values = $user_profile_values + $user_additional_values;
// Enumerate empty fields by comparing tagged fields to user profile values.
$empty_fields = array();
foreach ($fields as $field_name) {
if (empty($user_values[$field_name])) {
$empty_fields[$field_name] = $field_name;
}
}
// If there is one empty field or more.
if ($empty_fields) {
$profile_fields_order_value = variable_get('pcp_fields_order', '0');
// Pick up a random field, we won't use shuffle because it
// re-indexes the array keys
if ($profile_fields_order_value == 0) {
$field_name = array_rand($empty_fields);
}
else {
// Assign any higher value.
$old_field_instance_weight = '999';
foreach ($empty_fields as $key => $user_field_name) {
$field_instance = field_info_instance('user', $user_field_name, 'user');
$field_instance_weight = $field_instance['widget']['weight'];
if ($field_instance_weight < $old_field_instance_weight) {
$field_name = $user_field_name;
$old_field_instance_weight = $field_instance_weight;
}
}
}
if ($field_name == 'user_picture') {
$field = array(
'fiid' => 'user_picture',
'title' => 'User Picture',
'name' => 'picture_upload',
);
$field_title = t($field['title']);
}
else {
$field_title = $entity_fields[$field_name]['label'];
if (module_exists('i18n_field') && !empty($field_title)) {
$field_title = i18n_field_translate_property($entity_fields[$field_name], 'label');
}
}
$data['nextfield_title'] = $field_title;
$data['nextfield_name'] = $field_name;
}
$fields_count = count($fields);
$empty_fields_count = count($empty_fields);
$completed_fields = $fields_count - $empty_fields_count;
$current_percent = number_format($completed_fields / $fields_count, 2) * 100;
$next_percent = number_format(($completed_fields + 1) / $fields_count, 2) * 100;
$data['completed'] = $completed_fields;
$data['incomplete'] = $empty_fields_count;
$data['total'] = $fields_count;
$data['current_percent'] = $current_percent;
$data['next_percent'] = $next_percent;
return $data;
}
/**
* Get all the profile fields stored in the system, tagged or not tagged.
*/
function pcp_get_profile_fields($params) {
$instances = field_read_instances($params);
$fields = array();
foreach ($instances as $instance) {
$fields[$instance['entity_type'] . ':' . $instance['bundle'] . ':' . $instance['field_name']] = $instance['field_name'];
}
return $fields;
}
/**
* Get all the profile fields that have been tagged.
* If an $fiid is passed in, only the data for that field will be returned.
*
* @param $fiid
* (optional) NULL The field instance id of the field data should be returned for. If null, all fields
* are returned.
* @param $entity_type
* (optional) NULL The type of entity to return fields for.
* @param $bundle
* (optional) NULL The bundle to return fields for.
*
* @return
* field identifier (entity_type:bundle:field_name) and name(s).
*/
function pcp_get_tagged_profile_fields($entity_type = NULL, $bundle = NULL, $field_name = NULL) {
$enabled_fields = variable_get('pcp_enabled_fields', array());
if (empty($enabled_fields)) {
return array();
}
$query = db_select('field_config_instance', 'fci');
$query
->addField('fci', 'field_name', 'field_name');
$query
->condition('fci.deleted', 0);
$or = db_or();
foreach ($enabled_fields as $enabled_field_identifier) {
$enabled_field_name_elements = explode(':', $enabled_field_identifier);
if (count($enabled_field_name_elements) > 2) {
$or
->condition('fci.field_name', $enabled_field_name_elements[2]);
}
}
$query
->condition($or);
if (isset($entity_type)) {
$query
->condition('entity_type', $entity_type);
}
if (isset($bundle)) {
$query
->condition('bundle', $bundle);
}
if (isset($field_name)) {
$query
->condition('field_name', $field_name);
}
$result = $query
->execute();
$fields = array();
foreach ($result as $row) {
$fields[$entity_type . ':' . $bundle . ':' . $row->field_name] = $row->field_name;
}
return $fields;
}
/**
* Get all additional tagged fields that where not created
* using the profile module. This allows additional PCP
* support for other drupal features.
*/
function pcp_get_additional_tagged_fields($uid, $entity_type, $bundle = NULL) {
$fields = array();
// Enable user picture support.
if ($entity_type == 'user' && variable_get('pcp_enable_user_picture', 0)) {
$fields['user_picture'] = 'user_picture';
}
return $fields;
}
/**
* Return a users profile field values that have been saved
* for a given user.
*
* @param int $uid
* The uid of the user we are returning data for.
* @param $entity_type
* The type of entity to return fields for.
* @param $bundle
* (optional) NULL The bundle to return fields for
*
* @return assoc array of all profile fields for the user.
*/
function pcp_get_user_profile_values($uid, $entity_type, $bundle = NULL) {
$fields = field_info_instances($entity_type, $bundle);
// Make sure the user info is fresh and not cached.
$user = user_load($uid, TRUE);
$user_fields = array();
// Grab profile values from core profile fields.
if ($entity_type == 'user') {
foreach ($fields as $field) {
$user_fields[$field['field_name']] = $user->{$field['field_name']};
}
}
elseif ($entity_type == 'profile2' && ($profile = profile2_load_by_user($user, $bundle))) {
foreach ($fields as $field_name => $field_values) {
if (isset($profile->{$field_name}) && ($field = $profile->{$field_name})) {
foreach ($field[LANGUAGE_NONE][0] as $value) {
if (!is_null($value)) {
$user_fields[$field_name] = $field[LANGUAGE_NONE][0];
break;
}
}
}
}
}
// Note, entity type user will return empty fields, whereas entity type
// profile2 will only return non-empty fields.
return $user_fields;
}
/**
* Return a users additional field values that have been saved
* for a given user.
*
* @param int $uid
* The uid of the user we are returning data for.
* @param $entity_type
* The type of entity to return fields for.
* @param $bundle
* (optional) NULL The bundle to return fields for
*
* @return assoc array of all profile fields for the user.
*/
function pcp_get_user_additional_values($uid, $entity_type, $bundle = NULL) {
$values = array();
if ($uid && $entity_type == 'user') {
$account = user_load($uid);
$values['user_picture'] = $account->picture;
}
return $values;
}
/**
* Implements hook_form_FORM_ID_alter().
* Form builder; Configure PCP fields for profile2 profile types.
*/
function pcp_form_profile2_type_form_alter(&$form, &$form_state, $form_id) {
form_load_include($form_state, 'inc', 'pcp', 'includes/pcp.admin');
$bundle = $form['type']['#default_value'];
$form['profile_complete'] = array(
'#type' => 'fieldset',
'#title' => 'Profile Complete Settings',
);
$form['profile_complete']['hide_block_on_complete'] = array(
'#type' => 'checkbox',
'#title' => 'Hide Block When Complete',
'#default_value' => variable_get('pcp_profile2_' . $bundle . '_hide_block_on_complete', 0),
'#description' => t('When a user reaches 100% complete of their profile, do you want the profile complete percent block to go away? If so, check this box on.'),
);
$options = array();
$settings = pcp_admin_settings_form_data('profile2', $bundle);
foreach ($settings['profile_fields_options'] as $fiid => $field_name) {
$field_info = field_info_instance('profile2', $field_name, $bundle);
$options[$fiid] = $field_info['label'];
}
$profile_fields_description = empty($options) ? t('There are no fields enabled for this profile type. Please !link', array(
'!link' => l(t('add some profile fields'), 'admin/structure/profiles/manage/' . $bundle . '/fields'),
)) : t('Checking a profile field below will add that field to the logic of the complete percentage.');
$form['profile_complete']['profile_fields'] = array(
'#title' => t('Profile Fields'),
'#description' => filter_xss($profile_fields_description),
'#type' => 'checkboxes',
'#options' => $options,
'#default_value' => array_flip($settings['default_values']),
);
$form['#submit'][] = 'pcp_admin_settings_submit';
return $form;
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function pcp_form_user_admin_settings_alter(&$form, &$form_state) {
form_load_include($form_state, 'inc', 'pcp', 'includes/pcp.admin');
if (user_access('administer pcp')) {
$form['personalization']['pictures']['pcp_enable_user_picture'] = array(
'#title' => 'Make required for PCP module',
'#type' => 'checkbox',
'#default_value' => variable_get('pcp_enable_user_picture', 0),
'#description' => t('Checking this box will tag this field as a required field for completion of the users profile.'),
'#weight' => -5,
);
$form['#submit'][] = 'pcp_admin_settings_submit';
}
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function pcp_form_field_ui_field_edit_form_alter(&$form, &$form_state) {
form_load_include($form_state, 'inc', 'pcp', 'includes/pcp.admin');
// @todo do we need user access check here?
if ($form['#instance']['entity_type'] == 'profile2') {
$tag = FALSE;
$result = pcp_get_tagged_profile_fields($form['#instance']['entity_type'], $form['#instance']['bundle'], $form['#instance']['field_name']);
if (!empty($result)) {
$tag = TRUE;
}
$form['instance']['pcp_tag'] = array(
'#type' => 'checkbox',
'#title' => t('Make required for PCP module'),
'#description' => t('Checking this box will tag this field as a required field for completion of the users profile.'),
'#default_value' => $tag,
'#weight' => -5,
);
$form['#submit'][] = 'pcp_admin_settings_submit';
}
}
/**
* Implements hook_form_FORM_ID_alter().
* We need an extra submit handler to delete the PCP field settings when a field is deleted
*/
function pcp_form_field_ui_field_delete_form_alter(&$form, &$form_state) {
if (in_array($form['entity_type']['#value'], array(
'profile2',
'user',
))) {
$form['#submit'] = array_merge(array(
'pcp_delete_field_requireness',
), $form['#submit']);
}
}
/**
* Called when a user deletes a profile field
* We then need to delete the pcp value too
*/
function pcp_delete_field_requireness($form, &$form_state) {
_pcp_disable_field($form_state['values']['entity_type'], $form_state['values']['field_name'], $form_state['values']['bundle']);
}
/**
* Implements hook_form_alter().
*/
function pcp_form_alter(&$form, &$form_state, $form_id) {
if ($form_id == 'user_profile_form' || strpos($form_id, 'profile2_edit') === 0) {
// Add JS that will hightlight target field.
drupal_add_js(drupal_get_path('module', 'pcp') . '/pcp.js');
}
}
/**
* Process variables for pcp-template.tpl.php.
*
* @see pcp-template.tpl.php
*/
function template_preprocess_pcp_template(&$variables) {
if (isset($variables['nextfield_name'])) {
// Generate URL to edit next field for core user profile.
if ($variables['entity_type'] == 'user') {
$input_name = 'edit-' . str_replace('_', '-', $variables['nextfield_name']);
$user_edit_path = 'user/' . $variables['uid'] . '/edit';
$variables['next_path'] = url($user_edit_path, array(
'absolute' => TRUE,
'fragment' => $input_name,
));
}
elseif ($variables['entity_type'] == 'profile2') {
$bundle = $variables['bundle'];
$input_name = 'edit-profile-' . str_replace('_', '-', $bundle) . '-' . str_replace('_', '-', $variables['nextfield_name']);
// Determine correct 'edit path' for profile2 profile type.
$old_profile_edit_path = 'profile-' . $bundle . '/' . $variables['uid'] . '/edit';
$new_profile_edit_path = 'user/' . $variables['uid'] . '/edit/' . $bundle;
$profile_edit_path = drupal_valid_path($old_profile_edit_path) ? $old_profile_edit_path : $new_profile_edit_path;
$variables['next_path'] = url($profile_edit_path, array(
'absolute' => TRUE,
'fragment' => $input_name,
));
}
}
}
function _pcp_disable_field($entity_type, $bundle, $field_name) {
$enabled_fields = variable_get('pcp_enabled_fields', array());
$field_identifier = implode(':', array(
$entity_type,
$bundle,
$field_name,
));
if (in_array($field_identifier, $enabled_fields)) {
$key = array_search($field_identifier, $enabled_fields);
unset($enabled_fields[$field_identifier]);
variable_set('pcp_enabled_fields', $enabled_fields);
return TRUE;
}
return FALSE;
}
function _pcp_enable_field($entity_type, $bundle, $field_name) {
$enabled_fields = variable_get('pcp_enabled_fields', array());
$field_identifier = implode(':', array(
$entity_type,
$bundle,
$field_name,
));
if (!in_array($field_identifier, $enabled_fields)) {
$enabled_fields[$field_identifier] = $field_identifier;
variable_set('pcp_enabled_fields', $enabled_fields);
return TRUE;
}
return FALSE;
}
/**
* Get array of available pcp bundles.
*/
function pcp_get_bundles($filter = 'all') {
static $bundles = array();
if (empty($bundles)) {
// Add core user profile.
if ($filter != 'profile2') {
$bundles['user'] = 'user';
}
// Add profile2 types.
if ($profile2_entity = entity_get_info('profile2')) {
foreach ($profile2_entity['bundles'] as $bundle => $values) {
$bundles['profile2'] = $bundle;
}
}
}
return $bundles;
}
/**
* Implements hook_user_login().
*/
function pcp_user_login(&$edit, $account) {
// Default message, if user is not set any message.
$pcp_login_message = variable_get('pcp_login_message', '');
if (!empty($pcp_login_message)) {
$pcp_login_message = filter_xss($pcp_login_message);
$current_user_roles = array_keys($account->roles);
$user_roles = array_values(variable_get('pcp_login_message_role', array()));
$check_user_role = array_intersect($current_user_roles, $user_roles);
if (!empty($check_user_role)) {
$pcp_data = pcp_get_complete_percentage_data('user', 'user', $account);
if ($pcp_data['current_percent'] < 100) {
$current_user_object['user'] = $account;
$pcp_login_message = token_replace($pcp_login_message, $current_user_object);
drupal_set_message($pcp_login_message, 'warning');
}
}
}
}
/**
* Check is the user has access to the field.
*
* @param Array $fields
* Field names which are used in complete profile.
*
* @return Array
* Field names after removing user restricted fields.
*/
function _pcp_check_user_field_access($fields, $user_roles) {
foreach ($fields as $field_key => $field_name) {
$user_field_info = field_info_field($field_name);
// Get list of user field access by user_role_field module.
if (isset($user_field_info['settings']['user_role_field'])) {
$user_field_access = $user_field_info['settings']['user_role_field'];
$user_access_roles = array_intersect($user_field_access, $user_roles);
if (empty($user_access_roles)) {
unset($fields[$field_key]);
}
}
}
return $fields;
}
Functions
Name | Description |
---|---|
pcp_block_info | Implements hook_block_info(). |
pcp_block_view | Implements hook_block_view(). |
pcp_delete_field_requireness | Called when a user deletes a profile field We then need to delete the pcp value too |
pcp_form_alter | Implements hook_form_alter(). |
pcp_form_field_ui_field_delete_form_alter | Implements hook_form_FORM_ID_alter(). We need an extra submit handler to delete the PCP field settings when a field is deleted |
pcp_form_field_ui_field_edit_form_alter | Implements hook_form_FORM_ID_alter(). |
pcp_form_profile2_type_form_alter | Implements hook_form_FORM_ID_alter(). Form builder; Configure PCP fields for profile2 profile types. |
pcp_form_user_admin_settings_alter | Implements hook_form_FORM_ID_alter(). |
pcp_get_additional_tagged_fields | Get all additional tagged fields that where not created using the profile module. This allows additional PCP support for other drupal features. |
pcp_get_bundles | Get array of available pcp bundles. |
pcp_get_complete_percentage_data | Get the profile complete percentage data for a given user. |
pcp_get_profile_fields | Get all the profile fields stored in the system, tagged or not tagged. |
pcp_get_tagged_profile_fields | Get all the profile fields that have been tagged. If an $fiid is passed in, only the data for that field will be returned. |
pcp_get_user_additional_values | Return a users additional field values that have been saved for a given user. |
pcp_get_user_profile_values | Return a users profile field values that have been saved for a given user. |
pcp_menu | Implements hook_menu(). |
pcp_permission | Implements hook_permission(). |
pcp_theme | Implements hook_theme(). |
pcp_user_login | Implements hook_user_login(). |
pcp_views_api | Implements hook_views_api(). |
template_preprocess_pcp_template | Process variables for pcp-template.tpl.php. |
_pcp_block_identifier | Helper function to retrieve the block identifier. Because block names cannot be longer than 32 characters, we make a md5 string if it's longer. |
_pcp_check_user_field_access | Check is the user has access to the field. |
_pcp_disable_field | |
_pcp_enable_field |