Index: includes/form.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/form.inc,v retrieving revision 1.484 diff -u -p -r1.484 form.inc --- includes/form.inc 20 Aug 2010 01:08:18 -0000 1.484 +++ includes/form.inc 26 Aug 2010 17:51:27 -0000 @@ -1126,7 +1126,15 @@ function _form_validate(&$elements, &$fo // An unchecked checkbox has a #value of integer 0, different than string // '0', which could be a valid value. if (isset($elements['#needs_validation']) && $elements['#required'] && (!count($elements['#value']) || (is_string($elements['#value']) && strlen(trim($elements['#value'])) == 0) || $elements['#value'] === 0)) { - form_error($elements, $t('!name field is required.', array('!name' => $elements['#title']))); + $t_args = array( + '!title' => $elements['#title'], + ); + if (!empty($elements['#required_message'])) { + form_error($elements, $t($elements['#required_message'], $t_args)); + } + else { + form_error($elements, $t('!title field is required.', $t_args)); + } } // Call user-defined form level validators. @@ -1759,7 +1767,7 @@ function _form_builder_handle_input_elem // Avoid image buttons (which come with garbage value), so we only get value // for the button actually clicked. if (!isset($element['#value']) && empty($element['#has_garbage_value'])) { - $element['#value'] = isset($element['#default_value']) ? $element['#default_value'] : ''; + $element['#value'] = array_key_exists('#default_value', $element) ? $element['#default_value'] : ''; } } } @@ -2024,6 +2032,28 @@ function form_type_checkboxes_value($ele } /** + * Helper function to determine the value for a radios form element. + * + * @param $element + * The form element whose value is being populated. + * @param $input + * The incoming input to populate the form element. If this is FALSE, + * the element's default value should be returned. + * @return + * The data that will appear in the $element_state['values'] collection + * for this element. Return nothing to use the default. + */ +function form_type_radios_value(&$element, $input = FALSE) { + if ($input === FALSE) { + // If no #default_value was specified, and a user agent submits no value for + // #type 'radios', then _form_builder_handle_input_element() would assign an + // empty string as #value, which in turn would trigger an "illegal choice" + // error in _form_validate(). + $element += array('#default_value' => NULL); + } +} + +/** * Helper function to determine the value for a password_confirm form * element. * Index: modules/field/tests/field.test =================================================================== RCS file: /cvs/drupal/drupal/modules/field/tests/field.test,v retrieving revision 1.39 diff -u -p -r1.39 field.test --- modules/field/tests/field.test 18 Aug 2010 00:44:52 -0000 1.39 +++ modules/field/tests/field.test 26 Aug 2010 16:45:42 -0000 @@ -1300,7 +1300,7 @@ class FieldFormTestCase extends FieldTes // Submit with missing required value. $edit = array(); $this->drupalPost('test-entity/add/test-bundle', $edit, t('Save')); - $this->assertRaw(t('!name field is required.', array('!name' => $this->instance['label'])), 'Required field with no value fails validation'); + $this->assertRaw(t('!title field is required.', array('!title' => $this->instance['label'])), 'Required field with no value fails validation'); // Create an entity $value = mt_rand(1, 127); @@ -1316,7 +1316,7 @@ class FieldFormTestCase extends FieldTes $value = ''; $edit = array("{$this->field_name}[$langcode][0][value]" => $value); $this->drupalPost('test-entity/' . $id . '/edit', $edit, t('Save')); - $this->assertRaw(t('!name field is required.', array('!name' => $this->instance['label'])), 'Required field with no value fails validation'); + $this->assertRaw(t('!title field is required.', array('!title' => $this->instance['label'])), 'Required field with no value fails validation'); } // function testFieldFormMultiple() { Index: modules/file/file.module =================================================================== RCS file: /cvs/drupal/drupal/modules/file/file.module,v retrieving revision 1.36 diff -u -p -r1.36 file.module --- modules/file/file.module 23 Aug 2010 14:53:50 -0000 1.36 +++ modules/file/file.module 26 Aug 2010 16:45:42 -0000 @@ -555,7 +555,7 @@ function file_managed_file_validate(&$el // Check required property based on the FID. if ($element['#required'] && empty($element['fid']['#value']) && !in_array($clicked_button, array('upload_button', 'remove_button'))) { - form_error($element['upload'], t('!name field is required.', array('!name' => $element['#title']))); + form_error($element['upload'], t('!title field is required.', array('!title' => $element['#title']))); } // Consolidate the array value of this field to a single FID. Index: modules/simpletest/tests/form.test =================================================================== RCS file: /cvs/drupal/drupal/modules/simpletest/tests/form.test,v retrieving revision 1.61 diff -u -p -r1.61 form.test --- modules/simpletest/tests/form.test 18 Aug 2010 00:44:52 -0000 1.61 +++ modules/simpletest/tests/form.test 26 Aug 2010 17:51:02 -0000 @@ -7,6 +7,7 @@ */ class FormsTestCase extends DrupalWebTestCase { + protected $profile = 'testing'; public static function getInfo() { return array( @@ -17,7 +18,8 @@ class FormsTestCase extends DrupalWebTes } function setUp() { - parent::setUp('form_test'); + // testDisabledElements() requires File module's #type 'managed_file'. + parent::setUp('form_test', 'file'); } /** @@ -121,6 +123,22 @@ class FormsTestCase extends DrupalWebTes } /** + * Tests #required with custom validation errors. + * + * @see form_test_validate_required_form() + */ + function testRequiredValidation() { + $this->drupalPost('form-test/validate-required', array(), 'Submit'); + + // Verify that the #required error message can be overridden. + foreach (array('Textfield', 'Textarea', 'Checkboxes', 'Radios') as $title) { + $this->assertNoText(t('!title field is required.', array('!title' => $title))); + $this->assertText(strtr('Yo, ur !title iz amptee!', array('!title' => $title))); + } + $this->assertNoText(t('An illegal choice has been detected. Please contact the site administrator.')); + } + + /** * Test default value handling for checkboxes. * * @see _form_test_checkbox() @@ -129,7 +147,7 @@ class FormsTestCase extends DrupalWebTes // First, try to submit without the required checkbox. $edit = array(); $this->drupalPost('form-test/checkbox', $edit, t('Submit')); - $this->assertRaw(t('!name field is required.', array('!name' => 'required_checkbox')), t('A required checkbox is actually mandatory')); + $this->assertRaw(t('!title field is required.', array('!title' => 'required_checkbox')), t('A required checkbox is actually mandatory')); // Now try to submit the form correctly. $values = drupal_json_decode($this->drupalPost(NULL, array('required_checkbox' => 1), t('Submit'))); @@ -402,13 +420,13 @@ class FormValidationTestCase extends Dru // ensure that the title field is not validated, but the #element_validate // handler for the 'test' field is triggered. $this->drupalPost($path, $edit, t('Partial validate')); - $this->assertNoText(t('!name field is required.', array('!name' => 'Title'))); + $this->assertNoText(t('!title field is required.', array('!title' => 'Title'))); $this->assertText('Test element is invalid'); // Now test full form validation and ensure that the #element_validate // handler is still triggered. $this->drupalPost($path, $edit, t('Full validate')); - $this->assertText(t('!name field is required.', array('!name' => 'Title'))); + $this->assertText(t('!title field is required.', array('!title' => 'Title'))); $this->assertText('Test element is invalid'); } } @@ -831,7 +849,7 @@ class FormsFormStorageTestCase extends D // Test it again, but first trigger a validation error, then test. $this->drupalPost('form-test/state-persist', array('title' => ''), t('Submit'), $options); - $this->assertText(t('!name field is required.', array('!name' => 'title'))); + $this->assertText(t('!title field is required.', array('!title' => 'title'))); // Submit the form again triggering no validation error. $this->drupalPost(NULL, array('title' => 'foo'), t('Submit'), $options); $this->assertText('State persisted.'); Index: modules/simpletest/tests/form_test.module =================================================================== RCS file: /cvs/drupal/drupal/modules/simpletest/tests/form_test.module,v retrieving revision 1.47 diff -u -p -r1.47 form_test.module --- modules/simpletest/tests/form_test.module 31 Jul 2010 04:01:51 -0000 1.47 +++ modules/simpletest/tests/form_test.module 26 Aug 2010 16:45:42 -0000 @@ -24,6 +24,12 @@ function form_test_menu() { 'access arguments' => array('access content'), 'type' => MENU_CALLBACK, ); + $items['form-test/validate-required'] = array( + 'title' => 'Form #required validation', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('form_test_validate_required_form'), + 'access arguments' => array('access content'), + ); $items['form-test/limit-validation-errors'] = array( 'title' => 'Form validation with some error suppression', 'page callback' => 'drupal_get_form', @@ -298,6 +304,46 @@ function form_test_validate_form_validat } /** + * Form constructor for testing #required and custom form errors. + */ +function form_test_validate_required_form($form, &$form_state) { + $form['textfield'] = array( + '#type' => 'textfield', + '#title' => 'Textfield', + '#required' => TRUE, + '#required_message' => 'Yo, ur !title iz amptee!', + ); + $form['textarea'] = array( + '#type' => 'textarea', + '#title' => 'Textarea', + '#required' => TRUE, + '#required_message' => 'Yo, ur !title iz amptee!', + ); + $form['checkboxes'] = array( + '#type' => 'checkboxes', + '#title' => 'Checkboxes', + '#options' => array( + 'option1' => 'Option1', + 'option2' => 'Option2', + ), + '#required' => TRUE, + '#required_message' => 'Yo, ur !title iz amptee!', + ); + $form['radios'] = array( + '#type' => 'radios', + '#title' => 'Radios', + '#options' => array( + 'option1' => 'Option1', + 'option2' => 'Option2', + ), + '#required' => TRUE, + '#required_message' => 'Yo, ur !title iz amptee!', + ); + $form['submit'] = array('#type' => 'submit', '#value' => 'Submit'); + return $form; +} + +/** * Builds a simple form with a button triggering partial validation. */ function form_test_limit_validation_errors_form($form, &$form_state) {