diff --git modules/field/tests/field.test modules/field/tests/field.test index ee6351e..c5bf315 100644 --- modules/field/tests/field.test +++ modules/field/tests/field.test @@ -988,11 +988,12 @@ class FieldInfoTestCase extends FieldTestCase { */ function testFieldInfo() { // Test that field_test module's fields, widgets, and formatters show up. - $field_test_info = field_test_field_info(); - $formatter_info = field_test_field_formatter_info(); - $widget_info = field_test_field_widget_info(); - $storage_info = field_test_field_storage_info(); + $field_test_info = field_test_field_info(); + // We need to account for the existence of user_field_info_alter(). + foreach (array_keys($field_test_info) as $name) { + $field_test_info[$name]['instance_settings']['user_register_form'] = FALSE; + } $info = field_info_field_types(); foreach ($field_test_info as $t_key => $field_type) { foreach ($field_type as $key => $val) { @@ -1001,6 +1002,7 @@ class FieldInfoTestCase extends FieldTestCase { $this->assertEqual($info[$t_key]['module'], 'field_test', t("Field type field_test module appears")); } + $formatter_info = field_test_field_formatter_info(); $info = field_info_formatter_types(); foreach ($formatter_info as $f_key => $formatter) { foreach ($formatter as $key => $val) { @@ -1009,6 +1011,7 @@ class FieldInfoTestCase extends FieldTestCase { $this->assertEqual($info[$f_key]['module'], 'field_test', t("Formatter type field_test module appears")); } + $widget_info = field_test_field_widget_info(); $info = field_info_widget_types(); foreach ($widget_info as $w_key => $widget) { foreach ($widget as $key => $val) { @@ -1017,6 +1020,7 @@ class FieldInfoTestCase extends FieldTestCase { $this->assertEqual($info[$w_key]['module'], 'field_test', t("Widget type field_test module appears")); } + $storage_info = field_test_field_storage_info(); $info = field_info_storage_types(); foreach ($storage_info as $s_key => $storage) { foreach ($storage as $key => $val) { @@ -1180,6 +1184,10 @@ class FieldInfoTestCase extends FieldTestCase { */ function testSettingsInfo() { $info = field_test_field_info(); + // We need to account for the existence of user_field_info_alter(). + foreach (array_keys($info) as $name) { + $info[$name]['instance_settings']['user_register_form'] = FALSE; + } foreach ($info as $type => $data) { $this->assertIdentical(field_info_field_settings($type), $data['settings'], "field_info_field_settings returns {$type}'s field settings"); $this->assertIdentical(field_info_instance_settings($type), $data['instance_settings'], "field_info_field_settings returns {$type}'s field instance settings"); diff --git modules/field_ui/field_ui.admin.inc modules/field_ui/field_ui.admin.inc index 33924f7..8836a95 100644 --- modules/field_ui/field_ui.admin.inc +++ modules/field_ui/field_ui.admin.inc @@ -1731,6 +1731,7 @@ function field_ui_field_edit_form($form, &$form_state, $instance) { drupal_set_title($instance['label']); $form['#field'] = $field; + $form['#instance'] = $instance; if (!empty($field['locked'])) { $form['locked'] = array( diff --git modules/user/user.js modules/user/user.js index 1336d44..3d884ce 100644 --- modules/user/user.js +++ modules/user/user.js @@ -173,4 +173,25 @@ Drupal.evaluatePasswordStrength = function (password, translate) { }; +/** + * Field instance settings screen: force the 'Display on registration form' + * checkbox checked whenever 'Required' is checked. + */ +Drupal.behaviors.fieldUserRegistration = { + attach: function (context, settings) { + var $checkbox = $('form#field-ui-field-edit-form input#edit-instance-settings-user-register-form'); + + if ($checkbox.size()) { + $('input#edit-instance-required', context).once('user-register-form-checkbox', function () { + $(this).bind('change', function (e) { + if ($(this).attr('checked')) { + $checkbox.attr('checked', true); + } + }); + }); + + } + } +}; + })(jQuery); diff --git modules/user/user.module modules/user/user.module index da80733..ff47abf 100644 --- modules/user/user.module +++ modules/user/user.module @@ -177,6 +177,18 @@ function user_uri($user) { } /** + * Implements hook_field_info_alter(). + */ +function user_field_info_alter(&$info) { + // Add the 'user_register_form' instance setting to all field types. + foreach ($info as $field_type => $field_type_info) { + $info[$field_type]['instance_settings'] += array( + 'user_register_form' => FALSE, + ); + } +} + +/** * Implements hook_field_extra_fields(). */ function user_field_extra_fields() { @@ -3520,6 +3532,55 @@ function user_block_user_action(&$entity, $context = array()) { } /** + * Implements hook_form_FORM_ID_alter(). + * + * Add a checkbox for the 'user_register_form' instance settings on the 'Edit + * field instance' form. + */ +function user_form_field_ui_field_edit_form_alter(&$form, &$form_state, $form_id) { + $instance = $form['#instance']; + + if ($instance['entity_type'] == 'user') { + $form['instance']['settings']['user_register_form'] = array( + '#type' => 'checkbox', + '#title' => t('Display on user registration form.'), + '#description' => t("This is compulsory for 'required' fields."), + // Field instances created in D7 beta releases before the setting was + // introduced might be set as 'required' and 'not shown on user_register + // form'. We make sure the checkbox comes as 'checked' for those. + '#default_value' => $instance['settings']['user_register_form'] || $instance['required'], + // Display just below the 'required' checkbox. + '#weight' => $form['instance']['required']['#weight'] + .1, + // Disabled when the 'required' checkbox is checked. + '#states' => array( + 'enabled' => array('input[name="instance[required]"]' => array('checked' => FALSE)), + ), + // Checked when the 'required' checkbox is checked. This is done through + // a custom behavior, since the #states system would also synchronize on + // uncheck. + '#attached' => array( + 'js' => array(drupal_get_path('module', 'user') . '/user.js'), + ), + ); + + array_unshift($form['#submit'], 'user_form_field_ui_field_edit_form_submit'); + } +} + +/** + * Additional submit handler for the 'Edit field instance' form. + * + * Make sure the 'user_register_form' setting is set for required fields. + */ +function user_form_field_ui_field_edit_form_submit($form, &$form_state) { + $instance = $form_state['values']['instance']; + + if (!empty($instance['required'])) { + form_set_value($form['instance']['settings']['user_register_form'], 1, $form_state); + } +} + +/** * Form builder; the user registration form. * * @ingroup forms @@ -3546,6 +3607,15 @@ function user_register_form($form, &$form_state) { // Start with the default user account fields. user_account_form($form, $form_state); + // Attach field widgets, and hide the ones where the 'user_register_form' + // setting is not on. + field_attach_form('user', $form['#user'], $form, $form_state); + foreach (field_info_instances('user', 'user') as $field_name => $instance) { + if (empty($instance['settings']['user_register_form'])) { + $form[$field_name]['#access'] = FALSE; + } + } + if ($admin) { // Redirect back to page which initiated the create request; // usually admin/people/create. @@ -3558,6 +3628,7 @@ function user_register_form($form, &$form_state) { '#value' => t('Create new account'), ); + $form['#validate'][] = 'user_register_validate'; // Add the final user registration form submit handler. $form['#submit'][] = 'user_register_submit'; @@ -3565,6 +3636,13 @@ function user_register_form($form, &$form_state) { } /** + * Validation function for the user registration form. + */ +function user_register_validate($form, &$form_state) { + entity_form_field_validate('user', $form, $form_state); +} + +/** * Submit handler for the user registration form. * * This function is shared by the installation form and the normal registration form, @@ -3583,13 +3661,21 @@ function user_register_submit($form, &$form_state) { } $notify = !empty($form_state['values']['notify']); + // Remove unneeded values. form_state_values_clean($form_state); $form_state['values']['pass'] = $pass; $form_state['values']['init'] = $form_state['values']['mail']; $account = $form['#user']; - $account = user_save($account, $form_state['values']); + + entity_form_submit_build_entity('user', $account, $form, $form_state); + + // Populate $edit with the properties of $account, which have been edited on + // this form by taking over all values, which appear in the form values too. + $edit = array_intersect_key((array) $account, $form_state['values']); + $account = user_save($account, $edit); + // Terminate if an error occurred during user_save(). if (!$account) { drupal_set_message(t("Error saving user account."), 'error'); diff --git modules/user/user.test modules/user/user.test index a7925ca..977f5a3 100644 --- modules/user/user.test +++ modules/user/user.test @@ -10,6 +10,10 @@ class UserRegistrationTestCase extends DrupalWebTestCase { ); } + function setUp() { + parent::setUp('field_test'); + } + function testRegistrationWithEmailVerification() { // Require e-mail verification. variable_set('user_email_verification', TRUE); @@ -137,6 +141,91 @@ class UserRegistrationTestCase extends DrupalWebTestCase { $this->assertEqual($new_user->picture, '', t('Correct picture field.')); $this->assertEqual($new_user->init, $mail, t('Correct init field.')); } + + /** + * Tests Field API fields on user registration forms. + */ + function testRegistrationWithUserFields() { + // Create a field, and an instance on 'user' entity type. + $field = array( + 'type' => 'test_field', + 'field_name' => 'test_user_field', + 'cardinality' => 1, + ); + field_create_field($field); + $instance = array( + 'field_name' => 'test_user_field', + 'entity_type' => 'user', + 'label' => 'Some user field', + 'bundle' => 'user', + 'required' => TRUE, + 'settings' => array('user_register_form' => FALSE), + ); + field_create_instance($instance); + + // Check that the field does not appear on the registration form. + $this->drupalGet('user/register'); + $this->assertNoText($instance['label'], t('The field does not appear on user registration form')); + + // Have the field appear on the registration form. + $instance['settings']['user_register_form'] = TRUE; + field_update_instance($instance); + $this->drupalGet('user/register'); + $this->assertText($instance['label'], t('The field appears on user registration form')); + + // Check that validation errors are correctly reported. + $edit = array(); + $edit['name'] = $name = $this->randomName(); + $edit['mail'] = $mail = $edit['name'] . '@example.com'; + // Missing input in required field. + $edit['test_user_field[und][0][value]'] = ''; + $this->drupalPost(NULL, $edit, t('Create new account')); + $this->assertRaw(t('@name field is required.', array('@name' => $instance['label'])), t('Field validation error was correctly reported.')); + // Invalid input. + $edit['test_user_field[und][0][value]'] = '-1'; + $this->drupalPost(NULL, $edit, t('Create new account')); + $this->assertRaw(t('%name does not accept the value -1.', array('%name' => $instance['label'])), t('Field validation error was correctly reported.')); + + // Submit with valid data. + $value = rand(1, 255); + $edit['test_user_field[und][0][value]'] = $value; + $this->drupalPost(NULL, $edit, t('Create new account')); + // Check user fields. + $accounts = user_load_multiple(array(), array('name' => $name, 'mail' => $mail)); + $new_user = reset($accounts); + $this->assertEqual($new_user->test_user_field[LANGUAGE_NONE][0]['value'], $value, t('The field value was correclty saved.')); + + // Check that the 'add more' button works. + $field['cardinality'] = FIELD_CARDINALITY_UNLIMITED; + field_update_field($field); + foreach (array('js', 'nojs') as $js) { + $this->drupalGet('user/register'); + // Add two inputs. + $value = rand(1, 255); + $edit = array(); + $edit['test_user_field[und][0][value]'] = $value; + if ($js == 'js') { + $this->drupalPostAJAX(NULL, $edit, 'test_user_field_add_more'); + $this->drupalPostAJAX(NULL, $edit, 'test_user_field_add_more'); + } + else { + $this->drupalPost(NULL, $edit, t('Add another item')); + $this->drupalPost(NULL, $edit, t('Add another item')); + } + // Submit with three values. + $edit['test_user_field[und][1][value]'] = $value + 1; + $edit['test_user_field[und][2][value]'] = $value + 2; + $edit['name'] = $name = $this->randomName(); + $edit['mail'] = $mail = $edit['name'] . '@example.com'; + $this->drupalPost(NULL, $edit, t('Create new account')); + // Check user fields. + $accounts = user_load_multiple(array(), array('name' => $name, 'mail' => $mail)); + $new_user = reset($accounts); + $this->assertEqual($new_user->test_user_field[LANGUAGE_NONE][0]['value'], $value, t('@js : The field value was correclty saved.', array('@js' => $js))); + $this->assertEqual($new_user->test_user_field[LANGUAGE_NONE][1]['value'], $value + 1, t('@js : The field value was correclty saved.', array('@js' => $js))); + $this->assertEqual($new_user->test_user_field[LANGUAGE_NONE][2]['value'], $value + 2, t('@js : The field value was correclty saved.', array('@js' => $js))); + } + } } class UserValidationTestCase extends DrupalWebTestCase {