core/modules/field/field.attach.inc | 5 +- .../Drupal/field/Tests/FieldAttachOtherTest.php | 177 ++++++++++++++++++-- .../lib/Drupal/field/Tests/FieldAttachTestBase.php | 30 +++- 3 files changed, 190 insertions(+), 22 deletions(-) diff --git a/core/modules/field/field.attach.inc b/core/modules/field/field.attach.inc index 6d133e6..3b3f73e 100644 --- a/core/modules/field/field.attach.inc +++ b/core/modules/field/field.attach.inc @@ -1051,9 +1051,10 @@ function field_attach_load_revision($entity_type, $entities, $options = array()) function field_attach_validate($entity_type, $entity, array $options = array()) { $errors = array(); // Check generic, field-type-agnostic errors first. - _field_invoke_default('validate', $entity_type, $entity, $errors, $options); + $null = NULL; + _field_invoke_default('validate', $entity_type, $entity, $errors, $null, $options); // Check field-type specific errors. - _field_invoke('validate', $entity_type, $entity, $errors, $options); + _field_invoke('validate', $entity_type, $entity, $errors, $null, $options); // Let other modules validate the entity. // Avoid module_invoke_all() to let $errors be taken by reference. diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldAttachOtherTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldAttachOtherTest.php index 581d1c1..0557362 100644 --- a/core/modules/field/lib/Drupal/field/Tests/FieldAttachOtherTest.php +++ b/core/modules/field/lib/Drupal/field/Tests/FieldAttachOtherTest.php @@ -25,13 +25,18 @@ public static function getInfo() { * Test field_attach_view() and field_attach_prepare_view(). */ function testFieldAttachView() { + $this->setUpSecondField(); + $entity_type = 'test_entity'; $entity_init = field_test_create_entity(); $langcode = LANGUAGE_NOT_SPECIFIED; + $options = array('field_name' => $this->field_name_2); // Populate values to be displayed. $values = $this->_generateTestFieldValues($this->field['cardinality']); $entity_init->{$this->field_name}[$langcode] = $values; + $values_2 = $this->_generateTestFieldValues($this->field_2['cardinality']); + $entity_init->{$this->field_name_2}[$langcode] = $values_2; // Simple formatter, label displayed. $entity = clone($entity_init); @@ -46,15 +51,47 @@ function testFieldAttachView() { ), ); field_update_instance($this->instance); + $formatter_setting_2 = $this->randomName(); + $this->instance_2['display'] = array( + 'full' => array( + 'label' => 'above', + 'type' => 'field_test_default', + 'settings' => array( + 'test_formatter_setting' => $formatter_setting_2, + ) + ), + ); + field_update_instance($this->instance_2); + // View all fields. field_attach_prepare_view($entity_type, array($entity->ftid => $entity), 'full'); $entity->content = field_attach_view($entity_type, $entity, 'full'); $output = drupal_render($entity->content); $this->content = $output; - $this->assertRaw($this->instance['label'], "Label is displayed."); + $this->assertRaw($this->instance['label'], "First field's label is displayed."); foreach ($values as $delta => $value) { $this->content = $output; $this->assertRaw("$formatter_setting|{$value['value']}", "Value $delta is displayed, formatter settings are applied."); } + $this->assertRaw($this->instance_2['label'], "Second field's label is displayed."); + foreach ($values_2 as $delta => $value) { + $this->content = $output; + $this->assertRaw("$formatter_setting_2|{$value['value']}", "Value $delta is displayed, formatter settings are applied."); + } + // View single field (the second field). + field_attach_prepare_view($entity_type, array($entity->ftid => $entity), 'full', $langcode, $options); + $entity->content = field_attach_view($entity_type, $entity, 'full', $langcode, $options); + $output = drupal_render($entity->content); + $this->content = $output; + $this->assertNoRaw($this->instance['label'], "First field's label is not displayed."); + foreach ($values as $delta => $value) { + $this->content = $output; + $this->assertNoRaw("$formatter_setting|{$value['value']}", "Value $delta is displayed, formatter settings are applied."); + } + $this->assertRaw($this->instance_2['label'], "Second field's label is displayed."); + foreach ($values_2 as $delta => $value) { + $this->content = $output; + $this->assertRaw("$formatter_setting_2|{$value['value']}", "Value $delta is displayed, formatter settings are applied."); + } // Label hidden. $entity = clone($entity_init); @@ -81,7 +118,7 @@ function testFieldAttachView() { $this->content = $output; $this->assertNoRaw($this->instance['label'], "Hidden field: label is not displayed."); foreach ($values as $delta => $value) { - $this->assertNoRaw($value['value'], "Hidden field: value $delta is not displayed."); + $this->assertNoRaw("$formatter_setting|{$value['value']}", "Hidden field: value $delta is not displayed."); } // Multiple formatter. @@ -291,19 +328,29 @@ function testFieldAttachCache() { * hook_field_validate. */ function testFieldAttachValidate() { + $this->setUpSecondField(); + $entity_type = 'test_entity'; $entity = field_test_create_entity(0, 0, $this->instance['bundle']); $langcode = LANGUAGE_NOT_SPECIFIED; - // Set up values to generate errors + // Set up all but one values of the first field to generate errors. $values = array(); for ($delta = 0; $delta < $this->field['cardinality']; $delta++) { $values[$delta]['value'] = -1; } - // Arrange for item 1 not to generate an error + // Arrange for item 1 not to generate an error. $values[1]['value'] = 1; $entity->{$this->field_name}[$langcode] = $values; + // Set up all values of the second field to generate errors. + $values_2 = array(); + for ($delta = 0; $delta < $this->field_2['cardinality']; $delta++) { + $values_2[$delta]['value'] = -1; + } + $entity->{$this->field_name_2}[$langcode] = $values_2; + + // Validate all fields. try { field_attach_validate($entity_type, $entity); } @@ -313,26 +360,57 @@ function testFieldAttachValidate() { foreach ($values as $delta => $value) { if ($value['value'] != 1) { - $this->assertIdentical($errors[$this->field_name][$langcode][$delta][0]['error'], 'field_test_invalid', "Error set on value $delta"); - $this->assertEqual(count($errors[$this->field_name][$langcode][$delta]), 1, "Only one error set on value $delta"); + $this->assertIdentical($errors[$this->field_name][$langcode][$delta][0]['error'], 'field_test_invalid', "Error set on first field's value $delta"); + $this->assertEqual(count($errors[$this->field_name][$langcode][$delta]), 1, "Only one error set on first field's value $delta"); unset($errors[$this->field_name][$langcode][$delta]); } else { - $this->assertFalse(isset($errors[$this->field_name][$langcode][$delta]), "No error set on value $delta"); + $this->assertFalse(isset($errors[$this->field_name][$langcode][$delta]), "No error set on first field's value $delta"); } } - $this->assertEqual(count($errors[$this->field_name][$langcode]), 0, 'No extraneous errors set'); + foreach ($values_2 as $delta => $value) { + $this->assertIdentical($errors[$this->field_name_2][$langcode][$delta][0]['error'], 'field_test_invalid', "Error set on second field's value $delta"); + $this->assertEqual(count($errors[$this->field_name_2][$langcode][$delta]), 1, "Only one error set on second field's value $delta"); + unset($errors[$this->field_name_2][$langcode][$delta]); + } + $this->assertEqual(count($errors[$this->field_name][$langcode]), 0, 'No extraneous errors set for first field'); + $this->assertEqual(count($errors[$this->field_name_2][$langcode]), 0, 'No extraneous errors set for second field'); + + // Validate a single field. + $options = array('field_name' => $this->field_name_2); + try { + field_attach_validate($entity_type, $entity, $options); + } + catch (FieldValidationException $e) { + $errors = $e->errors; + } + + foreach ($values_2 as $delta => $value) { + $this->assertIdentical($errors[$this->field_name_2][$langcode][$delta][0]['error'], 'field_test_invalid', "Error set on second field's value $delta"); + $this->assertEqual(count($errors[$this->field_name_2][$langcode][$delta]), 1, "Only one error set on second field's value $delta"); + unset($errors[$this->field_name_2][$langcode][$delta]); + } + $this->assertFalse(isset($errors[$this->field_name]), 'No validation errors are set for the first field, despite it having errors'); + $this->assertEqual(count($errors[$this->field_name_2][$langcode]), 0, 'No extraneous errors set for second field'); // Check that cardinality is validated. - $entity->{$this->field_name}[$langcode] = $this->_generateTestFieldValues($this->field['cardinality'] + 1); + $entity->{$this->field_name_2}[$langcode] = $this->_generateTestFieldValues($this->field_2['cardinality'] + 1); + // When validating all fields. try { field_attach_validate($entity_type, $entity); } catch (FieldValidationException $e) { $errors = $e->errors; } - $this->assertEqual($errors[$this->field_name][$langcode][0][0]['error'], 'field_cardinality', 'Cardinality validation failed.'); - + $this->assertEqual($errors[$this->field_name_2][$langcode][0][0]['error'], 'field_cardinality', 'Cardinality validation failed.'); + // When validating a single field (the second field). + try { + field_attach_validate($entity_type, $entity, $options); + } + catch (FieldValidationException $e) { + $errors = $e->errors; + } + $this->assertEqual($errors[$this->field_name_2][$langcode][0][0]['error'], 'field_cardinality', 'Cardinality validation failed.'); } /** @@ -342,18 +420,39 @@ function testFieldAttachValidate() { * widgets show up. */ function testFieldAttachForm() { + $this->setUpSecondField(); + $entity_type = 'test_entity'; $entity = field_test_create_entity(0, 0, $this->instance['bundle']); + $langcode = LANGUAGE_NOT_SPECIFIED; + // When generating form for all fields. $form = array(); $form_state = form_state_defaults(); field_attach_form($entity_type, $entity, $form, $form_state); - $langcode = LANGUAGE_NOT_SPECIFIED; - $this->assertEqual($form[$this->field_name][$langcode]['#title'], $this->instance['label'], "Form title is {$this->instance['label']}"); + $this->assertEqual($form[$this->field_name][$langcode]['#title'], $this->instance['label'], "First field's form title is {$this->instance['label']}"); + $this->assertEqual($form[$this->field_name_2][$langcode]['#title'], $this->instance_2['label'], "Second field's form title is {$this->instance_2['label']}"); for ($delta = 0; $delta < $this->field['cardinality']; $delta++) { // field_test_widget uses 'textfield' - $this->assertEqual($form[$this->field_name][$langcode][$delta]['value']['#type'], 'textfield', "Form delta $delta widget is textfield"); + $this->assertEqual($form[$this->field_name][$langcode][$delta]['value']['#type'], 'textfield', "First field's form delta $delta widget is textfield"); + } + for ($delta = 0; $delta < $this->field_2['cardinality']; $delta++) { + // field_test_widget uses 'textfield' + $this->assertEqual($form[$this->field_name_2][$langcode][$delta]['value']['#type'], 'textfield', "Second field's form delta $delta widget is textfield"); + } + + // When generating form for a single field (the second field). + $options = array('field_name' => $this->field_name_2); + $form = array(); + $form_state = form_state_defaults(); + field_attach_form($entity_type, $entity, $form, $form_state, NULL, $options); + + $this->assertFalse(isset($form[$this->field_name]), 'The first field does not exist in the form'); + $this->assertEqual($form[$this->field_name_2][$langcode]['#title'], $this->instance_2['label'], "Second field's form title is {$this->instance_2['label']}"); + for ($delta = 0; $delta < $this->field_2['cardinality']; $delta++) { + // field_test_widget uses 'textfield' + $this->assertEqual($form[$this->field_name_2][$langcode][$delta]['value']['#type'], 'textfield', "Second field's form delta $delta widget is textfield"); } } @@ -361,15 +460,19 @@ function testFieldAttachForm() { * Test field_attach_submit(). */ function testFieldAttachSubmit() { + $this->setUpSecondField(); + $entity_type = 'test_entity'; - $entity = field_test_create_entity(0, 0, $this->instance['bundle']); + $entity_init = field_test_create_entity(0, 0, $this->instance['bundle']); + $langcode = LANGUAGE_NOT_SPECIFIED; - // Build the form. + // Build the form for all fields. $form = array(); $form_state = form_state_defaults(); - field_attach_form($entity_type, $entity, $form, $form_state); + field_attach_form($entity_type, $entity_init, $form, $form_state); // Simulate incoming values. + // First field. $values = array(); $weights = array(); for ($delta = 0; $delta < $this->field['cardinality']; $delta++) { @@ -383,21 +486,59 @@ function testFieldAttachSubmit() { } // Leave an empty value. 'field_test' fields are empty if empty(). $values[1]['value'] = 0; + // Second field. + $values_2 = array(); + $weights_2 = array(); + for ($delta = 0; $delta < $this->field_2['cardinality']; $delta++) { + $values_2[$delta]['value'] = mt_rand(1, 127); + // Assign random weight. + do { + $weight = mt_rand(0, $this->field_2['cardinality']); + } while (in_array($weight, $weights_2)); + $weights_2[$delta] = $weight; + $values_2[$delta]['_weight'] = $weight; + } + // Leave an empty value. 'field_test' fields are empty if empty(). + $values_2[1]['value'] = 0; - $langcode = LANGUAGE_NOT_SPECIFIED; // Pretend the form has been built. drupal_prepare_form('field_test_entity_form', $form, $form_state); drupal_process_form('field_test_entity_form', $form, $form_state); $form_state['values'][$this->field_name][$langcode] = $values; + $form_state['values'][$this->field_name_2][$langcode] = $values_2; + + // Call field_attach_submit() for all fields. + $entity = clone($entity_init); field_attach_submit($entity_type, $entity, $form, $form_state); asort($weights); + asort($weights_2); $expected_values = array(); + $expected_values_2 = array(); foreach ($weights as $key => $value) { if ($key != 1) { $expected_values[] = array('value' => $values[$key]['value']); } } $this->assertIdentical($entity->{$this->field_name}[$langcode], $expected_values, 'Submit filters empty values'); + foreach ($weights_2 as $key => $value) { + if ($key != 1) { + $expected_values_2[] = array('value' => $values_2[$key]['value']); + } + } + $this->assertIdentical($entity->{$this->field_name_2}[$langcode], $expected_values_2, 'Submit filters empty values'); + + // Call field_attach_submit() for a single field (the second field). + $options = array('field_name' => $this->field_name_2); + $entity = clone($entity_init); + field_attach_submit($entity_type, $entity, $form, $form_state, $options); + $expected_values_2 = array(); + foreach ($weights_2 as $key => $value) { + if ($key != 1) { + $expected_values_2[] = array('value' => $values_2[$key]['value']); + } + } + $this->assertFalse(isset($entity->{$this->field_name}), 'The first field does not exist in the entity object'); + $this->assertIdentical($entity->{$this->field_name_2}[$langcode], $expected_values_2, 'Submit filters empty values'); } } diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldAttachTestBase.php b/core/modules/field/lib/Drupal/field/Tests/FieldAttachTestBase.php index 17c7a3b..37b30f2 100644 --- a/core/modules/field/lib/Drupal/field/Tests/FieldAttachTestBase.php +++ b/core/modules/field/lib/Drupal/field/Tests/FieldAttachTestBase.php @@ -19,7 +19,7 @@ function setUp() { parent::setUp(); - $this->field_name = drupal_strtolower($this->randomName() . '_field_name'); + $this->field_name = drupal_strtolower($this->randomName() . '_field_name_1'); $this->field = array('field_name' => $this->field_name, 'type' => 'test_field', 'cardinality' => 4); $this->field = field_create_field($this->field); $this->field_id = $this->field['id']; @@ -27,7 +27,7 @@ function setUp() { 'field_name' => $this->field_name, 'entity_type' => 'test_entity', 'bundle' => 'test_bundle', - 'label' => $this->randomName() . '_label', + 'label' => $this->randomName() . '_label_1', 'description' => $this->randomName() . '_description', 'weight' => mt_rand(0, 127), 'settings' => array( @@ -43,4 +43,30 @@ function setUp() { ); field_create_instance($this->instance); } + + function setUpSecondField() { + $this->field_name_2 = drupal_strtolower($this->randomName() . '_field_name_2'); + $this->field_2 = array('field_name' => $this->field_name_2, 'type' => 'test_field', 'cardinality' => 4); + $this->field_2 = field_create_field($this->field_2); + $this->field_id_2 = $this->field_2['id']; + $this->instance_2 = array( + 'field_name' => $this->field_name_2, + 'entity_type' => 'test_entity', + 'bundle' => 'test_bundle', + 'label' => $this->randomName() . '_label_2', + 'description' => $this->randomName() . '_description_2', + 'weight' => mt_rand(0, 127), + 'settings' => array( + 'test_instance_setting' => $this->randomName(), + ), + 'widget' => array( + 'type' => 'test_field_widget', + 'label' => 'Test Field 2', + 'settings' => array( + 'test_widget_setting' => $this->randomName(), + ) + ) + ); + field_create_instance($this->instance_2); + } }