diff --git a/modules/field/field.form.inc b/modules/field/field.form.inc
index 372b712b88b..8b893ed32f4 100644
--- a/modules/field/field.form.inc
+++ b/modules/field/field.form.inc
@@ -15,21 +15,13 @@ function field_default_form($obj_type, $object, $field, $instance, $langcode, $i
if ($object) {
list($id, , ) = entity_extract_ids($obj_type, $object);
}
- $addition = array();
$field_name = $field['field_name'];
- // If the field is not accessible, don't add anything. The field value will
- // be left unchanged on update, or considered empty on insert (default value
- // will be inserted if applicable).
- if (!field_access('edit', $field, $obj_type, $object)) {
- return $addition;
- }
-
// Put field information at the top of the form, so that it can be easily
// retrieved.
- // Note : widgets and other form handling code should *always* fetch
- // field and instance information from $form['#fields'] rather than from
+ // Note : widgets and other form handling code should *always* fetch field
+ // and instance information from $form['#fields'] rather than from
// field_info_field(). This lets us build forms for 'variants' of a field,
// for instance on admin screens.
$form['#fields'][$field_name] = array(
@@ -42,54 +34,58 @@ function field_default_form($obj_type, $object, $field, $instance, $langcode, $i
$items = field_get_default_value($obj_type, $object, $field, $instance, $langcode);
}
- $form_element = array();
+ $field_elements = array();
- // If field module handles multiple values for this form element,
- // and we are displaying an individual element, process the multiple value
- // form.
- if (!isset($get_delta) && field_behaviors_widget('multiple values', $instance) == FIELD_BEHAVIOR_DEFAULT) {
- $form_element = field_multiple_value_form($field, $instance, $langcode, $items, $form, $form_state);
- }
- // If the widget is handling multiple values (e.g Options),
- // or if we are displaying an individual element, just get a single form
- // element and make it the $delta value.
- else {
- $delta = isset($get_delta) ? $get_delta : 0;
- $function = $instance['widget']['module'] . '_field_widget';
- if (function_exists($function)) {
- $element = array(
- '#object_type' => $instance['object_type'],
- '#bundle' => $instance['bundle'],
- '#field_name' => $field_name,
- '#columns' => array_keys($field['columns']),
- '#title' => check_plain(t($instance['label'])),
- '#description' => field_filter_xss($instance['description']),
- // Only the first widget should be required.
- '#required' => $delta == 0 && $instance['required'],
- '#delta' => $delta,
- );
- if ($element = $function($form, $form_state, $field, $instance, $langcode, $items, $delta, $element)) {
- // If we're processing a specific delta value for a field where the
- // field module handles multiples, set the delta in the result.
- // For fields that handle their own processing, we can't make assumptions
- // about how the field is structured, just merge in the returned value.
- if (field_behaviors_widget('multiple values', $instance) == FIELD_BEHAVIOR_DEFAULT) {
- $form_element[$delta] = $element;
- }
- else {
- $form_element = $element;
+ if (field_access('edit', $field, $obj_type, $object)) {
+ // If field module handles multiple values for this form element, and we
+ // are displaying an individual element, process the multiple value form.
+ if (!isset($get_delta) && field_behaviors_widget('multiple values', $instance) == FIELD_BEHAVIOR_DEFAULT) {
+ $field_elements = field_multiple_value_form($field, $instance, $langcode, $items, $form, $form_state);
+ }
+ // If the widget is handling multiple values (e.g Options), or if we are
+ // displaying an individual element, just get a single form element and
+ // make it the $delta value.
+ else {
+ $delta = isset($get_delta) ? $get_delta : 0;
+ $function = $instance['widget']['module'] . '_field_widget';
+ if (function_exists($function)) {
+ $element = array(
+ '#object_type' => $instance['object_type'],
+ '#bundle' => $instance['bundle'],
+ '#field_name' => $field_name,
+ '#columns' => array_keys($field['columns']),
+ '#title' => check_plain(t($instance['label'])),
+ '#description' => field_filter_xss($instance['description']),
+ // Only the first widget should be required.
+ '#required' => $delta == 0 && $instance['required'],
+ '#delta' => $delta,
+ );
+ if ($element = $function($form, $form_state, $field, $instance, $langcode, $items, $delta, $element)) {
+ // If we're processing a specific delta value for a field where the
+ // field module handles multiples, set the delta in the result.
+ // For fields that handle their own processing, we can't make
+ // assumptions about how the field is structured, just merge in the
+ // returned element.
+ if (field_behaviors_widget('multiple values', $instance) == FIELD_BEHAVIOR_DEFAULT) {
+ $field_elements[$delta] = $element;
+ }
+ else {
+ $field_elements = $element;
+ }
}
}
}
}
- if ($form_element) {
- // Add the field form element as a child keyed by language code to match the
- // field data structure: $object->{$field_name}[$langcode][$delta][$column].
- // The '#language' key can be used to access the field's form element when
- // $langcode is unknown. The #weight property is inherited from the field's
- // form element.
- // Also aid in theming of field widgets by rendering a classified container.
+ if ($field_elements) {
+ // Add the field form element as a child keyed by language code to match
+ // the field data structure:
+ // $object->{$field_name}[$langcode][$delta][$column].
+ // The '#language' key can be used to access the field's form element
+ // when $langcode is unknown. The #weight property is inherited from the
+ // field's form element.
+ // Also aid in theming of field widgets by rendering a classified
+ // container.
$addition[$field_name] = array(
'#type' => 'container',
'#attributes' => array(
@@ -102,11 +98,26 @@ function field_default_form($obj_type, $object, $field, $instance, $langcode, $i
'#tree' => TRUE,
'#weight' => $instance['widget']['weight'],
'#language' => $langcode,
- $langcode => $form_element,
+ $langcode => $field_elements,
);
-
- $form['#fields'][$field_name]['form_path'] = array($field_name);
}
+ else {
+ // The field is not accessible, or the widget did not return anything. Make
+ // sure the items are available in the submitted form values.
+ foreach ($items as $delta => $item) {
+ $field_elements[$delta] = array(
+ '#type' => 'value',
+ '#value' => $item,
+ );
+ }
+ $addition[$field_name] = array(
+ '#tree' => TRUE,
+ '#language' => $langcode,
+ $langcode => $field_elements,
+ );
+ }
+
+ $form['#fields'][$field_name]['form_path'] = array($field_name);
return $addition;
}
@@ -122,6 +133,7 @@ function field_default_form($obj_type, $object, $field, $instance, $langcode, $i
function field_multiple_value_form($field, $instance, $langcode, $items, &$form, &$form_state) {
$field_name = $field['field_name'];
+ // Determine the number of widgets to display.
switch ($field['cardinality']) {
case FIELD_CARDINALITY_UNLIMITED:
$filled_items = field_set_empty($field, $items);
@@ -141,20 +153,8 @@ function field_multiple_value_form($field, $instance, $langcode, $items, &$form,
$title = check_plain(t($instance['label']));
$description = field_filter_xss(t($instance['description']));
-
- $wrapper_id = str_replace('_', '-', $field_name) . '-wrapper';
-
- $form_element = array(
- '#theme' => 'field_multiple_value_form',
- '#field_name' => $field['field_name'],
- '#cardinality' => $field['cardinality'],
- '#title' => $title,
- '#required' => $instance['required'],
- '#description' => $description,
- '#prefix' => '
',
- '#suffix' => '
',
- '#max_delta' => $max,
- );
+ $wrapper_id = drupal_html_class($field_name) . '-wrapper';
+ $field_elements = array();
$function = $instance['widget']['module'] . '_field_widget';
if (function_exists($function)) {
@@ -186,34 +186,47 @@ function field_multiple_value_form($field, $instance, $langcode, $items, &$form,
'#weight' => 100,
);
}
- $form_element[$delta] = $element;
+ $field_elements[$delta] = $element;
}
}
- // Add 'add more' button, if not working with a programmed form.
- if ($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED && empty($form_state['programmed'])) {
- $form_element['add_more'] = array(
- '#type' => 'submit',
- '#name' => $field_name . '_add_more',
- '#value' => t('Add another item'),
- '#attributes' => array('class' => array('field-add-more-submit')),
- // Submit callback for disabled JavaScript.
- '#submit' => array('field_add_more_submit'),
- '#ajax' => array(
- 'callback' => 'field_add_more_js',
- 'wrapper' => $wrapper_id,
- 'method' => 'replace',
- 'effect' => 'fade',
- ),
- // The field_add_more_submit() and field_add_more_js() handlers will
- // find the relevant field using those entries.
- '#field_name' => $field_name,
- '#language' => $langcode,
+ if ($field_elements) {
+ $field_elements += array(
+ '#theme' => 'field_multiple_value_form',
+ '#field_name' => $field['field_name'],
+ '#cardinality' => $field['cardinality'],
+ '#title' => $title,
+ '#required' => $instance['required'],
+ '#description' => $description,
+ '#prefix' => '',
+ '#suffix' => '
',
+ '#max_delta' => $max,
);
+ // Add 'add more' button, if not working with a programmed form.
+ if ($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED && empty($form_state['programmed'])) {
+ $field_elements['add_more'] = array(
+ '#type' => 'submit',
+ '#name' => $field_name . '_add_more',
+ '#value' => t('Add another item'),
+ '#attributes' => array('class' => array('field-add-more-submit')),
+ // Submit callback for disabled JavaScript.
+ '#submit' => array('field_add_more_submit'),
+ '#ajax' => array(
+ 'callback' => 'field_add_more_js',
+ 'wrapper' => $wrapper_id,
+ 'method' => 'replace',
+ 'effect' => 'fade',
+ ),
+ // The field_add_more_submit() and field_add_more_js() handlers will
+ // find the relevant field using those entries.
+ '#field_name' => $field_name,
+ '#language' => $langcode,
+ );
+ }
}
}
- return $form_element;
+ return $field_elements;
}
/**
diff --git a/modules/field/field.test b/modules/field/field.test
index b85c4c59487..49a1a2452f9 100644
--- a/modules/field/field.test
+++ b/modules/field/field.test
@@ -1592,6 +1592,65 @@ class FieldFormTestCase extends FieldTestCase {
$this->assertNoField("$this->field_name[$langcode][" . ($delta + 1) . '][value]', 'No extraneous widget is displayed');
}
+ /**
+ * Tests fields with no 'edit' access.
+ */
+ function testFieldFormAccess() {
+ // Create a "regular" field.
+ $field = $this->field_single;
+ $field_name = $field['field_name'];
+ $instance = $this->instance;
+ $instance['field_name'] = $field_name;
+ field_create_field($field);
+ field_create_instance($instance);
+
+ // Create a field with no edit access - see field_test_field_access().
+ $field_no_access = array(
+ 'field_name' => 'field_no_edit_access',
+ 'type' => 'test_field',
+ );
+ $field_name_no_access = $field_no_access['field_name'];
+ $instance_no_access = array(
+ 'field_name' => $field_name_no_access,
+ 'object_type' => 'test_entity',
+ 'bundle' => 'test_bundle',
+ 'default_value' => array(0 => array('value' => 99)),
+ );
+ field_create_field($field_no_access);
+ field_create_instance($instance_no_access);
+
+ $langcode = FIELD_LANGUAGE_NONE;
+
+ // Display creation form.
+ $this->drupalGet('test-entity/add/test-bundle');
+ $this->assertNoFieldByName("{$field_name_no_access}[$langcode][0][value]", '', t('Widget is not displayed if field access is denied.'));
+
+ // Create entity.
+ $edit = array("{$field_name}[$langcode][0][value]" => 1);
+ $this->drupalPost(NULL, $edit, t('Save'));
+ preg_match('|test-entity/(\d+)/edit|', $this->url, $match);
+ $id = $match[1];
+
+ // Check that the default value was saved.
+ $entity = field_test_entity_test_load($id);
+ $this->assertEqual($entity->{$field_name_no_access}[$langcode][0]['value'], 99, t('Default value was saved for the field with no edit access.'));
+ $this->assertEqual($entity->{$field_name}[$langcode][0]['value'], 1, t('Entered value vas saved for the field with edit access.'));
+
+ // Create a new revision.
+ $edit = array("{$field_name}[$langcode][0][value]" => 2, 'revision' => TRUE);
+ $this->drupalPost('test-entity/' . $id . '/edit', $edit, t('Save'));
+
+ // Check that the new revision has the expected values.
+ $entity = field_test_entity_test_load($id);
+ $this->assertEqual($entity->{$field_name_no_access}[$langcode][0]['value'], 99, t('New revision has the expected value for the field with no edit access.'));
+ $this->assertEqual($entity->{$field_name}[$langcode][0]['value'], 2, t('New revision has the expected value for the field with edit access.'));
+
+ // Check that the revision is also saved in the revisions table.
+ $entity = field_test_entity_test_load($id, $entity->ftvid);
+ $this->assertEqual($entity->{$field_name_no_access}[$langcode][0]['value'], 99, t('New revision has the expected value for the field with no edit access.'));
+ $this->assertEqual($entity->{$field_name}[$langcode][0]['value'], 2, t('New revision has the expected value for the field with edit access.'));
+ }
+
/**
* Execute a POST request on a AHAH callback.
*
diff --git a/modules/simpletest/tests/field_test.module b/modules/simpletest/tests/field_test.module
index 538071deecd..a3cd45125b0 100644
--- a/modules/simpletest/tests/field_test.module
+++ b/modules/simpletest/tests/field_test.module
@@ -49,6 +49,15 @@ function field_test_menu() {
return $items;
}
+/**
+ * Implements hook_field_access().
+ */
+function field_test_field_access($op, $field, $obj_type, $object, $account) {
+ if ($field['field_name'] == "field_no_{$op}_access") {
+ return FALSE;
+ }
+ return TRUE;
+}
/**
*
@@ -312,7 +321,7 @@ function field_test_entity_add($fttype) {
$fttype = str_replace('-', '_', $fttype);
$entity = (object)array('fttype' => $fttype);
drupal_set_title(t('Create test_entity @bundle', array('@bundle' => $fttype)), PASS_THROUGH);
- return drupal_get_form('field_test_entity_form', $entity);
+ return drupal_get_form('field_test_entity_form', $entity, TRUE);
}
function field_test_entity_edit($entity) {
@@ -323,7 +332,7 @@ function field_test_entity_edit($entity) {
/**
* Form to set the value of fields attached to our entity.
*/
-function field_test_entity_form($form, &$form_state, $entity) {
+function field_test_entity_form($form, &$form_state, $entity, $add = FALSE) {
if (isset($form_state['test_entity'])) {
$entity = $form_state['test_entity'] + (array)$entity;
}
@@ -340,13 +349,15 @@ function field_test_entity_form($form, &$form_state, $entity) {
$form['#builder_function'] = 'field_test_entity_form_submit_builder';
field_attach_form('test_entity', $entity, $form, $form_state);
- $form['revision'] = array(
- '#access' => user_access('administer field_test content'),
- '#type' => 'checkbox',
- '#title' => t('Create new revision'),
- '#default_value' => FALSE,
- '#weight' => 100,
- );
+ if (!$add) {
+ $form['revision'] = array(
+ '#access' => user_access('administer field_test content'),
+ '#type' => 'checkbox',
+ '#title' => t('Create new revision'),
+ '#default_value' => FALSE,
+ '#weight' => 100,
+ );
+ }
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Save'),
@@ -391,6 +402,7 @@ function field_test_entity_form_submit($form, &$form_state) {
*/
function field_test_entity_form_submit_builder($form, &$form_state) {
$entity = field_test_create_stub_entity($form_state['values']['ftid'], $form_state['values']['ftvid'], $form_state['values']['fttype']);
+ $entity->revision = !empty($form_state['values']['revision']);
field_attach_submit('test_entity', $entity, $form, $form_state);
$form_state['test_entity'] = (array)$entity;