Index: modules/profile/profile.info =================================================================== RCS file: /cvs/drupal/drupal/modules/profile/profile.info,v retrieving revision 1.9 diff -u -p -r1.9 profile.info --- modules/profile/profile.info 8 Jun 2009 09:23:53 -0000 1.9 +++ modules/profile/profile.info 16 Oct 2009 08:37:29 -0000 @@ -1,11 +1,9 @@ -; $Id: profile.info,v 1.9 2009/06/08 09:23:53 dries Exp $ -name = Profile -description = Supports configurable user profiles. -package = Core -version = VERSION -core = 7.x -files[] = profile.module -files[] = profile.admin.inc -files[] = profile.pages.inc -files[] = profile.install -files[] = profile.test +; $Id: profile.info,v 1.9 2009/06/08 09:23:53 dries Exp $ +name = Profile +description = Supports configurable user profiles. +package = Core +version = VERSION +core = 7.x +files[] = profile.module +files[] = profile.install +files[] = profile.test Index: modules/profile/profile.install =================================================================== RCS file: /cvs/drupal/drupal/modules/profile/profile.install,v retrieving revision 1.22 diff -u -p -r1.22 profile.install --- modules/profile/profile.install 29 Sep 2009 15:13:56 -0000 1.22 +++ modules/profile/profile.install 16 Oct 2009 08:37:29 -0000 @@ -1,156 +1,150 @@ - 'Stores profile field information.', - 'fields' => array( - 'fid' => array( - 'type' => 'serial', - 'not null' => TRUE, - 'description' => 'Primary Key: Unique profile field ID.', - ), - 'title' => array( - 'type' => 'varchar', - 'length' => 255, - 'not null' => FALSE, - 'description' => 'Title of the field shown to the end user.', - ), - 'name' => array( - 'type' => 'varchar', - 'length' => 128, - 'not null' => TRUE, - 'default' => '', - 'description' => 'Internal name of the field used in the form HTML and URLs.', - ), - 'explanation' => array( - 'type' => 'text', - 'not null' => FALSE, - 'description' => 'Explanation of the field to end users.', - ), - 'category' => array( - 'type' => 'varchar', - 'length' => 255, - 'not null' => FALSE, - 'description' => 'Profile category that the field will be grouped under.', - ), - 'page' => array( - 'type' => 'varchar', - 'length' => 255, - 'not null' => FALSE, - 'description' => "Title of page used for browsing by the field's value", - ), - 'type' => array( - 'type' => 'varchar', - 'length' => 128, - 'not null' => FALSE, - 'description' => 'Type of form field.', - ), - 'weight' => array( - 'type' => 'int', - 'not null' => TRUE, - 'default' => 0, - 'size' => 'tiny', - 'description' => 'Weight of field in relation to other profile fields.', - ), - 'required' => array( - 'type' => 'int', - 'not null' => TRUE, - 'default' => 0, - 'size' => 'tiny', - 'description' => 'Whether the user is required to enter a value. (0 = no, 1 = yes)', - ), - 'register' => array( - 'type' => 'int', - 'not null' => TRUE, - 'default' => 0, - 'size' => 'tiny', - 'description' => 'Whether the field is visible in the user registration form. (1 = yes, 0 = no)', - ), - 'visibility' => array( - 'type' => 'int', - 'not null' => TRUE, - 'default' => 0, - 'size' => 'tiny', - 'description' => 'The level of visibility for the field. (0 = hidden, 1 = private, 2 = public on profile but not member list pages, 3 = public on profile and list pages)', - ), - 'autocomplete' => array( - 'type' => 'int', - 'not null' => TRUE, - 'default' => 0, - 'size' => 'tiny', - 'description' => 'Whether form auto-completion is enabled. (0 = disabled, 1 = enabled)', - ), - 'options' => array( - 'type' => 'text', - 'not null' => FALSE, - 'description' => 'List of options to be used in a list selection field.', - ), - ), - 'indexes' => array( - 'category' => array('category'), - ), - 'unique keys' => array( - 'name' => array('name'), - ), - 'primary key' => array('fid'), - ); - - $schema['profile_value'] = array( - 'description' => 'Stores values for profile fields.', - 'fields' => array( - 'fid' => array( - 'type' => 'int', + +/** + * Implement hook_schema(). + */ +function profile_schema() { + $schema['profile'] = array( + 'description' => 'Stores profile items.', + 'fields' => array( + 'pid' => array( + 'type' => 'serial', + 'not null' => TRUE, + 'description' => 'Primary Key: Unique profile item ID.', + ), + 'name' => array( + 'type' => 'varchar', + 'length' => 32, + 'not null' => TRUE, + 'default' => '', + 'description' => 'The name of the profile.', + ), + 'uid' => array( + 'type' => 'int', 'unsigned' => TRUE, - 'not null' => TRUE, - 'default' => 0, - 'description' => 'The {profile_field}.fid of the field.', - ), - 'uid' => array( - 'type' => 'int', - 'unsigned' => TRUE, - 'not null' => TRUE, - 'default' => 0, - 'description' => 'The {users}.uid of the profile user.', - ), - 'value' => array( - 'type' => 'text', - 'not null' => FALSE, - 'description' => 'The value for the field.', - ), - ), - 'primary key' => array('uid', 'fid'), - 'indexes' => array( - 'fid' => array('fid'), - ), - 'foreign keys' => array( - 'fid' => array('profile_field' => 'fid'), - 'uid' => array('users' => 'uid'), - ), - ); - - return $schema; -} - -/** - * Rename {profile_fields} table to {profile_field} and {profile_values} to {profile_value}. - */ -function profile_update_7001() { - db_rename_table('profile_fields', 'profile_field'); - db_rename_table('profile_values', 'profile_value'); + // This is allowed to be NULL so contrib modules may use profiles without users. + 'not null' => FALSE, + 'default' => NULL, + 'description' => "The {users}.uid of the associated user.", + ), + ), + 'primary key' => array('pid'), + 'indexes' => array( + 'uid' => array('uid'), + ), + 'foreign keys' => array( + 'uid' => array('users' => 'uid'), + 'name' => array('profile_types' => 'name'), + ), + ); + + $schema['profile_type'] = array( + 'description' => 'Stores information about all defined profile types.', + 'fields' => array( + 'name' => array( + 'type' => 'varchar', + 'length' => 32, + 'not null' => TRUE, + 'description' => 'The machine-readable name of this profile type.', + ), + 'label' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => '', + 'description' => 'The human-readable name of this profile type.', + ), + 'weight' => array( + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + 'size' => 'tiny', + 'description' => 'The weight of this profile type in relation to others.', + ), + 'locked' => array( + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + 'size' => 'tiny', + 'description' => 'A boolean indicating whether the administrator may delete this type.', + ), + 'registration' => array( + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + 'size' => 'tiny', + 'description' => 'A boolean indicating whether this type is used in user registration and account creation.', + ), + 'data' => array( + 'type' => 'text', + 'not null' => FALSE, + 'size' => 'big', + 'serialize' => TRUE, + 'description' => 'A serialized array of additional data related to this profile type.', + ), + ), + 'primary key' => array('name'), + ); + + return $schema; } + +/** + * Implement hook_enable(). + * + * Create a main profile type with a field for the user's full name. + */ +function profile_enable() { + if (!profile_get_types('account')) { + // Refresh schema cache, needed to let type save work during installation. + drupal_get_schema('profile_type', TRUE); + + profile_type_save(array( + 'name' => 'account', + 'label' => t('Profile'), + 'weight' => 0, + 'locked' => TRUE, + 'registration' => TRUE, + )); + + $field = array( + 'field_name' => 'profile_fullname', + 'type' => 'text', + 'cardinality' => 1, + 'translatable' => FALSE, + ); + // Only create the field if it doesn't exist yet. + /// (Uninstalling does not delete it. Bug in FieldAPI?) + $prior_field = field_read_field($field['field_name'], array('include_inactive' => TRUE)); + if (empty($prior_field)) { + field_create_field($field); + } + + $instance = array( + 'field_name' => 'profile_fullname', + 'object_type' => 'profile', + 'bundle' => 'account', + 'label' => 'Full name', + 'description' => 'Specify your first and last name.', + 'widget' => array( + 'type' => 'text_textfield', + 'weight' => 0, + ), + ); + field_create_instance($instance); + } +} + +/** + * Implement hook_uninstall(). + */ +function profile_uninstall() { +} + +//TODO: Update procedure. Index: modules/profile/profile.module =================================================================== RCS file: /cvs/drupal/drupal/modules/profile/profile.module,v retrieving revision 1.279 diff -u -p -r1.279 profile.module --- modules/profile/profile.module 10 Oct 2009 21:39:03 -0000 1.279 +++ modules/profile/profile.module 16 Oct 2009 08:37:30 -0000 @@ -1,624 +1,409 @@ -' . t('The profile module allows custom fields (such as country, full name, or age) to be defined and displayed in the My Account section. This permits users of a site to share more information about themselves, and can help community-based sites organize users around specific information.') . '

'; - $output .= '

' . t('The following types of fields can be added to a user profile:') . '

'; - $output .= ''; - $output .= '

' . t('For more information, see the online handbook entry for Profile module.', array('@profile' => 'http://drupal.org/handbook/modules/profile/')) . '

'; - return $output; - case 'admin/config/people/profile': - return '

' . t("This page displays a list of the existing custom profile fields to be displayed on a user's My Account page. To provide structure, similar or related fields may be placed inside a category. To add a new category (or edit an existing one), edit a profile field and provide a new category name. Remember that your changes will not be saved until you click the Save configuration button at the bottom of the page.") . '

'; - } -} - -/** - * Implement hook_theme(). - */ -function profile_theme() { - return array( - 'profile_block' => array( - 'arguments' => array('account' => NULL, 'fields' => array()), - 'template' => 'profile-block', - ), - 'profile_listing' => array( - 'arguments' => array('account' => NULL, 'fields' => array()), - 'template' => 'profile-listing', - ), - 'profile_wrapper' => array( - 'arguments' => array('content' => NULL), - 'template' => 'profile-wrapper', - ), - 'profile_admin_overview' => array( - 'arguments' => array('form' => NULL), - 'file' => 'profile.admin.inc', - ) - ); -} - -/** - * Implement hook_menu(). - */ -function profile_menu() { - $items['profile'] = array( - 'title' => 'User list', - 'page callback' => 'profile_browse', - 'access arguments' => array('access user profiles'), - 'file' => 'profile.pages.inc', - 'type' => MENU_SUGGESTED_ITEM, - ); - $items['admin/config/people/profile'] = array( - 'title' => 'Profiles', - 'description' => 'Create customizable fields for your users.', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('profile_admin_overview'), - 'access arguments' => array('administer users'), - 'file' => 'profile.admin.inc', - ); - $items['admin/config/people/profile/add'] = array( - 'title' => 'Add field', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('profile_field_form'), - 'access arguments' => array('administer users'), - 'file' => 'profile.admin.inc', - 'type' => MENU_CALLBACK, - ); - $items['admin/config/people/profile/autocomplete'] = array( - 'title' => 'Profile category autocomplete', - 'page callback' => 'profile_admin_settings_autocomplete', - 'access arguments' => array('administer users'), - 'file' => 'profile.admin.inc', - 'type' => MENU_CALLBACK, - ); - $items['admin/config/people/profile/edit'] = array( - 'title' => 'Edit field', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('profile_field_form'), - 'access arguments' => array('administer users'), - 'file' => 'profile.admin.inc', - 'type' => MENU_CALLBACK, - ); - $items['admin/config/people/profile/delete'] = array( - 'title' => 'Delete field', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('profile_field_delete'), - 'access arguments' => array('administer users'), - 'file' => 'profile.admin.inc', - 'type' => MENU_CALLBACK, - ); - $items['profile/autocomplete'] = array( - 'title' => 'Profile autocomplete', - 'page callback' => 'profile_autocomplete', - 'access arguments' => array('access user profiles'), - 'file' => 'profile.pages.inc', - 'type' => MENU_CALLBACK, - ); - return $items; -} - -/** - * Implement hook_block_info(). - */ - function profile_block_info() { - $blocks['author-information']['info'] = t('Author information'); - $blocks['author-information']['cache'] = DRUPAL_CACHE_PER_PAGE | DRUPAL_CACHE_PER_ROLE; - return $blocks; -} - -/** - * Implement hook_block_configure(). - */ -function profile_block_configure($delta = '') { - // Compile a list of fields to show - $fields = array(); - $result = db_query('SELECT name, title, weight, visibility FROM {profile_field} WHERE visibility IN (:visibility) ORDER BY weight', array(':visibility' => array(PROFILE_PUBLIC, PROFILE_PUBLIC_LISTINGS))); - foreach ($result as $record) { - $fields[$record->name] = check_plain($record->title); - } - $fields['user_profile'] = t('Link to full user profile'); - $form['profile_block_author_fields'] = array( - '#type' => 'checkboxes', - '#title' => t('Profile fields to display'), - '#default_value' => variable_get('profile_block_author_fields', array()), - '#options' => $fields, - '#description' => t('Select which profile fields you wish to display in the block. Only fields designated as public in the profile field configuration are available.', array('@profile-admin' => url('admin/config/people/profile'))), - ); - return $form; -} - -/** - * Implement hook_block_save(). - */ -function profile_block_save($delta = '', $edit = array()) { - variable_set('profile_block_author_fields', $edit['profile_block_author_fields']); -} - -/** - * Implement hook_block_view(). - */ -function profile_block_view($delta = '') { - if (user_access('access user profiles')) { - $output = ''; - if ((arg(0) == 'node') && is_numeric(arg(1)) && (arg(2) == NULL)) { - $node = node_load(arg(1)); - $account = user_load(array('uid' => $node->uid)); - - if ($use_fields = variable_get('profile_block_author_fields', array())) { - // Compile a list of fields to show. - $fields = array(); - $result = db_query('SELECT name, title, weight, visibility FROM {profile_field} WHERE visibility IN (:visibility) ORDER BY weight', array(':visibility' => array(PROFILE_PUBLIC, PROFILE_PUBLIC_LISTINGS))); - foreach ($result as $record) { - // Ensure that field is displayed only if it is among the defined block fields and, if it is private, the user has appropriate permissions. - if (isset($use_fields[$record->name]) && $use_fields[$record->name]) { - $fields[] = $record; - } - } - } - - if (!empty($fields)) { - $profile = _profile_update_user_fields($fields, $account); - $output .= theme('profile_block', array('account' => $account, 'fields' => $profile)); - } - - if (isset($use_fields['user_profile']) && $use_fields['user_profile']) { - $output .= '
' . l(t('View full user profile'), 'user/' . $account->uid) . '
'; - } - } - - if ($output) { - $block['subject'] = t('About %name', array('%name' => $account->name)); - $block['content'] = $output; - return $block; - } - } -} - -/** - * Implement hook_user_presave(). - */ -function profile_user_presave(&$edit, $account, $category) { - if ($account->uid) { - profile_save_profile($edit, $account, $category); - } -} - -/** - * Implement hook_user_insert(). - */ -function profile_user_insert(&$edit, $account, $category) { - profile_save_profile($edit, $account, $category, TRUE); -} - -/** - * Implement hook_user_cancel(). - */ -function profile_user_cancel(&$edit, $account, $method) { - switch ($method) { - case 'user_cancel_reassign': - case 'user_cancel_delete': - db_delete('profile_value') - ->condition('uid', $account->uid) - ->execute(); - break; - } -} - -/** - * Implement hook_user_load(). - */ -function profile_user_load($users) { - $result = db_query('SELECT f.name, f.type, v.uid, v.value FROM {profile_field} f INNER JOIN {profile_value} v ON f.fid = v.fid WHERE uid IN (:uids)', array(':uids' => array_keys($users))); - foreach ($result as $record) { - if (empty($users[$record->uid]->{$record->name})) { - $users[$record->uid]->{$record->name} = _profile_field_serialize($record->type) ? unserialize($record->value) : $record->value; - } - } -} - -function profile_save_profile(&$edit, $account, $category, $register = FALSE) { - $result = _profile_get_fields($category, $register); - foreach ($result as $field) { - if (_profile_field_serialize($field->type)) { - $edit[$field->name] = serialize($edit[$field->name]); - } - db_merge('profile_value') - ->key(array( - 'fid' => $field->fid, - 'uid' => $account->uid, - )) - ->fields(array('value' => $edit[$field->name])) - ->execute(); - // Mark field as handled (prevents saving to user->data). - $edit[$field->name] = NULL; - } -} - -function profile_view_field($account, $field) { - // Only allow browsing of private fields for admins, if browsing is enabled, - // and if a user has permission to view profiles. Note that this check is - // necessary because a user may always see their own profile. - $browse = user_access('access user profiles') - && (user_access('administer users') || $field->visibility != PROFILE_PRIVATE) - && !empty($field->page); - - if (isset($account->{$field->name}) && $value = $account->{$field->name}) { - switch ($field->type) { - case 'textarea': - return check_markup($value, filter_default_format($account), '', TRUE); - case 'textfield': - case 'selection': - return $browse ? l($value, 'profile/' . $field->name . '/' . $value) : check_plain($value); - case 'checkbox': - return $browse ? l($field->title, 'profile/' . $field->name) : check_plain($field->title); - case 'url': - return '' . check_plain($value) . ''; - case 'date': - $format = substr(variable_get('date_format_short', 'm/d/Y - H:i'), 0, 5); - // Note: Avoid PHP's date() because it does not handle dates before - // 1970 on Windows. This would make the date field useless for e.g. - // birthdays. - $replace = array( - 'd' => sprintf('%02d', $value['day']), - 'j' => $value['day'], - 'm' => sprintf('%02d', $value['month']), - 'M' => map_month($value['month']), - 'Y' => $value['year'], - 'H:i' => NULL, - 'g:ia' => NULL, - ); - return strtr($format, $replace); - case 'list': - $values = preg_split("/[,\n\r]/", $value); - $fields = array(); - foreach ($values as $value) { - if ($value = trim($value)) { - $fields[] = $browse ? l($value, 'profile/' . $field->name . '/' . $value) : check_plain($value); - } - } - return implode(', ', $fields); - } - } -} - -/** - * Implement hook_user_view(). - */ -function profile_user_view($account) { - // Show private fields to administrators and people viewing their own account. - if (user_access('administer users') || $GLOBALS['user']->uid == $account->uid) { - $result = db_query('SELECT * FROM {profile_field} WHERE visibility <> :hidden ORDER BY category, weight', array(':hidden' => PROFILE_HIDDEN)); - } - else { - $result = db_query('SELECT * FROM {profile_field} WHERE visibility <> :private AND visibility <> :hidden ORDER BY category, weight', array(':private' => PROFILE_PRIVATE, ':hidden' => PROFILE_HIDDEN)); - } - - $fields = array(); - foreach ($result as $field) { - if ($value = profile_view_field($account, $field)) { - $title = ($field->type != 'checkbox') ? check_plain($field->title) : NULL; - - // Create a single fieldset for each category. - if (!isset($account->content[$field->category])) { - $account->content[$field->category] = array( - '#type' => 'user_profile_category', - '#title' => $field->category, - ); - } - - $account->content[$field->category][$field->name] = array( - '#type' => 'user_profile_item', - '#title' => $title, - '#markup' => $value, - '#weight' => $field->weight, - '#attributes' => array('class' => array('profile-' . $field->name)), - ); - } - } -} - -function _profile_form_explanation($field) { - $output = $field->explanation; - - if ($field->type == 'list') { - $output .= ' ' . t('Put each item on a separate line or separate them by commas. No HTML allowed.'); - } - - if ($field->visibility == PROFILE_PRIVATE) { - $output .= ' ' . t('The content of this field is kept private and will not be shown publicly.'); - } - - return $output; -} - -/** - * Implement hook_form_alter(). - */ -function profile_form_alter(&$form, &$form_state, $form_id) { - if (!($form_id == 'user_register_form' || $form_id == 'user_profile_form')) { - return; - } - $form['#validate'][] = 'profile_user_form_validate'; - $account = $form['#user']; - $result = _profile_get_fields($form['#user_category'], $form['#user_category'] == 'register'); - $weight = 1; - foreach ($result as $field) { - $category = $field->category; - if (!isset($form[$category])) { - $form[$category] = array('#type' => 'fieldset', '#title' => check_plain($category), '#weight' => $weight++); - } - switch ($field->type) { - case 'textfield': - case 'url': - $form[$category][$field->name] = array( - '#type' => 'textfield', - '#title' => check_plain($field->title), - '#default_value' => isset($account->{$field->name}) ? $account->{$field->name} : '', - '#maxlength' => 255, - '#description' => _profile_form_explanation($field), - '#required' => $field->required, - ); - if ($field->autocomplete) { - $form[$category][$field->name]['#autocomplete_path'] = "profile/autocomplete/" . $field->fid; - } - break; - - case 'textarea': - $form[$category][$field->name] = array( - '#type' => 'textarea', - '#title' => check_plain($field->title), - '#default_value' => isset($account->{$field->name}) ? $account->{$field->name} : '', - '#description' => _profile_form_explanation($field), - '#required' => $field->required, - ); - break; - - case 'list': - $form[$category][$field->name] = array( - '#type' => 'textarea', - '#title' => check_plain($field->title), - '#default_value' => isset($account->{$field->name}) ? $account->{$field->name} : '', - '#description' => _profile_form_explanation($field), - '#required' => $field->required, - ); - break; - - case 'checkbox': - $form[$category][$field->name] = array( - '#type' => 'checkbox', - '#title' => check_plain($field->title), - '#default_value' => isset($account->{$field->name}) ? $account->{$field->name} : '', - '#description' => _profile_form_explanation($field), - '#required' => $field->required, - ); - break; - - case 'selection': - $options = $field->required ? array() : array('--'); - $lines = preg_split("/[\n\r]/", $field->options); - foreach ($lines as $line) { - if ($line = trim($line)) { - $options[$line] = $line; - } - } - $form[$category][$field->name] = array( - '#type' => 'select', - '#title' => check_plain($field->title), - '#default_value' => isset($account->{$field->name}) ? $account->{$field->name} : '', - '#options' => $options, - '#description' => _profile_form_explanation($field), - '#required' => $field->required, - ); - break; - - case 'date': - $form[$category][$field->name] = array( - '#type' => 'date', - '#title' => check_plain($field->title), - '#default_value' => isset($account->{$field->name}) ? $account->{$field->name} : '', - '#description' => _profile_form_explanation($field), - '#required' => $field->required, - ); - break; - } - } -} - -/** - * Helper function: update an array of user fields by calling profile_view_field - */ -function _profile_update_user_fields($fields, $account) { - foreach ($fields as $key => $field) { - $fields[$key]->value = profile_view_field($account, $field); - } - return $fields; -} - -/** - * Form validation handler for the user register/profile form. - * - * @see profile_form_alter() - */ -function profile_user_form_validate($form, &$form_state) { - $result = _profile_get_fields($form['#user_category'], $form['#user_category'] == 'register'); - foreach ($result as $field) { - if (!empty($form_state['values'][$field->name])) { - if ($field->type == 'url' && !valid_url($form_state['values'][$field->name], TRUE)) { - form_set_error($field->name, t('The value provided for %field is not a valid URL.', array('%field' => $field->title))); - } - } - elseif ($field->required && !user_access('administer users')) { - form_set_error($field->name, t('The field %field is required.', array('%field' => $field->title))); - } - } -} - -/** - * Implement hook_user_categories(). - */ -function profile_user_categories() { - $result = db_query("SELECT DISTINCT(category) FROM {profile_field}"); - $data = array(); - foreach ($result as $category) { - $data[] = array( - 'name' => $category->category, - 'title' => $category->category, - 'weight' => 3, - 'access callback' => 'profile_category_access', - 'access arguments' => array(1, $category->category) - ); - } - return $data; -} - -/** - * Menu item access callback - check if a user has access to a profile category. - */ -function profile_category_access($account, $category) { - if (user_access('administer users') && $account->uid > 0) { - return TRUE; - } - else { - $category_visible = (bool) db_query_range('SELECT 1 FROM {profile_field} WHERE category = :category AND visibility <> :visibility', 0, 1, array( - ':category' => $category, - ':visibility' => PROFILE_HIDDEN - ))->fetchField(); - return user_edit_access($account) && $category_visible; - } -} - -/** - * Process variables for profile-block.tpl.php. - * - * The $variables array contains the following arguments: - * - $account - * - $fields + array( + 'label' => t('Profile'), + 'controller class' => 'DrupalDefaultEntityController', + 'base table' => 'profile', + 'fieldable' => TRUE, + 'object keys' => array( + 'id' => 'pid', + 'bundle' => 'name', + ), + 'bundles' => array(), + ), + ); + foreach (profile_get_types() as $name => $info) { + $return['profile']['bundles'][$name] = array( + 'label' => $info['label'], + 'admin' => array( + 'path' => 'admin/structure/profiles/' . str_replace('_', '-', $name), + 'access arguments' => array('administer profiles'), + ), + ); + } + return $return; +} + +/** + * Implement hook_permission(). + */ +function profile_permission() { + return array( + 'administer profiles' => array( + 'title' => t('Administer profiles'), + 'description' => t('Manage user profiles.'), + ), + ); +} + +/** + * Gets an array of all profile types, keyed by the name. + * + * @param $name + * If set, the type with the given name is returned. + */ +function profile_get_types($name = NULL) { + $types = drupal_static(__FUNCTION__); + if (!isset($types)) { + $types = db_select('profile_type', 'pt') + ->fields('pt') + ->orderBy('name') + ->execute() + ->fetchAllAssoc('name', PDO::FETCH_ASSOC); + foreach ($types as &$type) { + $data = unserialize($type['data']); + unset($type['data']); + $type += (array)$data + array( + 'user category' => TRUE, + 'user view' => TRUE, + ); + } + } + if (isset($name)) { + return isset($types[$name]) ? $types[$name] : FALSE; + } + return $types; +} + +/** + * Implement hook_menu(). + */ +function profile_menu() { + //TODO: Add page to manage profile types at admin/structure/profiles. +} + +/** + * Fetch a profile object. + * + * @param $pid + * Integer specifying the profile id. + * @param $reset + * A boolean indicating that the internal cache should be reset. + * @return + * A fully-loaded $profile object or FALSE if it cannot be loaded. + * + * @see profile_load_multiple() + */ +function profile_load($pid, $reset = FALSE) { + $profiles = profile_load_multiple(array($pid), array(), $reset); + return reset($profiles); +} + +/** + * Load multiple profiles based on certain conditions. + * + * @param $pids + * An array of profile IDs. + * @param $conditions + * An array of conditions to match against the {profile} table. + * @param $reset + * A boolean indicating that the internal cache should be reset. + * @return + * An array of profile objects, indexed by pid. + * + * @see entity_load() + * @see profile_load() + * @see profile_load_by_user() + */ +function profile_load_multiple($pids = array(), $conditions = array(), $reset = FALSE) { + return entity_load('profile', $pids, $conditions, $reset); +} + +/** + * Fetch profiles by account. + * + * @param $account + * The user account to load profiles for, or its uid. + * @param $name + * To load a single profile, pass the name of the profile to load. + * @return + * Either a single profile or an array of profiles keyed by profile name. + * + * @see profile_load_multiple() + */ +function profile_load_by_user($account, $name = NULL) { + $cache = drupal_static(__FUNCTION__, array()); + $uid = is_object($account) ? $account->uid : $account; + + if (!isset($cache[$uid])) { + if (empty($name)) { + $profiles = profile_load_multiple(array(), array('uid' => $uid)); + // Cache ids for further lookups. + $cache[$uid] = array(); + foreach ($profiles as $pid => $profile) { + $cache[$uid][$profile->name] = $pid; + } + return array_combine(array_keys($cache[$uid]), $profiles); + } + $cache[$uid] = db_select('profile', 'p') + ->fields('p', array('name', 'pid')) + ->condition('uid', $uid) + ->execute() + ->fetchAllKeyed(); + } + if (isset($name)) { + return isset($cache[$uid][$name]) ? profile_load($cache[$uid][$name]) : FALSE; + } + // Return an array containing profiles keyed by profile name. + return $cache[$uid] ? array_combine(array_keys($cache[$uid]), profile_load_multiple($cache[$uid])) : $cache[$uid]; +} + +/** + * Deletes a profile + */ +function profile_delete($profile) { + db_delete('profile')->condition('pid', $profile->pid)->execute(); + // Invoke hook. + module_invoke_all('profile_delete', $profile); + field_attach_delete('profile', $profile); + + // Clear caches. + cache_clear_all(); + profile_load_multiple(FALSE, array(), TRUE); + drupal_static_reset('profile_load_by_user'); +} + +/** + * Implement hook_user_cancel(). + */ +function profile_user_cancel(&$edit, $account, $method) { + // Delete all profiles of the user in any case. + foreach (profile_load_by_user($account) as $profile) { + profile_delete($profile); + } +} + +/** + * Saves a profile to the database. + * + * @param $profile + * The profile object. + */ +function profile_save($profile) { + field_attach_presave('profile', $profile); + module_invoke_all('profile_presave', $profile); + + if (!empty($profile->pid)) { + $return = drupal_write_record('profile', $profile, 'pid'); + field_attach_update('profile', $profile); + module_invoke_all('profile_update', $profile); + } + else { + $return = drupal_write_record('profile', $profile); + field_attach_insert('profile', $profile); + module_invoke_all('profile_insert', $profile); + } + return $return; +} + +/** + * Saves a profile type to the db. + * + * @param $type + * An array of information about the type. + */ +function profile_type_save(array $type) { + $types = profile_get_types(); + // Save all additional properties to the 'data' field. + $data = $type; + unset($data['name'], $data['label'], $data['weight'], $data['locked'], $data['data']); + $type['data'] = $data; + + if (isset($types[$type['name']])) { + drupal_write_record('profile_type', $type, 'name'); + module_invoke_all('profile_type_update', $type); + } + else { + drupal_write_record('profile_type', $type); + field_attach_create_bundle('profile', $type['name']); + module_invoke_all('profile_type_insert', $type); + } + drupal_static_reset('profile_get_types'); +} + +/** + * Deletes a profile type from. + */ +function profile_type_delete(array $type) { + // Delete profiles. + $pids = db_select('profile', 'p') + ->fields('p', array('pid')) + ->condition('name', $type['name']) + ->execute() + ->fetchCol(); + foreach ($pids as $pid) { + profile_delete(profile_load($pid)); + } + db_delete('profile_type')->condition('name', $type['name'])->execute(); + // Invoke hook. + module_invoke_all('profile_type_delete', $type); + field_attach_delete_bundle($type['name']); +} + +/** + * Implement hook_profile_load() + */ +function profile_profile_load($profiles) { + $types = profile_get_types(); + // Load the profile's label. + foreach ($profiles as $profile) { + if (isset($types[$profile->name])) { + $profile->label = $types[$profile->name]['label']; + } + } +} + +/** + * Implement hook_user_view(). + */ +function profile_user_view($account) { + foreach (profile_get_types() as $name => $profile_type) { + if ($profile_type['user view'] && ($profile = profile_load_by_user($account, $name))) { + $account->content['profile_' . $name] = array( + '#type' => 'user_profile_category', + '#title' => $profile->label, + ); + $account->content['profile_' . $name] += field_attach_view('profile', $profile); + } + } +} + +/** + * Implement hook_field_build_modes(). + */ +function profile_field_build_modes($obj_type) { + if ($obj_type == 'profile') { + return array( + 'full' => t('Full profile'), + ); + } +} + +/** + * Implement hook_form_FORM_ID_alter() for the user edit form. + * + * @see profile_form_validate_handler + * @see profile_form_submit_handler + */ +function profile_form_user_profile_form_alter(&$form, &$form_state) { + if (($type = profile_get_types($form['#user_category'])) && $type['user category']) { + if (empty($form_state['profile'])) { + $form['#profile'] = profile_load_by_user($form['#user'], $form['#user_category']); + if (!$form['#profile']) { + $form['#profile'] = (object)array('name' => $form['#user_category'], 'uid' => $form['#user']->uid); + } + } + profile_attach_form($form, $form_state); + } +} + +/** + * Implement hook_form_FORM_ID_alter() for the registration form. * - * @see profile-block.tpl.php - */ -function template_preprocess_profile_block(&$variables) { - - $variables['user_picture'] = theme('user_picture', array('account' => $variables['account'])); - $variables['profile'] = array(); - // Supply filtered version of $fields that have values. - foreach ($variables['fields'] as $field) { - if ($field->value) { - $variables['profile'][$field->name]->title = check_plain($field->title); - $variables['profile'][$field->name]->value = $field->value; - $variables['profile'][$field->name]->type = $field->type; - } - } - -} - -/** - * Process variables for profile-listing.tpl.php. - * - * The $variables array contains the following arguments: - * - $account - * - $fields - * - * @see profile-listing.tpl.php - */ -function template_preprocess_profile_listing(&$variables) { - - $variables['user_picture'] = theme('user_picture', array('account' => $variables['account'])); - $variables['name'] = theme('username', array('account' => $variables['account'])); - $variables['profile'] = array(); - // Supply filtered version of $fields that have values. - foreach ($variables['fields'] as $field) { - if ($field->value) { - $variables['profile'][$field->name]->title = $field->title; - $variables['profile'][$field->name]->value = $field->value; - $variables['profile'][$field->name]->type = $field->type; - } - } - -} - -/** - * Process variables for profile-wrapper.tpl.php. - * - * The $variables array contains the following arguments: - * - $content - * - * @see profile-wrapper.tpl.php - */ -function template_preprocess_profile_wrapper(&$variables) { - $variables['current_field'] = ''; - if ($field = arg(1)) { - $variables['current_field'] = $field; - // Supply an alternate template suggestion based on the browsable field. - $variables['template_files'][] = 'profile-wrapper-' . $field; - } -} - -function _profile_field_types($type = NULL) { - $types = array('textfield' => t('single-line textfield'), - 'textarea' => t('multi-line textfield'), - 'checkbox' => t('checkbox'), - 'selection' => t('list selection'), - 'list' => t('freeform list'), - 'url' => t('URL'), - 'date' => t('date')); - return isset($type) ? $types[$type] : $types; -} - -function _profile_field_serialize($type = NULL) { - return $type == 'date'; -} - -function _profile_get_fields($category, $register = FALSE) { - $query = db_select('profile_field'); - if ($register) { - $query->condition('register', 1); - } - else { - // Use LOWER(:category) instead of PHP's strtolower() to avoid UTF-8 conversion issues. - $query->where('LOWER(category) = LOWER(:category)', array(':category' => $category)); - } - if (!user_access('administer users')) { - $query->condition('visibility', PROFILE_HIDDEN, '<>'); - } - return $query - ->fields('profile_field') - ->orderBy('category', 'ASC') - ->orderBy('weight', 'ASC') - ->execute(); -} - + * Any profile types with 'registration' TRUE are included. + */ +function profile_form_user_register_alter(&$form, &$form_state) { + $types = profile_get_types(); + foreach ($types as $name => $type) { + if ($type['registration']) { + // @todo, as I have no idea what these next 2 lines do + // and now this loops they are surely wrong + if (empty($form_state['profile'][$name])) { + $form['#profile'][$name] = (object)array('name' => $name); + } + profile_attach_form($form, $form_state); + } + } +} + +/** + * Attaches the profile form of the profile set in $form['#profile'] or + * $form_state['profile']. + * + * @see profile_form_validate_handler() + * @see profile_form_submit_handler() + */ +/////////////// all this is @todo +function Xprofile_attach_form(&$form, &$form_state) { + if (isset($form_state['profile'][$name])) { + // This is a multistep form rebuild, thus initialize with the given profile. + $form['#profile'][$name] = $form_state['profile'][$name]; + } + $form['#builder_function'] = 'profile_form_submit_builder'; + field_attach_form('profile', $form['#profile'][$name], $form, $form_state); + $form['#validate'][] = 'profile_form_validate_handler'; + $form['#submit'][] = 'profile_form_submit_handler'; +} + +/** + * @see profile_attach_form() + */ +function profile_form_validate_handler(&$form, &$form_state) { + field_attach_form_validate('profile', $form['#profile'][$name], $form, $form_state); +} + +/** + * @see profile_attach_form() + */ +function profile_form_submit_builder(&$form, &$form_state) { + field_attach_submit('profile', $form['#profile'], $form, $form_state); + $form_state['profile'] = $form['#profile']; + $form_state['rebuild'] = TRUE; + return $form['#profile']; +} + +/** + * @see profile_attach_form() + */ +function profile_form_submit_handler(&$form, &$form_state) { + $profile = profile_form_submit_builder($form, $form_state); + // During registration set the uid field of the newly created user. + if (empty($profile->uid) && isset($form_state['user']->uid)) { + $profile->uid = $form_state['user']->uid; + } + profile_save($profile); + unset($form_state['rebuild']); +} + +/** + * Implement hook_user_categories(). + */ +function profile_user_categories() { + $data = array(); + foreach (profile_get_types() as $name => $type) { + $data[] = array( + 'name' => $name, + 'title' => $type['label'], + // Add an offset so a weight of 0 appears right of the account category. + 'weight' => $type['weight'] + 3, + 'access callback' => 'profile_category_access', + 'access arguments' => array(1, $name) + ); + } + return $data; +} + +/** + * Menu item access callback - check if a user has access to a profile category. + */ +function profile_category_access($account, $profile_name) { + if (user_access('administer profiles') && $account->uid > 0) { + return TRUE; + } + else { + //TODO: Should we add a more sophisticated access handling invoking + // hook_profile_access ? + return $GLOBALS['user']->uid == $account->uid; + } +} Index: modules/profile/profile.test =================================================================== RCS file: /cvs/drupal/drupal/modules/profile/profile.test,v retrieving revision 1.21 diff -u -p -r1.21 profile.test --- modules/profile/profile.test 5 Oct 2009 01:18:25 -0000 1.21 +++ modules/profile/profile.test 16 Oct 2009 08:37:30 -0000 @@ -1,335 +1,100 @@ -admin_user = $this->drupalCreateUser(array('administer users', 'access user profiles')); - - // This is the user whose profile will be edited. - $this->normal_user = $this->drupalCreateUser(); - } - - /** - * Create a profile field. - * - * @param $type - * The field type to be created. - * @param $category - * The category in which the field should be created. - * @param $edit - * Additional parameters to be submitted. - * @return - * The fid of the field that was just created. - */ - function createProfileField($type = 'textfield', $category = 'simpletest', $edit = array()) { - $edit['title'] = $title = $this->randomName(8); - $edit['name'] = $form_name = 'profile_' . $title; - $edit['category'] = $category; - $edit['explanation'] = $this->randomName(50); - - $this->drupalPost('admin/config/people/profile/add/' . $type, $edit, t('Save field')); - $fid = db_query("SELECT fid FROM {profile_field} WHERE title = :title", array(':title' => $title))->fetchField(); - $this->assertTrue($fid, t('New Profile field has been entered in the database')); - - // Check that the new field is appearing on the user edit form. - $this->drupalGet('user/' . $this->admin_user->uid . '/edit/' . $category); - - // Checking field. - if ($type == 'date') { - $this->assertField($form_name . '[month]', t('Found month selection field')); - $this->assertField($form_name . '[day]', t('Found day selection field')); - $this->assertField($form_name . '[year]', t('Found day selection field')); - } - else { - $this->assertField($form_name , t('Found form named @name', array('@name' => $form_name))); - } - - // Checking name. - $this->assertText($title, t('Checking title for field %title', array('%title' => $title))); - // Checking explanation. - $this->assertText($edit['explanation'], t('Checking explanation for field %title', array('%title' => $title))); - - return array( - 'fid' => $fid, - 'type' => $type, - 'form_name' => $form_name, - 'title' => $title, - 'category' => $category, - ); - } - - /** - * Set the profile field to a random value - * - * @param $field - * The field that should be set. - * @param $value - * The value for the field, defaults to a random string. - * @return - * The value that has been assigned to - */ - function setProfileField($field, $value = NULL) { - - if (!isset($value)) { - $value = $this->randomName(); - } - - $edit = array( - $field['form_name'] => $value, - ); - $this->drupalPost('user/' . $this->normal_user->uid . '/edit/' . $field['category'], $edit, t('Save')); - - // Check profile page. - $content = $this->drupalGet('user/' . $this->normal_user->uid); - $this->assertText($field['title'], t('Found profile field with title %title', array('%title' => $field['title']))); - - if ($field['type'] != 'checkbox') { - // $value must be cast to a string in order to be found by assertText. - $this->assertText("$value", t('Found profile field with value %value', array('%value' => $value))); - } - - return $value; - } - - /** - * Delete a profile field. - * - * @param $field - * The field to be deleted. - */ - function deleteProfileField($field) { - $this->drupalPost('admin/config/people/profile/delete/' . $field['fid'], array(), t('Delete')); - $this->drupalGet('admin/config/people/profile'); - $this->assertNoText($field['title'], t('Checking deleted field %title', array('%title' => $field['title']))); - } -} - -class ProfileTestFields extends ProfileTestCase { - public static function getInfo() { - return array( - 'name' => 'Test single fields', - 'description' => 'Testing profile module with add/edit/delete textfield, textarea, list, checkbox, and url fields into profile page', - 'group' => 'Profile' - ); - } - - /** - * Test each of the field types. List selection and date fields are tested - * separately because they need some special handling. - */ - function testProfileFields() { - $this->drupalLogin($this->admin_user); - - // Set test values for every field type. - $field_types = array( - 'textfield' => $this->randomName(), - 'textarea' => $this->randomName(), - 'list' => $this->randomName(), - 'checkbox' => 1, - // An underscore is an invalid character in a domain name. The method randomName can - // return an underscore. - 'url' => 'http://www.' . str_replace('_', '', $this->randomName(10)) . '.org', - ); - - // For each field type, create a field, give it a value and delete the field. - foreach ($field_types as $type => $value) { - $field = $this->createProfileField($type); - $this->setProfileField($field, $value); - $this->deleteProfileField($field); - } - } -} - -class ProfileTestSelect extends ProfileTestCase { - public static function getInfo() { - return array( - 'name' => 'Test select field', - 'description' => 'Testing profile module with add/edit/delete a select field', - 'group' => 'Profile' - ); - } - - /** - * Create a list selection field, give it a value, and delete the field. - */ - function testProfileSelectionField() { - $this->drupalLogin($this->admin_user); - - $edit = array( - 'options' => implode("\n", range(1, 10)), - ); - $field = $this->createProfileField('selection', 'simpletest', $edit); - - $this->setProfileField($field, rand(1, 10)); - - $this->deleteProfileField($field); - } -} - -class ProfileTestDate extends ProfileTestCase { - public static function getInfo() { - return array( - 'name' => 'Test date field', - 'description' => 'Testing profile module with add/edit/delete a date field', - 'group' => 'Profile' - ); - } - - /** - * Create a date field, give it a value, and delete the field. - */ - function testProfileDateField() { - $this->drupalLogin($this->admin_user); - - variable_set('date_format_short', 'm/d/Y - H:i'); - $field = $this->createProfileField('date'); - - // Set date to January 09, 1983 - $edit = array( - $field['form_name'] . '[month]' => 1, - $field['form_name'] . '[day]' => 9, - $field['form_name'] . '[year]' => 1983, - ); - - $this->drupalPost('user/' . $this->normal_user->uid . '/edit/' . $field['category'], $edit, t('Save')); - - // Check profile page. - $this->drupalGet('user/' . $this->normal_user->uid); - $this->assertText($field['title'], t('Found profile field with title %title', array('%title' => $field['title']))); - - $this->assertText('01/09/1983', t('Found date profile field.')); - - $this->deleteProfileField($field); - } -} - -class ProfileTestWeights extends ProfileTestCase { - public static function getInfo() { - return array( - 'name' => 'Test field weights', - 'description' => 'Testing profile modules weigting of fields', - 'group' => 'Profile' - ); - } - - function testProfileFieldWeights() { - $this->drupalLogin($this->admin_user); - - $category = $this->randomName(); - $field1 = $this->createProfileField('textfield', $category, array('weight' => 1)); - $field2 = $this->createProfileField('textfield', $category, array('weight' => -1)); - - $this->setProfileField($field1, $this->randomName(8)); - $this->setProfileField($field2, $this->randomName(8)); - - $profile_edit = $this->drupalGet('user/' . $this->normal_user->uid . '/edit/' . $category); - $this->assertTrue(strpos($profile_edit, $field1['title']) > strpos($profile_edit, $field2['title']), t('Profile field weights are respected on the user edit form.')); - - $profile_page = $this->drupalGet('user/' . $this->normal_user->uid); - $this->assertTrue(strpos($profile_page, $field1['title']) > strpos($profile_page, $field2['title']), t('Profile field weights are respected on the user profile page.')); - } -} - -/** - * Test profile field autocompletion and access. - */ -class ProfileTestAutocomplete extends ProfileTestCase { - public static function getInfo() { - return array( - 'name' => 'Autocompletion', - 'description' => 'Test profile fields with autocompletion.', - 'group' => 'Profile' - ); - } - - /** - * Tests profile field autocompletion and access. - */ - function testAutocomplete() { - $this->drupalLogin($this->admin_user); - - // Create a new profile field with autocompletion enabled. - $category = $this->randomName(); - $field = $this->createProfileField('textfield', $category, array('weight' => 1, 'autocomplete' => 1)); - - // Enter profile field value. - $field['value'] = $this->randomName(); - $this->setProfileField($field, $field['value']); - - // Set some html for what we want to see in the page output later. - $autocomplete_html = ''; - $field_html = ''; - - // Check that autocompletion html is found on the user's profile edit page. - $this->drupalGet('user/' . $this->admin_user->uid . '/edit/' . $category); - $this->assertRaw($autocomplete_html, t('Autocomplete found.')); - $this->assertRaw('misc/autocomplete.js', t('Autocomplete JavaScript found.')); - $this->assertRaw('class="form-text form-autocomplete"', t('Autocomplete form element class found.')); - - // Check the autocompletion path using the first letter of our user's profile - // field value to make sure access is allowed and a valid result if found. - $this->drupalGet('profile/autocomplete/' . $field['fid'] . '/' . $field['value'][0]); - $this->assertResponse(200, t('Autocomplete path allowed to user with permission.')); - $this->assertRaw($field['value'], t('Autocomplete value found.')); - - // Logout and login with a user without the 'access user profiles' permission. - $this->drupalLogout(); - $this->drupalLogin($this->normal_user); - - // Check that autocompletion html is not found on the user's profile edit page. - $this->drupalGet('user/' . $this->normal_user->uid . '/edit/' . $category); - $this->assertNoRaw($autocomplete_html, t('Autocomplete not found.')); - - // User should be denied access to the profile autocomplete path. - $this->drupalGet('profile/autocomplete/' . $field['fid'] . '/' . $field['value'][0]); - $this->assertResponse(403, t('Autocomplete path denied to user without permission.')); - } -} - -class ProfileBlockTestCase extends DrupalWebTestCase { - public static function getInfo() { - return array( - 'name' => 'Block availability', - 'description' => 'Check if the author-information block is available.', - 'group' => 'Profile', - ); - } - - function setUp() { - parent::setUp('profile'); - - // Create and login user - $admin_user = $this->drupalCreateUser(array('administer blocks')); - $this->drupalLogin($admin_user); - } - - function testAuthorInformationBlock() { - // Set block title to confirm that the interface is availble. - $this->drupalPost('admin/structure/block/configure/profile/author-information', array('title' => $this->randomName(8)), t('Save block')); - $this->assertText(t('The block configuration has been saved.'), t('Block configuration set.')); - - // Set the block to a region to confirm block is availble. - $edit = array(); - $edit['profile_author-information[region]'] = 'footer'; - $this->drupalPost('admin/structure/block', $edit, t('Save blocks')); - $this->assertText(t('The block settings have been updated.'), t('Block successfully move to footer region.')); - } -} - - /** - * TODO: - * - Test field visibility - * - Test profile browsing - * - Test required fields - * - Test fields on registration form - * - Test updating fields - */ + 'Editing profiles', + 'description' => 'Tests basic CRUD and editing of profiles.', + 'group' => 'Profile', + ); + } + + function setUp() { + parent::setUp('profile'); + + profile_type_save(array( + 'name' => 'test', + 'label' => 'label', + 'weight' => 0 + )); + profile_type_save(array( + 'name' => 'test2', + 'label' => 'label2', + 'weight' => 2 + )); + profile_load_multiple(FALSE, array(), TRUE); + } + + /** + * Tests CRUD for a profile related to a user and one unrelated to a user. + */ + function testCRUD() { + return; + $user1 = $this->drupalCreateUser(); + // Create profiles for the user1 and unrelated to a user. + profile_save((object)array('name' => 'test', 'uid' => $user1->uid)); + profile_save((object)array('name' => 'test2', 'uid' => $user1->uid)); + $profile = (object)array('name' => 'test', 'uid' => NULL); + profile_save($profile); + + $profiles = profile_load_by_user($user1); + $this->assertEqual($profiles['test']->label, 'label', 'Created and loaded profile 1.'); + $this->assertEqual($profiles['test2']->label, 'label2', 'Created and loaded profile 2.'); + + // Test looking up from static cache works also. + $profiles = profile_load_by_user($user1); + $this->assertEqual($profiles['test']->label, 'label', 'Looked up profiles again.'); + + $loaded = profile_load($profile->pid); + $this->assertEqual($loaded->pid, $profile->pid, 'Loaded profile unrelated to a user.'); + + profile_delete($profiles['test']); + $profiles2 = profile_load_by_user($user1); + $this->assertEqual(array_keys($profiles2), array('test2'), 'Profile successfully deleted.'); + + profile_save($profiles2['test2']); + $this->assertEqual($profiles['test2']->pid, $profiles2['test2']->pid, 'Profile successfully updated.'); + + // Delete a profile type. + profile_type_delete(profile_get_types('test')); + } + + /** + * Test registration integration. + */ + function testRegistrationIntegration() { + // Allow registration by site visitors without administrator approval. + variable_set('user_register', 1); + $edit = array(); + $edit['name'] = $name = $this->randomName(); + $edit['mail'] = $mail = $edit['name'] . '@example.com'; + $edit['profile_fullname[zxx][0][value]'] = $this->randomName(); + $this->drupalPost('user/register', $edit, t('Create new account')); + $this->assertText(t('Your password and further instructions have been sent to your e-mail address.'), t('User registered successfully.')); + $new_user = reset(user_load_multiple(array(), array('name' => $name, 'mail' => $mail))); + $this->assertTrue($new_user->status, t('New account is active after registration.')); + $this->assertEqual(profile_load_by_user($new_user, 'main')->profile_fullname[FIELD_LANGUAGE_NONE][0]['value'], $edit['profile_fullname[zxx][0][value]'], 'Profile created.'); + } + + /** + * Test basic edit and display. + */ + function testEditAndDisplay() { + $user1 = $this->drupalCreateUser(); + $this->drupalLogin($user1); + // Create profiles for the user1. + $edit['profile_fullname[zxx][0][value]'] = $this->randomName(); + $this->drupalPost('user/' . $user1->uid . '/edit/main', $edit, t('Save')); + $this->assertText(t('The changes have been saved.'), 'Profile saved.'); + $this->assertEqual(profile_load_by_user($user1, 'main')->profile_fullname[FIELD_LANGUAGE_NONE][0]['value'], $edit['profile_fullname[zxx][0][value]'], 'Profile edited.'); + + $this->drupalGet('user/' . $user1->uid); + $this->assertText(check_plain($edit['profile_fullname[zxx][0][value]']), 'Profile displayed.'); + } + +}