#636834 by yched: Fixed field revision data when user has no 'edit' access on the field (with tests).
parent
457a109406
commit
9b71489a48
|
@ -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' => '<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 +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' => '<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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue