? .cache
? .settings
Index: modules/field/field.form.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/field/field.form.inc,v
retrieving revision 1.34
diff -u -p -r1.34 field.form.inc
--- modules/field/field.form.inc	11 Nov 2009 08:32:34 -0000	1.34
+++ modules/field/field.form.inc	19 Nov 2009 00:56:12 -0000
@@ -15,21 +15,13 @@ function field_default_form($obj_type, $
   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, $
     $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,12 +98,25 @@ function field_default_form($obj_type, $
       '#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.
+    $addition[$field_name] = array(
+      '#tree' => TRUE,
+    );
+    foreach ($items as $delta => $item) {
+      $addition[$field_name][$langcode][$delta] = array(
+        '#type' => 'value',
+        '#value' => $item,
+      );
+    }
   }
 
+  $form['#fields'][$field_name]['form_path'] = array($field_name);
+
   return $addition;
 }
 
@@ -122,6 +131,7 @@ function field_default_form($obj_type, $
 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 +151,8 @@ function field_multiple_value_form($fiel
 
   $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' => '<div id="' . $wrapper_id . '">',
-    '#suffix' => '</div>',
-    '#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 +184,47 @@ function field_multiple_value_form($fiel
             '#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' => '<div id="' . $wrapper_id . '">',
+        '#suffix' => '</div>',
+        '#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;
 }
 
 /**
Index: modules/field/field.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/field/field.test,v
retrieving revision 1.67
diff -u -p -r1.67 field.test
--- modules/field/field.test	12 Nov 2009 20:07:06 -0000	1.67
+++ modules/field/field.test	19 Nov 2009 00:56:39 -0000
@@ -1593,6 +1593,65 @@ class FieldFormTestCase extends FieldTes
   }
 
   /**
+   * 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.
    *
    * Stolen from poll.test. The JSON result is parsed into HTML and placed in
Index: modules/simpletest/tests/field_test.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/field_test.module,v
retrieving revision 1.38
diff -u -p -r1.38 field_test.module
--- modules/simpletest/tests/field_test.module	2 Nov 2009 03:41:58 -0000	1.38
+++ modules/simpletest/tests/field_test.module	19 Nov 2009 01:01:54 -0000
@@ -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['#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($
  */
 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;
