#361683 follow-up by sun: Remove more windows line endings.

merge-requests/26/head
Angie Byron 2009-02-05 03:42:58 +00:00
parent 8bac2dd319
commit f3ed3283db
21 changed files with 5890 additions and 5890 deletions

View File

@ -2006,10 +2006,10 @@ function template_preprocess_node(&$variables) {
}
// Clean up name so there are no underscores.
$variables['template_files'][] = 'node-' . str_replace('_', '-', $node->type);
$variables['template_files'][] = 'node-' . $node->nid;
// Add $FIELD_NAME_rendered variables for fields.
drupal_function_exists('field_attach_preprocess');
$variables['template_files'][] = 'node-' . $node->nid;
// Add $FIELD_NAME_rendered variables for fields.
drupal_function_exists('field_attach_preprocess');
$variables += field_attach_preprocess('node', $node);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,408 +1,409 @@
<?php
// $Id$
// TODO : merge with field.default.inc ?
/**
* Create a separate form element for each field.
*/
function field_default_form($obj_type, $object, $field, $instance, $items, &$form, &$form_state, $get_delta = NULL) {
// This could be called with no object, as when a UI module creates a
// dummy form to set default values.
if ($object) {
list($id, ,) = field_attach_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.
// TODO : if/when field_attach_insert() takes care of default values,
// unaccessible fields will automatically get the default value on insert.
if (!field_access('edit', $field)) {
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
// field_info_field(). This lets us build forms for 'variants' of a field,
// for instance on admin screens.
$form['#fields'][$field_name] = array(
'field' => $field,
'instance' => $instance,
);
// TODO : why do we need this ?
$form['#cache'] = FALSE;
// Populate widgets with default values if we're creating a new object.
if (empty($items) && empty($id) && !empty($instance['default_value_function'])) {
$items = array();
$function = $instance['default_value_function'];
if (drupal_function_exists($function)) {
$items = $function($obj_type, $object, $field, $instance);
}
}
$form_element = 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, $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 (drupal_function_exists($function)) {
if ($element = $function($form, $form_state, $field, $instance, $items, $delta)) {
$defaults = array(
'#required' => $get_delta > 0 ? FALSE : $instance['required'],
'#columns' => array_keys($field['columns']),
'#title' => check_plain(t($instance['label'])),
'#description' => field_filter_xss($instance['description']),
'#delta' => $delta,
'#field_name' => $field['field_name'],
'#bundle' => $instance['bundle'],
);
$element = array_merge($element, $defaults);
// 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 ($form_element) {
$defaults = array(
'#field_name' => $field['field_name'],
'#tree' => TRUE,
'#weight' => $instance['weight'],
);
$addition[$field['field_name']] = array_merge($form_element, $defaults);
$form['#fields'][$field['field_name']]['form_path'] = array($field['field_name']);
}
return $addition;
}
/**
* Special handling to create form elements for multiple values.
*
* Handles generic features for multiple fields:
* - number of widgets
* - AHAH-'add more' button
* - drag-n-drop value reordering
*/
function field_multiple_value_form($field, $instance, $items, &$form, &$form_state) {
$field = field_info_field($instance['field_name']);
$field_name = $field['field_name'];
switch ($field['cardinality']) {
case FIELD_CARDINALITY_UNLIMITED:
$filled_items = field_set_empty($field, $items);
$current_item_count = isset($form_state['field_item_count'][$field_name])
? $form_state['field_item_count'][$field_name]
: count($items);
// We always want at least one empty icon for the user to fill in.
$max = ($current_item_count > count($filled_items))
? $current_item_count - 1
: $current_item_count;
break;
default:
$max = $field['cardinality'] - 1;
break;
}
$title = check_plain(t($instance['label']));
$description = field_filter_xss(t($instance['description']));
$form_element = array(
'#theme' => 'field_multiple_value_form',
'#multiple' => $field['cardinality'],
'#title' => $title,
'#required' => $instance['required'],
'#description' => $description,
);
$function = $instance['widget']['module'] . '_field_widget';
if (drupal_function_exists($function)) {
for ($delta = 0; $delta <= $max; $delta++) {
if ($element = $function($form, $form_state, $field, $instance, $items, $delta)) {
$multiple = $field['cardinality'] > 1 || $field['cardinality'] == FIELD_CARDINALITY_UNLIMITED;
$defaults = array(
'#title' => $multiple ? '' : $title,
'#description' => $multiple ? '' : $description,
'#required' => $delta == 0 && $instance['required'],
'#weight' => $delta,
'#delta' => $delta,
'#columns' => array_keys($field['columns']),
'#field_name' => $field_name,
'#bundle' => $instance['bundle'],
);
// Add an input field for the delta (drag-n-drop reordering), which will
// be hidden by tabledrag js behavior.
if ($multiple) {
// We name the element '_weight' to avoid clashing with column names
// defined by field modules.
$element['_weight'] = array(
'#type' => 'weight',
'#delta' => $max, // this 'delta' is the 'weight' element's property
'#default_value' => isset($items[$delta]['_weight']) ? $items[$delta]['_weight'] : $delta,
'#weight' => 100,
);
}
$form_element[$delta] = array_merge($element, $defaults);
}
}
// Add AHAH add more button, if not working with a programmed form.
if ($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED && empty($form['#programmed'])) {
// Make sure the form is cached so ahah can work.
$form['#cache'] = TRUE;
$bundle_name_url_str = str_replace('_', '-', $instance['bundle']);
$field_name_url_str = str_replace('_', '-', $field_name);
$form_element[$field_name . '_add_more'] = array(
'#type' => 'submit',
'#name' => $field_name . '_add_more',
'#value' => t('Add another item'),
'#weight' => $instance['weight'] + $max + 1,
// Submit callback for disabled JavaScript.
'#submit' => array('field_add_more_submit'),
'#ahah' => array(
'path' => 'field/js_add_more/' . $bundle_name_url_str . '/' . $field_name_url_str,
'wrapper' => $field_name_url_str . '-items',
'method' => 'replace',
'effect' => 'fade',
),
// When JS is disabled, the field_add_more_submit handler will find
// the relevant field using these entries.
'#field_name' => $field_name,
'#bundle' => $instance['bundle'],
);
// Add wrappers for the fields and 'more' button.
$form_element['#prefix'] = '<div class="clear-block" id="' . $field_name_url_str . '-add-more-wrapper"><div id="' . $field_name_url_str . '-items">';
$form_element[$field_name . '_add_more']['#prefix'] = '<div class="field-add-more">';
$form_element[$field_name . '_add_more']['#suffix'] = '</div></div></div>';
}
}
return $form_element;
}
/**
* Theme an individual form element.
*
* Combine multiple values into a table with drag-n-drop reordering.
* TODO : convert to a template.
*/
function theme_field_multiple_value_form($element) {
$output = '';
if ($element['#multiple'] > 1 || $element['#multiple'] == FIELD_CARDINALITY_UNLIMITED) {
$table_id = $element['#field_name'] . '_values';
$order_class = $element['#field_name'] . '-delta-order';
$required = !empty($element['#required']) ? '<span class="form-required" title="' . t('This field is required. ') . '">*</span>' : '';
$header = array(
array(
'data' => t('!title: !required', array('!title' => $element['#title'], '!required' => $required)),
'colspan' => 2
),
t('Order'),
);
$rows = array();
// Sort items according to '_weight' (needed when the form comes back after
// preview or failed validation)
$items = array();
foreach (element_children($element) as $key) {
if ($key !== $element['#field_name'] . '_add_more') {
$items[] = &$element[$key];
}
}
usort($items, '_field_sort_items_value_helper');
// Add the items as table rows.
foreach ($items as $key => $item) {
$item['_weight']['#attributes']['class'] = $order_class;
$delta_element = drupal_render($item['_weight']);
$cells = array(
array('data' => '', 'class' => 'field-multiple-drag'),
drupal_render($item),
array('data' => $delta_element, 'class' => 'delta-order'),
);
$rows[] = array(
'data' => $cells,
'class' => 'draggable',
);
}
$output .= theme('table', $header, $rows, array('id' => $table_id, 'class' => 'field-multiple-table'));
$output .= $element['#description'] ? '<div class="description">' . $element['#description'] . '</div>' : '';
$output .= drupal_render($element[$element['#field_name'] . '_add_more']);
drupal_add_tabledrag($table_id, 'order', 'sibling', $order_class);
}
else {
foreach (element_children($element) as $key) {
$output .= drupal_render($element[$key]);
}
}
return $output;
}
/**
* Submit handler to add more choices to a field form. This handler is used when
* JavaScript is not available. It makes changes to the form state and the
* entire form is rebuilt during the page reload.
*/
function field_add_more_submit($form, &$form_state) {
// Set the form to rebuild and run submit handlers.
if (isset($form['#builder_function']) && drupal_function_exists($form['#builder_function'])) {
$form['#builder_function']($form, $form_state);
// Make the changes we want to the form state.
$field_name = $form_state['clicked_button']['#field_name'];
if ($form_state['values'][$field_name][$field_name . '_add_more']) {
$form_state['field_item_count'][$field_name] = count($form_state['values'][$field_name]);
}
}
}
/**
* Menu callback for AHAH addition of new empty widgets.
*/
function field_add_more_js($bundle_name, $field_name) {
// Arguments are coming from the url, so we translate back dashes.
$field_name = str_replace('-', '_', $field_name);
$invalid = FALSE;
if (empty($_POST['form_build_id'])) {
// Invalid request.
$invalid = TRUE;
}
// Retrieve the cached form.
$form_state = array('submitted' => FALSE);
$form_build_id = $_POST['form_build_id'];
$form = form_get_cache($form_build_id, $form_state);
if (!$form) {
// Invalid form_build_id.
$invalid = TRUE;
}
// Retrieve field information.
$field = $form['#fields'][$field_name]['field'];
$instance = $form['#fields'][$field_name]['instance'];
$form_path = $form['#fields'][$field_name]['form_path'];
if ($field['cardinality'] != FIELD_CARDINALITY_UNLIMITED) {
// Ivnalid
$invalid = TRUE;
}
if ($invalid) {
drupal_json(array('data' => ''));
exit;
}
// We don't simply return a new empty widget row to append to existing ones,
// because:
// - ahah.js won't simply let us add a new row to a table
// - attaching the 'draggable' behavior won't be easy
// So we resort to rebuilding the whole table of widgets including the
// existing ones, which makes us jump through a few hoops.
// The form that we get from the cache is unbuilt. We need to build it so
// that _value callbacks can be executed and $form_state['values'] populated.
// We only want to affect $form_state['values'], not the $form itself
// (built forms aren't supposed to enter the cache) nor the rest of
// $form_state, so we use copies of $form and $form_state.
$form_copy = $form;
$form_state_copy = $form_state;
$form_copy['#post'] = array();
form_builder($_POST['form_id'], $form_copy, $form_state_copy);
// Just grab the data we need.
$form_state['values'] = $form_state_copy['values'];
// Reset cached ids, so that they don't affect the actual form we output.
form_clean_id(NULL, TRUE);
// Sort the $form_state['values'] we just built *and* the incoming $_POST data
// according to d-n-d reordering.
unset($form_state['values'][$field_name][$field['field_name'] . '_add_more']);
foreach ($_POST[$field_name] as $delta => $item) {
$form_state['values'][$field_name][$delta]['_weight'] = $item['_weight'];
}
$form_state['values'][$field_name] = _field_sort_items($field, $form_state['values'][$field_name]);
$_POST[$field_name] = _field_sort_items($field, $_POST[$field_name]);
// Build our new form element for the whole field, asking for one more element.
$form_state['field_item_count'] = array($field_name => count($_POST[$field_name]) + 1);
$items = $form_state['values'][$field_name];
$form_element = field_default_form(NULL, NULL, $field, $instance, $items, $form, $form_state);
// Let other modules alter it.
drupal_alter('form', $form_element, array(), 'field_add_more_js');
// Add the new element at the right location in the (original, unbuilt) form.
$target = &$form;
foreach ($form_path as $key) {
$target = &$target[$key];
}
$target = $form_element[$field_name];
// Save the new definition of the form.
$form_state['values'] = array();
form_set_cache($form_build_id, $form, $form_state);
// Build the new form against the incoming $_POST values so that we can
// render the new element.
$delta = max(array_keys($_POST[$field_name])) + 1;
$_POST[$field_name][$delta]['_weight'] = $delta;
$form_state = array('submitted' => FALSE);
$form += array(
'#post' => $_POST,
'#programmed' => FALSE,
);
$form = form_builder($_POST['form_id'], $form, $form_state);
// Render the new output.
// We get fetch the form element from the built $form.
$field_form = $form;
foreach ($form_path as $key) {
$field_form = $field_form[$key];
}
// We add a div around the new field to receive the ahah effect.
$field_form[$delta]['#prefix'] = '<div class="ahah-new-field">' . (isset($field_form[$delta]['#prefix']) ? $field_form[$delta]['#prefix'] : '');
$field_form[$delta]['#suffix'] = (isset($field_form[$delta]['#suffix']) ? $field_form[$delta]['#suffix'] : '') . '</div>';
// TODO : this causes duplication of the wrapping divs
// If a newly inserted widget contains AHAH behaviors, they normally won't
// work because AHAH doesn't know about those - it just attaches to the exact
// form elements that were initially specified in the Drupal.settings object.
// The new ones didn't exist then, so we need to update Drupal.settings
// by ourselves in order to let AHAH know about those new form elements.
$javascript = drupal_add_js(NULL, NULL);
$output_js = isset($javascript['setting']) ? '<script type="text/javascript">jQuery.extend(Drupal.settings, ' . drupal_to_js(call_user_func_array('array_merge_recursive', $javascript['setting'])) . ');</script>' : '';
$output = theme('status_messages') . drupal_render($field_form) . $output_js;
drupal_json(array('status' => TRUE, 'data' => $output));
exit;
}
<?php
// $Id$
// TODO : merge with field.default.inc ?
/**
* Create a separate form element for each field.
*/
function field_default_form($obj_type, $object, $field, $instance, $items, &$form, &$form_state, $get_delta = NULL) {
// This could be called with no object, as when a UI module creates a
// dummy form to set default values.
if ($object) {
list($id, ,) = field_attach_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.
// TODO : if/when field_attach_insert() takes care of default values,
// unaccessible fields will automatically get the default value on insert.
if (!field_access('edit', $field)) {
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
// field_info_field(). This lets us build forms for 'variants' of a field,
// for instance on admin screens.
$form['#fields'][$field_name] = array(
'field' => $field,
'instance' => $instance,
);
// TODO : why do we need this ?
$form['#cache'] = FALSE;
// Populate widgets with default values if we're creating a new object.
if (empty($items) && empty($id) && !empty($instance['default_value_function'])) {
$items = array();
$function = $instance['default_value_function'];
if (drupal_function_exists($function)) {
$items = $function($obj_type, $object, $field, $instance);
}
}
$form_element = 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, $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 (drupal_function_exists($function)) {
if ($element = $function($form, $form_state, $field, $instance, $items, $delta)) {
$defaults = array(
'#required' => $get_delta > 0 ? FALSE : $instance['required'],
'#columns' => array_keys($field['columns']),
'#title' => check_plain(t($instance['label'])),
'#description' => field_filter_xss($instance['description']),
'#delta' => $delta,
'#field_name' => $field['field_name'],
'#bundle' => $instance['bundle'],
);
$element = array_merge($element, $defaults);
// 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 ($form_element) {
$defaults = array(
'#field_name' => $field['field_name'],
'#tree' => TRUE,
'#weight' => $instance['weight'],
);
$addition[$field['field_name']] = array_merge($form_element, $defaults);
$form['#fields'][$field['field_name']]['form_path'] = array($field['field_name']);
}
return $addition;
}
/**
* Special handling to create form elements for multiple values.
*
* Handles generic features for multiple fields:
* - number of widgets
* - AHAH-'add more' button
* - drag-n-drop value reordering
*/
function field_multiple_value_form($field, $instance, $items, &$form, &$form_state) {
$field = field_info_field($instance['field_name']);
$field_name = $field['field_name'];
switch ($field['cardinality']) {
case FIELD_CARDINALITY_UNLIMITED:
$filled_items = field_set_empty($field, $items);
$current_item_count = isset($form_state['field_item_count'][$field_name])
? $form_state['field_item_count'][$field_name]
: count($items);
// We always want at least one empty icon for the user to fill in.
$max = ($current_item_count > count($filled_items))
? $current_item_count - 1
: $current_item_count;
break;
default:
$max = $field['cardinality'] - 1;
break;
}
$title = check_plain(t($instance['label']));
$description = field_filter_xss(t($instance['description']));
$form_element = array(
'#theme' => 'field_multiple_value_form',
'#multiple' => $field['cardinality'],
'#title' => $title,
'#required' => $instance['required'],
'#description' => $description,
);
$function = $instance['widget']['module'] . '_field_widget';
if (drupal_function_exists($function)) {
for ($delta = 0; $delta <= $max; $delta++) {
if ($element = $function($form, $form_state, $field, $instance, $items, $delta)) {
$multiple = $field['cardinality'] > 1 || $field['cardinality'] == FIELD_CARDINALITY_UNLIMITED;
$defaults = array(
'#title' => $multiple ? '' : $title,
'#description' => $multiple ? '' : $description,
'#required' => $delta == 0 && $instance['required'],
'#weight' => $delta,
'#delta' => $delta,
'#columns' => array_keys($field['columns']),
'#field_name' => $field_name,
'#bundle' => $instance['bundle'],
);
// Add an input field for the delta (drag-n-drop reordering), which will
// be hidden by tabledrag js behavior.
if ($multiple) {
// We name the element '_weight' to avoid clashing with column names
// defined by field modules.
$element['_weight'] = array(
'#type' => 'weight',
'#delta' => $max, // this 'delta' is the 'weight' element's property
'#default_value' => isset($items[$delta]['_weight']) ? $items[$delta]['_weight'] : $delta,
'#weight' => 100,
);
}
$form_element[$delta] = array_merge($element, $defaults);
}
}
// Add AHAH add more button, if not working with a programmed form.
if ($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED && empty($form['#programmed'])) {
// Make sure the form is cached so ahah can work.
$form['#cache'] = TRUE;
$bundle_name_url_str = str_replace('_', '-', $instance['bundle']);
$field_name_url_str = str_replace('_', '-', $field_name);
$form_element[$field_name . '_add_more'] = array(
'#type' => 'submit',
'#name' => $field_name . '_add_more',
'#value' => t('Add another item'),
'#weight' => $instance['weight'] + $max + 1,
// Submit callback for disabled JavaScript.
'#submit' => array('field_add_more_submit'),
'#ahah' => array(
'path' => 'field/js_add_more/' . $bundle_name_url_str . '/' . $field_name_url_str,
'wrapper' => $field_name_url_str . '-items',
'method' => 'replace',
'effect' => 'fade',
),
// When JS is disabled, the field_add_more_submit handler will find
// the relevant field using these entries.
'#field_name' => $field_name,
'#bundle' => $instance['bundle'],
);
// Add wrappers for the fields and 'more' button.
$form_element['#prefix'] = '<div class="clear-block" id="' . $field_name_url_str . '-add-more-wrapper"><div id="' . $field_name_url_str . '-items">';
$form_element[$field_name . '_add_more']['#prefix'] = '<div class="field-add-more">';
$form_element[$field_name . '_add_more']['#suffix'] = '</div></div></div>';
}
}
return $form_element;
}
/**
* Theme an individual form element.
*
* Combine multiple values into a table with drag-n-drop reordering.
* TODO : convert to a template.
*/
function theme_field_multiple_value_form($element) {
$output = '';
if ($element['#multiple'] > 1 || $element['#multiple'] == FIELD_CARDINALITY_UNLIMITED) {
$table_id = $element['#field_name'] . '_values';
$order_class = $element['#field_name'] . '-delta-order';
$required = !empty($element['#required']) ? '<span class="form-required" title="' . t('This field is required. ') . '">*</span>' : '';
$header = array(
array(
'data' => t('!title: !required', array('!title' => $element['#title'], '!required' => $required)),
'colspan' => 2
),
t('Order'),
);
$rows = array();
// Sort items according to '_weight' (needed when the form comes back after
// preview or failed validation)
$items = array();
foreach (element_children($element) as $key) {
if ($key !== $element['#field_name'] . '_add_more') {
$items[] = &$element[$key];
}
}
usort($items, '_field_sort_items_value_helper');
// Add the items as table rows.
foreach ($items as $key => $item) {
$item['_weight']['#attributes']['class'] = $order_class;
$delta_element = drupal_render($item['_weight']);
$cells = array(
array('data' => '', 'class' => 'field-multiple-drag'),
drupal_render($item),
array('data' => $delta_element, 'class' => 'delta-order'),
);
$rows[] = array(
'data' => $cells,
'class' => 'draggable',
);
}
$output .= theme('table', $header, $rows, array('id' => $table_id, 'class' => 'field-multiple-table'));
$output .= $element['#description'] ? '<div class="description">' . $element['#description'] . '</div>' : '';
$output .= drupal_render($element[$element['#field_name'] . '_add_more']);
drupal_add_tabledrag($table_id, 'order', 'sibling', $order_class);
}
else {
foreach (element_children($element) as $key) {
$output .= drupal_render($element[$key]);
}
}
return $output;
}
/**
* Submit handler to add more choices to a field form. This handler is used when
* JavaScript is not available. It makes changes to the form state and the
* entire form is rebuilt during the page reload.
*/
function field_add_more_submit($form, &$form_state) {
// Set the form to rebuild and run submit handlers.
if (isset($form['#builder_function']) && drupal_function_exists($form['#builder_function'])) {
$form['#builder_function']($form, $form_state);
// Make the changes we want to the form state.
$field_name = $form_state['clicked_button']['#field_name'];
if ($form_state['values'][$field_name][$field_name . '_add_more']) {
$form_state['field_item_count'][$field_name] = count($form_state['values'][$field_name]);
}
}
}
/**
* Menu callback for AHAH addition of new empty widgets.
*/
function field_add_more_js($bundle_name, $field_name) {
// Arguments are coming from the url, so we translate back dashes.
$field_name = str_replace('-', '_', $field_name);
$invalid = FALSE;
if (empty($_POST['form_build_id'])) {
// Invalid request.
$invalid = TRUE;
}
// Retrieve the cached form.
$form_state = array('submitted' => FALSE);
$form_build_id = $_POST['form_build_id'];
$form = form_get_cache($form_build_id, $form_state);
if (!$form) {
// Invalid form_build_id.
$invalid = TRUE;
}
// Retrieve field information.
$field = $form['#fields'][$field_name]['field'];
$instance = $form['#fields'][$field_name]['instance'];
$form_path = $form['#fields'][$field_name]['form_path'];
if ($field['cardinality'] != FIELD_CARDINALITY_UNLIMITED) {
// Ivnalid
$invalid = TRUE;
}
if ($invalid) {
drupal_json(array('data' => ''));
exit;
}
// We don't simply return a new empty widget row to append to existing ones,
// because:
// - ahah.js won't simply let us add a new row to a table
// - attaching the 'draggable' behavior won't be easy
// So we resort to rebuilding the whole table of widgets including the
// existing ones, which makes us jump through a few hoops.
// The form that we get from the cache is unbuilt. We need to build it so
// that _value callbacks can be executed and $form_state['values'] populated.
// We only want to affect $form_state['values'], not the $form itself
// (built forms aren't supposed to enter the cache) nor the rest of
// $form_state, so we use copies of $form and $form_state.
$form_copy = $form;
$form_state_copy = $form_state;
$form_copy['#post'] = array();
form_builder($_POST['form_id'], $form_copy, $form_state_copy);
// Just grab the data we need.
$form_state['values'] = $form_state_copy['values'];
// Reset cached ids, so that they don't affect the actual form we output.
form_clean_id(NULL, TRUE);
// Sort the $form_state['values'] we just built *and* the incoming $_POST data
// according to d-n-d reordering.
unset($form_state['values'][$field_name][$field['field_name'] . '_add_more']);
foreach ($_POST[$field_name] as $delta => $item) {
$form_state['values'][$field_name][$delta]['_weight'] = $item['_weight'];
}
$form_state['values'][$field_name] = _field_sort_items($field, $form_state['values'][$field_name]);
$_POST[$field_name] = _field_sort_items($field, $_POST[$field_name]);
// Build our new form element for the whole field, asking for one more element.
$form_state['field_item_count'] = array($field_name => count($_POST[$field_name]) + 1);
$items = $form_state['values'][$field_name];
$form_element = field_default_form(NULL, NULL, $field, $instance, $items, $form, $form_state);
// Let other modules alter it.
drupal_alter('form', $form_element, array(), 'field_add_more_js');
// Add the new element at the right location in the (original, unbuilt) form.
$target = &$form;
foreach ($form_path as $key) {
$target = &$target[$key];
}
$target = $form_element[$field_name];
// Save the new definition of the form.
$form_state['values'] = array();
form_set_cache($form_build_id, $form, $form_state);
// Build the new form against the incoming $_POST values so that we can
// render the new element.
$delta = max(array_keys($_POST[$field_name])) + 1;
$_POST[$field_name][$delta]['_weight'] = $delta;
$form_state = array('submitted' => FALSE);
$form += array(
'#post' => $_POST,
'#programmed' => FALSE,
);
$form = form_builder($_POST['form_id'], $form, $form_state);
// Render the new output.
// We get fetch the form element from the built $form.
$field_form = $form;
foreach ($form_path as $key) {
$field_form = $field_form[$key];
}
// We add a div around the new field to receive the ahah effect.
$field_form[$delta]['#prefix'] = '<div class="ahah-new-field">' . (isset($field_form[$delta]['#prefix']) ? $field_form[$delta]['#prefix'] : '');
$field_form[$delta]['#suffix'] = (isset($field_form[$delta]['#suffix']) ? $field_form[$delta]['#suffix'] : '') . '</div>';
// TODO : this causes duplication of the wrapping divs
// If a newly inserted widget contains AHAH behaviors, they normally won't
// work because AHAH doesn't know about those - it just attaches to the exact
// form elements that were initially specified in the Drupal.settings object.
// The new ones didn't exist then, so we need to update Drupal.settings
// by ourselves in order to let AHAH know about those new form elements.
$javascript = drupal_add_js(NULL, NULL);
$output_js = isset($javascript['setting']) ? '<script type="text/javascript">jQuery.extend(Drupal.settings, ' . drupal_to_js(call_user_func_array('array_merge_recursive', $javascript['setting'])) . ');</script>' : '';
$output = theme('status_messages') . drupal_render($field_form) . $output_js;
drupal_json(array('status' => TRUE, 'data' => $output));
exit;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,388 +1,388 @@
<?php
// $Id$
/**
* @file
* Default implementation of the field storage API.
*/
/**
* Implementation of hook_help().
*/
function field_sql_storage_help($path, $arg) {
switch ($path) {
case 'admin/help#field_sql_storage':
$output = '<p>' . t('The Field SQL Storage module stores Field API data in the database. It is the default field storage module, but other field storage modules may be available in the contributions repository.') . '</p>';
return $output;
}
}
/**
* Generate a table name for a field data table.
*
* @param $name
* The name of the field
* @return
* A string containing the generated name for the database table
*/
function _field_sql_storage_tablename($name) {
return 'field_data_' . $name;
}
/**
* Generate a table name for a field revision archive table.
*
* @param $name
* The name of the field
* @return
* A string containing the generated name for the database table
*/
function _field_sql_storage_revision_tablename($name) {
return 'field_data_revision_' . $name;
}
/**
* Generate a column name for a field data table.
*
* @param $name
* The name of the field
* @param $column
* The name of the column
* @return
* A string containing a generated column name for a field data
* table that is unique among all other fields.
*/
function _field_sql_storage_columnname($name, $column) {
return $name . '_' . $column;
}
/**
* Retrieve or assign an entity type id for an object type.
*
* @param $obj_type
* The object type, such as 'node' or 'user'.
* @return
* The entity type id.
*
* TODO: We need to decide on 'entity' or 'object'.
*/
function _field_sql_storage_etid($obj_type) {
$etid = variable_get('field_sql_storage_' . $obj_type . '_etid', NULL);
if (is_null($etid)) {
$etid = db_insert('field_config_entity_type')->fields(array('type' => $obj_type))->execute();
variable_set('field_sql_storage_' . $obj_type . '_etid', $etid);
}
return $etid;
}
/**
* Return the database schema for a field. This may contain one or
* more tables. Each table will contain the columns relevant for the
* specified field. Leave $field['columns'] empty to get only the
* base schema.
*
* @param $field
* The field structure for which to generate a database schema.
* @return
* One or more tables representing the schema for the field.
*/
function _field_sql_storage_schema($field) {
$current = array(
'description' => 'Data storage for field ' . $field['field_name'],
'fields' => array(
'etid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'description' => 'The entity type id this data is attached to',
),
'bundle' => array(
'type' => 'varchar',
'length' => 32,
'not null' => TRUE,
'default' => '',
'description' => 'The field instance bundle to which this row belongs, used when deleting a field instance',
),
'deleted' => array(
'type' => 'int',
'size' => 'tiny',
'not null' => TRUE,
'default' => 0,
'description' => 'A boolean indicating whether this data item has been deleted'
),
'entity_id' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'description' => 'The entity id this data is attached to',
),
'revision_id' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => FALSE,
'description' => 'The entity revision id this data is attached to, or NULL if the entity type is not versioned',
),
'delta' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'description' => 'The sequence number for this data item, used for multi-value fields',
),
),
'primary key' => array('etid', 'entity_id', 'deleted', 'delta'),
// TODO : index on 'bundle'
);
// Add field columns.
foreach ($field['columns'] as $column_name => $attributes) {
$current['fields'][_field_sql_storage_columnname($field['field_name'], $column_name)] = $attributes;
}
// Construct the revision table. The primary key includes
// revision_id but not entity_id so that multiple revision loads can
// use the IN operator.
$revision = $current;
$revision['description'] = 'Revision archive storage for field ' . $field['field_name'];
$revision['revision_id']['description'] = 'The entity revision id this data is attached to';
$revision['primary key'] = array('etid', 'revision_id', 'deleted', 'delta');
return array(
_field_sql_storage_tablename($field['field_name']) => $current,
_field_sql_storage_revision_tablename($field['field_name']) => $revision,
);
}
function field_sql_storage_field_storage_create_field($field) {
$schema = _field_sql_storage_schema($field);
foreach ($schema as $name => $table) {
db_create_table($ret, $name, $table);
}
}
function field_sql_storage_field_storage_delete_field($field_name) {
// Mark all data associated with the field for deletion.
$table = _field_sql_storage_tablename($field_name);
db_update($table)
->fields(array('deleted' => 1))
->execute();
}
/**
* Load field data for a set of objects from the database.
*
* @param $obj_type
* The entity type of objects being loaded, such as 'node' or
* 'user'.
* @param $objects
* The array of objects for which to load data.
* @param $age
* FIELD_LOAD_CURRENT to load the most recent revision for all
* fields, or FIELD_LOAD_REVISION to load the version indicated by
* each object.
* @return
* An array of field data for the objects, keyed by entity id, field
* name, and item delta number.
*/
function field_sql_storage_field_storage_load($obj_type, $objects, $age) {
$etid = _field_sql_storage_etid($obj_type);
$load_current = $age == FIELD_LOAD_CURRENT;
// Gather ids needed for each field.
$field_ids = array();
$delta_count = array();
foreach ($objects as $obj) {
list($id, $vid, $bundle) = field_attach_extract_ids($obj_type, $obj);
foreach (field_info_instances($bundle) as $instance) {
$field_ids[$instance['field_name']][] = $load_current ? $id : $vid;
$delta_count[$id][$instance['field_name']] = 0;
}
}
$additions = array();
foreach ($field_ids as $field_name => $ids) {
$field = field_info_field($field_name);
$table = $load_current ? _field_sql_storage_tablename($field_name) : _field_sql_storage_revision_tablename($field_name);
$results = db_select($table, 't')
->fields('t')
->condition('etid', $etid)
->condition($load_current ? 'entity_id' : 'revision_id', $ids, 'IN')
->condition('deleted', 0)
->orderBy('delta')
->execute();
foreach ($results as $row) {
if ($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED || $delta_count[$row->entity_id][$field_name] < $field['cardinality']) {
$item = array();
// For each column declared by the field, populate the item
// from the prefixed database column.
foreach ($field['columns'] as $column => $attributes) {
$item[$column] = $row->{_field_sql_storage_columnname($field_name, $column)};
}
// Add the item to the field values for the entity.
$additions[$row->entity_id][$field_name][] = $item;
$delta_count[$row->entity_id][$field_name]++;
}
}
}
return $additions;
}
function field_sql_storage_field_storage_write($obj_type, $object, $update = FALSE) {
list($id, $vid, $bundle) = field_attach_extract_ids($obj_type, $object);
$etid = _field_sql_storage_etid($obj_type);
$instances = field_info_instances($bundle);
foreach ($instances as $instance) {
$field_name = $instance['field_name'];
$table_name = _field_sql_storage_tablename($field_name);
$revision_name = _field_sql_storage_revision_tablename($field_name);
$field = field_read_field($field_name);
// Leave the field untouched if $object comes with no $field_name property.
// Empty the field if $object->$field_name is NULL or an empty array.
// Function property_exists() is slower, so we catch the more frequent cases
// where it's an empty array with the faster isset().
if (isset($object->$field_name) || property_exists($object, $field_name)) {
// Delete and insert, rather than update, in case a value was added.
if ($update) {
db_delete($table_name)->condition('etid', $etid)->condition('entity_id', $id)->execute();
if (isset($vid)) {
db_delete($revision_name)->condition('etid', $etid)->condition('entity_id', $id)->condition('revision_id', $vid)->execute();
}
}
if ($object->$field_name) {
// Prepare the multi-insert query.
$columns = array('etid', 'entity_id', 'revision_id', 'bundle', 'delta');
foreach ($field['columns'] as $column => $attributes) {
$columns[] = _field_sql_storage_columnname($field_name, $column);
}
$query = db_insert($table_name)->fields($columns);
if (isset($vid)) {
$revision_query = db_insert($revision_name)->fields($columns);
}
$delta_count = 0;
foreach ($object->$field_name as $delta => $item) {
$record = array(
'etid' => $etid,
'entity_id' => $id,
'revision_id' => $vid,
'bundle' => $bundle,
'delta' => $delta,
);
foreach ($field['columns'] as $column => $attributes) {
$record[_field_sql_storage_columnname($field_name, $column)] = isset($item[$column]) ? $item[$column] : NULL;
}
$query->values($record);
if (isset($vid)) {
$revision_query->values($record);
}
if ($field['cardinality'] != FIELD_CARDINALITY_UNLIMITED && ++$delta_count == $field['cardinality']) {
break;
}
}
// Execute the insert.
$query->execute();
if (isset($vid)) {
$revision_query->execute();
}
}
}
}
}
/**
* Delete all field data for a single object. This function actually
* deletes the data from the database.
*
* @param $obj_type
* The entity type of the object being deleted, such as 'node' or
* 'user'.
* @param $object
* The object for which to delete field data.
*/
function field_sql_storage_field_storage_delete($obj_type, $object) {
list($id, $vid, $bundle) = field_attach_extract_ids($obj_type, $object);
$etid = _field_sql_storage_etid($obj_type);
$instances = field_info_instances($bundle);
foreach ($instances as $instance) {
$field_name = $instance['field_name'];
$table_name = _field_sql_storage_tablename($field_name);
$revision_name = _field_sql_storage_revision_tablename($field_name);
db_delete($table_name)
->condition('etid', $etid)
->condition('entity_id', $id)
->execute();
db_delete($revision_name)
->condition('etid', $etid)
->condition('entity_id', $id)
->execute();
}
}
/**
* Delete field data for a single revision of a single object.
* Deleting the current (most recently written) revision is not
* allowed as has undefined results. This function actually deletes
* the data from the database.
*
* @param $obj_type
* The entity type of the object being deleted, such as 'node' or
* 'user'.
* @param $object
* The object for which to delete field data.
*/
function field_sql_storage_field_storage_delete_revision($obj_type, $object) {
list($id, $vid, $bundle) = field_attach_extract_ids($obj_type, $object);
$etid = _field_sql_storage_etid($obj_type);
if (isset($vid)) {
$instances = field_info_instances($bundle);
foreach ($instances as $instance) {
$field_name = $instance['field_name'];
$revision_name = _field_sql_storage_revision_tablename($field_name);
db_delete($revision_name)
->condition('etid', $etid)
->condition('entity_id', $id)
->condition('revision_id', $vid)
->execute();
}
}
}
function field_sql_storage_field_storage_delete_instance($field_name, $bundle) {
// Mark all data associated with the field for deletion.
$table_name = _field_sql_storage_tablename($field_name);
$revision_name = _field_sql_storage_revision_tablename($field_name);
db_update($table_name)
->fields(array('deleted' => 1))
->condition('bundle', $bundle)
->execute();
db_update($revision_name)
->fields(array('deleted' => 1))
->condition('bundle', $bundle)
->execute();
}
function field_sql_storage_field_storage_rename_bundle($bundle_old, $bundle_new) {
$instances = field_info_instances($bundle_old);
foreach ($instances as $instance) {
$table_name = _field_sql_storage_tablename($instance['field_name']);
$revision_name = _field_sql_storage_revision_tablename($instance['field_name']);
db_update($table_name)
->fields(array('bundle' => $bundle_new))
->condition('bundle', $bundle_old)
->execute();
db_update($revision_name)
->fields(array('bundle' => $bundle_new))
->condition('bundle', $bundle_old)
->execute();
}
<?php
// $Id$
/**
* @file
* Default implementation of the field storage API.
*/
/**
* Implementation of hook_help().
*/
function field_sql_storage_help($path, $arg) {
switch ($path) {
case 'admin/help#field_sql_storage':
$output = '<p>' . t('The Field SQL Storage module stores Field API data in the database. It is the default field storage module, but other field storage modules may be available in the contributions repository.') . '</p>';
return $output;
}
}
/**
* Generate a table name for a field data table.
*
* @param $name
* The name of the field
* @return
* A string containing the generated name for the database table
*/
function _field_sql_storage_tablename($name) {
return 'field_data_' . $name;
}
/**
* Generate a table name for a field revision archive table.
*
* @param $name
* The name of the field
* @return
* A string containing the generated name for the database table
*/
function _field_sql_storage_revision_tablename($name) {
return 'field_data_revision_' . $name;
}
/**
* Generate a column name for a field data table.
*
* @param $name
* The name of the field
* @param $column
* The name of the column
* @return
* A string containing a generated column name for a field data
* table that is unique among all other fields.
*/
function _field_sql_storage_columnname($name, $column) {
return $name . '_' . $column;
}
/**
* Retrieve or assign an entity type id for an object type.
*
* @param $obj_type
* The object type, such as 'node' or 'user'.
* @return
* The entity type id.
*
* TODO: We need to decide on 'entity' or 'object'.
*/
function _field_sql_storage_etid($obj_type) {
$etid = variable_get('field_sql_storage_' . $obj_type . '_etid', NULL);
if (is_null($etid)) {
$etid = db_insert('field_config_entity_type')->fields(array('type' => $obj_type))->execute();
variable_set('field_sql_storage_' . $obj_type . '_etid', $etid);
}
return $etid;
}
/**
* Return the database schema for a field. This may contain one or
* more tables. Each table will contain the columns relevant for the
* specified field. Leave $field['columns'] empty to get only the
* base schema.
*
* @param $field
* The field structure for which to generate a database schema.
* @return
* One or more tables representing the schema for the field.
*/
function _field_sql_storage_schema($field) {
$current = array(
'description' => 'Data storage for field ' . $field['field_name'],
'fields' => array(
'etid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'description' => 'The entity type id this data is attached to',
),
'bundle' => array(
'type' => 'varchar',
'length' => 32,
'not null' => TRUE,
'default' => '',
'description' => 'The field instance bundle to which this row belongs, used when deleting a field instance',
),
'deleted' => array(
'type' => 'int',
'size' => 'tiny',
'not null' => TRUE,
'default' => 0,
'description' => 'A boolean indicating whether this data item has been deleted'
),
'entity_id' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'description' => 'The entity id this data is attached to',
),
'revision_id' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => FALSE,
'description' => 'The entity revision id this data is attached to, or NULL if the entity type is not versioned',
),
'delta' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'description' => 'The sequence number for this data item, used for multi-value fields',
),
),
'primary key' => array('etid', 'entity_id', 'deleted', 'delta'),
// TODO : index on 'bundle'
);
// Add field columns.
foreach ($field['columns'] as $column_name => $attributes) {
$current['fields'][_field_sql_storage_columnname($field['field_name'], $column_name)] = $attributes;
}
// Construct the revision table. The primary key includes
// revision_id but not entity_id so that multiple revision loads can
// use the IN operator.
$revision = $current;
$revision['description'] = 'Revision archive storage for field ' . $field['field_name'];
$revision['revision_id']['description'] = 'The entity revision id this data is attached to';
$revision['primary key'] = array('etid', 'revision_id', 'deleted', 'delta');
return array(
_field_sql_storage_tablename($field['field_name']) => $current,
_field_sql_storage_revision_tablename($field['field_name']) => $revision,
);
}
function field_sql_storage_field_storage_create_field($field) {
$schema = _field_sql_storage_schema($field);
foreach ($schema as $name => $table) {
db_create_table($ret, $name, $table);
}
}
function field_sql_storage_field_storage_delete_field($field_name) {
// Mark all data associated with the field for deletion.
$table = _field_sql_storage_tablename($field_name);
db_update($table)
->fields(array('deleted' => 1))
->execute();
}
/**
* Load field data for a set of objects from the database.
*
* @param $obj_type
* The entity type of objects being loaded, such as 'node' or
* 'user'.
* @param $objects
* The array of objects for which to load data.
* @param $age
* FIELD_LOAD_CURRENT to load the most recent revision for all
* fields, or FIELD_LOAD_REVISION to load the version indicated by
* each object.
* @return
* An array of field data for the objects, keyed by entity id, field
* name, and item delta number.
*/
function field_sql_storage_field_storage_load($obj_type, $objects, $age) {
$etid = _field_sql_storage_etid($obj_type);
$load_current = $age == FIELD_LOAD_CURRENT;
// Gather ids needed for each field.
$field_ids = array();
$delta_count = array();
foreach ($objects as $obj) {
list($id, $vid, $bundle) = field_attach_extract_ids($obj_type, $obj);
foreach (field_info_instances($bundle) as $instance) {
$field_ids[$instance['field_name']][] = $load_current ? $id : $vid;
$delta_count[$id][$instance['field_name']] = 0;
}
}
$additions = array();
foreach ($field_ids as $field_name => $ids) {
$field = field_info_field($field_name);
$table = $load_current ? _field_sql_storage_tablename($field_name) : _field_sql_storage_revision_tablename($field_name);
$results = db_select($table, 't')
->fields('t')
->condition('etid', $etid)
->condition($load_current ? 'entity_id' : 'revision_id', $ids, 'IN')
->condition('deleted', 0)
->orderBy('delta')
->execute();
foreach ($results as $row) {
if ($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED || $delta_count[$row->entity_id][$field_name] < $field['cardinality']) {
$item = array();
// For each column declared by the field, populate the item
// from the prefixed database column.
foreach ($field['columns'] as $column => $attributes) {
$item[$column] = $row->{_field_sql_storage_columnname($field_name, $column)};
}
// Add the item to the field values for the entity.
$additions[$row->entity_id][$field_name][] = $item;
$delta_count[$row->entity_id][$field_name]++;
}
}
}
return $additions;
}
function field_sql_storage_field_storage_write($obj_type, $object, $update = FALSE) {
list($id, $vid, $bundle) = field_attach_extract_ids($obj_type, $object);
$etid = _field_sql_storage_etid($obj_type);
$instances = field_info_instances($bundle);
foreach ($instances as $instance) {
$field_name = $instance['field_name'];
$table_name = _field_sql_storage_tablename($field_name);
$revision_name = _field_sql_storage_revision_tablename($field_name);
$field = field_read_field($field_name);
// Leave the field untouched if $object comes with no $field_name property.
// Empty the field if $object->$field_name is NULL or an empty array.
// Function property_exists() is slower, so we catch the more frequent cases
// where it's an empty array with the faster isset().
if (isset($object->$field_name) || property_exists($object, $field_name)) {
// Delete and insert, rather than update, in case a value was added.
if ($update) {
db_delete($table_name)->condition('etid', $etid)->condition('entity_id', $id)->execute();
if (isset($vid)) {
db_delete($revision_name)->condition('etid', $etid)->condition('entity_id', $id)->condition('revision_id', $vid)->execute();
}
}
if ($object->$field_name) {
// Prepare the multi-insert query.
$columns = array('etid', 'entity_id', 'revision_id', 'bundle', 'delta');
foreach ($field['columns'] as $column => $attributes) {
$columns[] = _field_sql_storage_columnname($field_name, $column);
}
$query = db_insert($table_name)->fields($columns);
if (isset($vid)) {
$revision_query = db_insert($revision_name)->fields($columns);
}
$delta_count = 0;
foreach ($object->$field_name as $delta => $item) {
$record = array(
'etid' => $etid,
'entity_id' => $id,
'revision_id' => $vid,
'bundle' => $bundle,
'delta' => $delta,
);
foreach ($field['columns'] as $column => $attributes) {
$record[_field_sql_storage_columnname($field_name, $column)] = isset($item[$column]) ? $item[$column] : NULL;
}
$query->values($record);
if (isset($vid)) {
$revision_query->values($record);
}
if ($field['cardinality'] != FIELD_CARDINALITY_UNLIMITED && ++$delta_count == $field['cardinality']) {
break;
}
}
// Execute the insert.
$query->execute();
if (isset($vid)) {
$revision_query->execute();
}
}
}
}
}
/**
* Delete all field data for a single object. This function actually
* deletes the data from the database.
*
* @param $obj_type
* The entity type of the object being deleted, such as 'node' or
* 'user'.
* @param $object
* The object for which to delete field data.
*/
function field_sql_storage_field_storage_delete($obj_type, $object) {
list($id, $vid, $bundle) = field_attach_extract_ids($obj_type, $object);
$etid = _field_sql_storage_etid($obj_type);
$instances = field_info_instances($bundle);
foreach ($instances as $instance) {
$field_name = $instance['field_name'];
$table_name = _field_sql_storage_tablename($field_name);
$revision_name = _field_sql_storage_revision_tablename($field_name);
db_delete($table_name)
->condition('etid', $etid)
->condition('entity_id', $id)
->execute();
db_delete($revision_name)
->condition('etid', $etid)
->condition('entity_id', $id)
->execute();
}
}
/**
* Delete field data for a single revision of a single object.
* Deleting the current (most recently written) revision is not
* allowed as has undefined results. This function actually deletes
* the data from the database.
*
* @param $obj_type
* The entity type of the object being deleted, such as 'node' or
* 'user'.
* @param $object
* The object for which to delete field data.
*/
function field_sql_storage_field_storage_delete_revision($obj_type, $object) {
list($id, $vid, $bundle) = field_attach_extract_ids($obj_type, $object);
$etid = _field_sql_storage_etid($obj_type);
if (isset($vid)) {
$instances = field_info_instances($bundle);
foreach ($instances as $instance) {
$field_name = $instance['field_name'];
$revision_name = _field_sql_storage_revision_tablename($field_name);
db_delete($revision_name)
->condition('etid', $etid)
->condition('entity_id', $id)
->condition('revision_id', $vid)
->execute();
}
}
}
function field_sql_storage_field_storage_delete_instance($field_name, $bundle) {
// Mark all data associated with the field for deletion.
$table_name = _field_sql_storage_tablename($field_name);
$revision_name = _field_sql_storage_revision_tablename($field_name);
db_update($table_name)
->fields(array('deleted' => 1))
->condition('bundle', $bundle)
->execute();
db_update($revision_name)
->fields(array('deleted' => 1))
->condition('bundle', $bundle)
->execute();
}
function field_sql_storage_field_storage_rename_bundle($bundle_old, $bundle_new) {
$instances = field_info_instances($bundle_old);
foreach ($instances as $instance) {
$table_name = _field_sql_storage_tablename($instance['field_name']);
$revision_name = _field_sql_storage_revision_tablename($instance['field_name']);
db_update($table_name)
->fields(array('bundle' => $bundle_new))
->condition('bundle', $bundle_old)
->execute();
db_update($revision_name)
->fields(array('bundle' => $bundle_new))
->condition('bundle', $bundle_old)
->execute();
}
}

View File

@ -3,5 +3,4 @@ name = List
description = Defines list field types. Use with Options to create selection lists.
package = Core - fields
core = 7.x
files[]=list.module

View File

@ -1,188 +1,188 @@
<?php
// $Id$
/**
* @file
* Defines list field types that can be used with the Options module.
*/
/**
* Implementation of hook_theme().
*/
function list_theme() {
return array(
'field_formatter_list_default' => array(
'arguments' => array('element' => NULL),
),
'field_formatter_list_key' => array(
'arguments' => array('element' => NULL),
),
);
}
/**
* Implementation of hook_field_info().
*/
function list_field_info() {
return array(
'list' => array(
'label' => t('List'),
'description' => t('This field stores numeric keys from key/value lists of allowed values where the key is a simple alias for the position of the value, i.e. 0|First option, 1|Second option, 2|Third option.'),
'settings' => array('allowed_values_function' => ''),
'default_widget' => 'options_select',
'default_formatter' => 'list_default',
),
'list_boolean' => array(
'label' => t('Boolean'),
'description' => t('This field stores simple on/off or yes/no options.'),
'settings' => array('allowed_values_function' => ''),
'default_widget' => 'options_select',
'default_formatter' => 'list_default',
),
'list_number' => array(
'label' => t('List (numeric)'),
'description' => t('This field stores keys from key/value lists of allowed numbers where the stored numeric key has significance and must be preserved, i.e. \'Lifetime in days\': 1|1 day, 7|1 week, 31|1 month.'),
'settings' => array('allowed_values_function' => ''),
'default_widget' => 'options_select',
'default_formatter' => 'list_default',
),
'list_text' => array(
'label' => t('List (text)'),
'description' => t('This field stores keys from key/value lists of allowed values where the stored key has significance and must be a varchar, i.e. \'US States\': IL|Illinois, IA|Iowa, IN|Indiana'),
'settings' => array('allowed_values_function' => ''),
'default_widget' => 'options_select',
'default_formatter' => 'list_default',
),
);
}
/**
* Implementation of hook_field_schema().
*/
function list_field_columns($field) {
switch ($field['type']) {
case 'list_text':
$columns = array(
'value' => array(
'type' => 'varchar',
'length' => 255,
'not null' => FALSE,
),
);
break;
case 'list_number':
$columns = array(
'value' => array(
'type' => 'float',
'unsigned' => TRUE,
'not null' => FALSE,
),
);
break;
default:
$columns = array(
'value' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => FALSE,
),
);
break;
}
return $columns;
}
/**
* Implementation of hook_field_validate().
*/
function list_field_validate($obj_type, $object, $field, $instance, $items, $form) {
$allowed_values = list_allowed_values($field);
if (is_array($items)) {
foreach ($items as $delta => $item) {
$error_element = isset($item['_error_element']) ? $item['_error_element'] : '';
if (is_array($item) && isset($item['_error_element'])) unset($item['_error_element']);
if (!empty($item['value'])) {
if (count($allowed_values) && !array_key_exists($item['value'], $allowed_values)) {
form_set_error($error_element, t('%name: illegal value.', array('%name' => t($instance['label']))));
}
}
}
}
}
/**
* Implementation of hook_field_is_empty().
*/
function list_field_is_empty($item, $field) {
if (empty($item['value']) && (string)$item['value'] !== '0') {
return TRUE;
}
return FALSE;
}
/**
* Implementation of hook_field_formatter_info().
*/
function list_field_formatter_info() {
return array(
'list_default' => array(
'label' => t('Default'),
'field types' => array('list', 'list_boolean', 'list_text', 'list_number'),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_DEFAULT,
),
),
'list_key' => array(
'label' => t('Key'),
'field types' => array('list', 'list_boolean', 'list_text', 'list_number'),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_DEFAULT,
),
),
);
}
/**
* Theme function for 'default' list field formatter.
*/
function theme_field_formatter_list_default($element) {
$field = field_info_field($element['#field_name']);
if (($allowed_values = list_allowed_values($field)) && isset($allowed_values[$element['#item']['value']])) {
return $allowed_values[$element['#item']['value']];
}
// If no match was found in allowed values, fall back to the key.
return $element['#item']['safe'];
}
/**
* Theme function for 'key' list field formatter.
*/
function theme_field_formatter_list_key($element) {
return $element['#item']['safe'];
}
/**
* Create an array of the allowed values for this field.
*
* Call the allowed_values_function to retrieve the allowed
* values array.
*
* TODO Rework this to create a method of selecting plugable allowed values lists.
*/
function list_allowed_values($field) {
static $allowed_values;
if (isset($allowed_values[$field['field_name']])) {
return $allowed_values[$field['field_name']];
}
$allowed_values[$field['field_name']] = array();
if (isset($field['settings']['allowed_values_function'])) {
$function = $field['settings']['allowed_values_function'];
if (drupal_function_exists($function)) {
$allowed_values[$field['field_name']] = $function($field);
}
}
return $allowed_values[$field['field_name']];
}
<?php
// $Id$
/**
* @file
* Defines list field types that can be used with the Options module.
*/
/**
* Implementation of hook_theme().
*/
function list_theme() {
return array(
'field_formatter_list_default' => array(
'arguments' => array('element' => NULL),
),
'field_formatter_list_key' => array(
'arguments' => array('element' => NULL),
),
);
}
/**
* Implementation of hook_field_info().
*/
function list_field_info() {
return array(
'list' => array(
'label' => t('List'),
'description' => t('This field stores numeric keys from key/value lists of allowed values where the key is a simple alias for the position of the value, i.e. 0|First option, 1|Second option, 2|Third option.'),
'settings' => array('allowed_values_function' => ''),
'default_widget' => 'options_select',
'default_formatter' => 'list_default',
),
'list_boolean' => array(
'label' => t('Boolean'),
'description' => t('This field stores simple on/off or yes/no options.'),
'settings' => array('allowed_values_function' => ''),
'default_widget' => 'options_select',
'default_formatter' => 'list_default',
),
'list_number' => array(
'label' => t('List (numeric)'),
'description' => t('This field stores keys from key/value lists of allowed numbers where the stored numeric key has significance and must be preserved, i.e. \'Lifetime in days\': 1|1 day, 7|1 week, 31|1 month.'),
'settings' => array('allowed_values_function' => ''),
'default_widget' => 'options_select',
'default_formatter' => 'list_default',
),
'list_text' => array(
'label' => t('List (text)'),
'description' => t('This field stores keys from key/value lists of allowed values where the stored key has significance and must be a varchar, i.e. \'US States\': IL|Illinois, IA|Iowa, IN|Indiana'),
'settings' => array('allowed_values_function' => ''),
'default_widget' => 'options_select',
'default_formatter' => 'list_default',
),
);
}
/**
* Implementation of hook_field_schema().
*/
function list_field_columns($field) {
switch ($field['type']) {
case 'list_text':
$columns = array(
'value' => array(
'type' => 'varchar',
'length' => 255,
'not null' => FALSE,
),
);
break;
case 'list_number':
$columns = array(
'value' => array(
'type' => 'float',
'unsigned' => TRUE,
'not null' => FALSE,
),
);
break;
default:
$columns = array(
'value' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => FALSE,
),
);
break;
}
return $columns;
}
/**
* Implementation of hook_field_validate().
*/
function list_field_validate($obj_type, $object, $field, $instance, $items, $form) {
$allowed_values = list_allowed_values($field);
if (is_array($items)) {
foreach ($items as $delta => $item) {
$error_element = isset($item['_error_element']) ? $item['_error_element'] : '';
if (is_array($item) && isset($item['_error_element'])) unset($item['_error_element']);
if (!empty($item['value'])) {
if (count($allowed_values) && !array_key_exists($item['value'], $allowed_values)) {
form_set_error($error_element, t('%name: illegal value.', array('%name' => t($instance['label']))));
}
}
}
}
}
/**
* Implementation of hook_field_is_empty().
*/
function list_field_is_empty($item, $field) {
if (empty($item['value']) && (string)$item['value'] !== '0') {
return TRUE;
}
return FALSE;
}
/**
* Implementation of hook_field_formatter_info().
*/
function list_field_formatter_info() {
return array(
'list_default' => array(
'label' => t('Default'),
'field types' => array('list', 'list_boolean', 'list_text', 'list_number'),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_DEFAULT,
),
),
'list_key' => array(
'label' => t('Key'),
'field types' => array('list', 'list_boolean', 'list_text', 'list_number'),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_DEFAULT,
),
),
);
}
/**
* Theme function for 'default' list field formatter.
*/
function theme_field_formatter_list_default($element) {
$field = field_info_field($element['#field_name']);
if (($allowed_values = list_allowed_values($field)) && isset($allowed_values[$element['#item']['value']])) {
return $allowed_values[$element['#item']['value']];
}
// If no match was found in allowed values, fall back to the key.
return $element['#item']['safe'];
}
/**
* Theme function for 'key' list field formatter.
*/
function theme_field_formatter_list_key($element) {
return $element['#item']['safe'];
}
/**
* Create an array of the allowed values for this field.
*
* Call the allowed_values_function to retrieve the allowed
* values array.
*
* TODO Rework this to create a method of selecting plugable allowed values lists.
*/
function list_allowed_values($field) {
static $allowed_values;
if (isset($allowed_values[$field['field_name']])) {
return $allowed_values[$field['field_name']];
}
$allowed_values[$field['field_name']] = array();
if (isset($field['settings']['allowed_values_function'])) {
$function = $field['settings']['allowed_values_function'];
if (drupal_function_exists($function)) {
$allowed_values[$field['field_name']] = $function($field);
}
}
return $allowed_values[$field['field_name']];
}

View File

@ -3,5 +3,4 @@ name = Number
description = Defines numeric field types.
package = Core - fields
core = 7.x
files[]=number.module

View File

@ -1,425 +1,425 @@
<?php
// $Id$
/**
* @file
* Defines numeric field types.
*/
/**
* Implementation of hook_theme().
*/
function number_theme() {
return array(
'number' => array('arguments' => array('element' => NULL)),
'field_formatter_number_integer' => array('arguments' => array('element' => NULL), 'function' => 'theme_field_formatter_number'),
'field_formatter_number_decimal' => array('arguments' => array('element' => NULL), 'function' => 'theme_field_formatter_number'),
'field_formatter_number_unformatted' => array('arguments' => array('element' => NULL)),
);
}
/**
* Implementation of hook_field_info().
*/
function number_field_info() {
return array(
'number_integer' => array(
'label' => t('Integer'),
'description' => t('This field stores a number in the database as an integer.'),
'instance_settings' => array('min' => '', 'max' => '', 'prefix' => '', 'suffix' => ''),
'default_widget' => 'number',
'default_formatter' => 'number_integer',
),
'number_decimal' => array(
'label' => t('Decimal'),
'description' => t('This field stores a number in the database in a fixed decimal format.'),
'settings' => array('precision' => 10, 'scale' => 2, 'decimal' => ' .'),
'instance_settings' => array('min' => '', 'max' => '', 'prefix' => '', 'suffix' => ''),
'default_widget' => 'number',
'default_formatter' => 'number_integer',
),
'number_float' => array(
'label' => t('Float'),
'description' => t('This field stores a number in the database in a floating point format.'),
'instance_settings' => array('min' => '', 'max' => '', 'prefix' => '', 'suffix' => ''),
'default_widget' => 'number',
'default_formatter' => 'number_integer',
),
);
}
function number_field_columns($field) {
switch ($field['type']) {
case 'number_integer' :
$colums = array(
'value' => array(
'type' => 'int',
'not null' => FALSE
),
);
break;
case 'number_float' :
$colums = array(
'value' => array(
'type' => 'float',
'not null' => FALSE
),
);
break;
case 'number_decimal' :
$colums = array(
'value' => array(
'type' => 'numeric',
'precision' => $field['settings']['precision'],
'scale' => $field['settings']['scale'],
'not null' => FALSE
),
);
break;
}
return $colums;
}
/**
* Implementation of hook_field_validate().
*/
function number_field_validate($obj_type, $node, $field, $instance, &$items, $form) {
if (is_array($items)) {
foreach ($items as $delta => $item) {
$error_element = isset($item['_error_element']) ? $item['_error_element'] : '';
if (is_array($item) && isset($item['_error_element'])) unset($item['_error_element']);
if ($item['value'] != '') {
if (is_numeric($instance['settings']['min']) && $item['value'] < $instance['settings']['min']) {
form_set_error($error_element, t('%name: the value may be no smaller than %min.', array('%name' => t($instance['label']), '%min' => $instance['settings']['min'])));
}
if (is_numeric($instance['settings']['max']) && $item['value'] > $instance['settings']['max']) {
form_set_error($error_element, t('%name: the value may be no larger than %max.', array('%name' => t($instance['label']), '%max' => $instance['settings']['max'])));
}
}
}
}
}
/**
* Implementation of hook_content_is_empty().
*/
function number_field_is_empty($item, $field) {
if (empty($item['value']) && (string)$item['value'] !== '0') {
return TRUE;
}
return FALSE;
}
/**
* Implementation of hook_field_formatter_info().
*/
function number_field_formatter_info() {
return array(
'number_integer' => array(
'label' => t('default'),
'field types' => array('number_integer'),
'settings' => array(
'thousand_separator' => ' ',
'decimal_separator' => '.',
'scale' => 0,
'prefix_suffix' => TRUE,
),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_DEFAULT,
),
),
'number_decimal' => array(
'label' => t('default'),
'field types' => array('number_decimal', 'number_float'),
'settings' => array(
'thousand_separator' => ' ',
'decimal_separator' => '.',
'scale' => 2,
'prefix_suffix' => TRUE,
),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_DEFAULT,
),
),
'number_unformatted' => array(
'label' => t('unformatted'),
'field types' => array('number_integer', 'number_decimal', 'number_float'),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_DEFAULT,
),
),
);
}
/**
* Theme function for 'unformatted' number field formatter.
*/
function theme_field_formatter_number_unformatted($element) {
return $element['#item']['value'];
}
/**
* Proxy theme function for number field formatters.
*/
function theme_field_formatter_number($element) {
$field = field_info_field($element['#field_name']);
$instance = field_info_instance($element['#field_name'], $element['#bundle']);
$value = $element['#item']['value'];
$settings = $element['#settings'];
$formatter_type = $element['#formatter'];
if (empty($value) && $value !== '0') {
return '';
}
$output = number_format($value, $settings['scale'], $settings['decimal_separator'], $settings['thousand_separator']);
if ($settings['prefix_suffix']) {
$prefixes = isset($instance['settings']['prefix']) ? explode('|', check_plain($instance['settings']['prefix'])) : array(0 => '');
$suffixes = isset($instance['settings']['suffix']) ? explode('|', check_plain($instance['settings']['suffix'])) : array(0 => '');
$prefix = (count($prefixes) > 1) ? format_plural($value, $prefixes[0], $prefixes[1]) : $prefixes[0];
$suffix = (count($suffixes) > 1) ? format_plural($value, $suffixes[0], $suffixes[1]) : $suffixes[0];
$output = $prefix . $output . $suffix;
}
return $output;
}
/**
* Implementation of hook_field_widget_info().
*
* Here we indicate that the Field module will handle
* multiple values for these widgets.
*
* Callbacks can be omitted if default handing is used.
* They're included here just so this module can be used
* as an example for custom modules that might do things
* differently.
*/
function number_field_widget_info() {
return array(
'number' => array(
'label' => t('Text field'),
'field types' => array('number_integer', 'number_decimal', 'number_float'),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_DEFAULT,
'default value' => FIELD_BEHAVIOR_DEFAULT,
),
),
);
}
/**
* Implementation of FAPI hook_elements().
*
* Any FAPI callbacks needed for individual widgets can be declared here,
* and the element will be passed to those callbacks for processing.
*
* Drupal will automatically theme the element using a theme with
* the same name as the hook_elements key.
*
* Includes a regex to check for valid values as an additional parameter
* the validator can use. The regex can be overridden if necessary.
*/
function number_elements() {
return array(
'number' => array(
'#input' => TRUE,
'#columns' => array('value'), '#delta' => 0,
'#process' => array('number_process'),
),
);
}
/**
* Implementation of hook_field_widget().
*
* Attach a single form element to the form. It will be built out and
* validated in the callback(s) listed in hook_elements. We build it
* out in the callbacks rather than here in hook_widget so it can be
* plugged into any module that can provide it with valid
* $field information.
*
* Field module will set the weight, field name and delta values
* for each form element.
*
* If there are multiple values for this field, the Field module will
* call this function as many times as needed.
*
* @param $form
* the entire form array, $form['#node'] holds node information
* @param $form_state
* the form_state, $form_state['values'] holds the form values.
* @param $field
* The field structure.
* @param $instance
* the field instance array
* @param $delta
* the order of this item in the array of subelements (0, 1, 2, etc)
*
* @return
* the form item for a single element for this field
*/
function number_field_widget(&$form, &$form_state, $field, $instance, $items, $delta = 0) {
$element = array(
'#type' => $instance['widget']['type'],
'#default_value' => isset($items[$delta]) ? $items[$delta] : NULL,
);
return $element;
}
/**
* Process an individual element.
*
* Build the form element. When creating a form using FAPI #process,
* note that $element['#value'] is already set.
*
* The $field and $instance arrays are in $form['#fields'][$element['#field_name']].
*/
function number_process($element, $edit, $form_state, $form) {
$field_name = $element['#field_name'];
$field = field_info_field($element['#field_name']);
$instance = field_info_instance($element['#field_name'], $element['#bundle']);
$field_key = $element['#columns'][0];
$value = isset($element['#value'][$field_key]) ? $element['#value'][$field_key] : '';
if ($field['type'] == 'number_decimal') {
$value = str_replace('.', $field['settings']['decimal'], $value);
}
$element[$field_key] = array(
'#type' => 'textfield',
'#default_value' => $value,
// Need to allow a slightly larger size that the field length to allow
// for some configurations where all characters won't fit in input field.
'#size' => $field['type'] == 'number_decimal' ? $field['settings']['precision'] + 2 : 12,
'#maxlength' => $field['type'] == 'number_decimal' ? $field['settings']['precision'] : 10,
'#attributes' => array('class' => 'number'),
// The following values were set by the Field module and need
// to be passed down to the nested element.
'#title' => $element['#title'],
'#description' => $element['#description'],
'#required' => $element['#required'],
'#field_name' => $element['#field_name'],
'#bundle' => $element['#bundle'],
'#delta' => $element['#delta'],
'#columns' => $element['#columns'],
);
if (!empty($instance['settings']['prefix'])) {
$prefixes = explode('|', $instance['settings']['prefix']);
$element[$field_key]['#field_prefix'] = array_pop($prefixes);
}
if (!empty($instance['settings']['suffix'])) {
$suffixes = explode('|', $instance['settings']['suffix']);
$element[$field_key]['#field_suffix'] = array_pop($suffixes);
}
// Make sure we don't wipe out element validation added elsewhere.
if (empty($element['#element_validate'])) {
$element['#element_validate'] = array();
}
switch ($field['type']) {
case 'number_float':
$element['#element_validate'][] = 'number_float_validate';
break;
case 'number_integer':
$element['#element_validate'][] = 'number_integer_validate';
break;
case 'number_decimal':
$element['#element_validate'][] = 'number_decimal_validate';
break;
}
// Used so that hook_field('validate') knows where to flag an error.
$element['_error_element'] = array(
'#type' => 'value',
'#value' => implode('][', array_merge($element['#parents'], array($field_key))),
);
return $element;
}
/**
* FAPI validation of an individual float element.
*/
function number_float_validate($element, &$form_state) {
$field = field_info_field($element['#field_name']);
$instance = field_info_instance($element['#field_name'], $element['#bundle']);
$field_key = $element['#columns'][0];
$value = $element['#value'][$field_key];
if (($element[$field_key]['#required'] || !empty($value))) {
$start = $value;
$value = preg_replace('@[^-0-9\.]@', '', $value);
if ($start != $value) {
$error_field = implode('][', $element['#parents']) . '][' . $field_key;
form_set_error($error_field, t('Only numbers and decimals are allowed in %field.', array('%field' => t($instance['label']))));
}
else {
form_set_value($element[$field_key], $value, $form_state);
}
}
}
/**
* FAPI validation of an individual integer element.
*/
function number_integer_validate($element, &$form_state) {
$field = field_info_field($element['#field_name']);
$instance = field_info_instance($element['#field_name'], $element['#bundle']);
$field_key = $element['#columns'][0];
$value = $element['#value'][$field_key];
if (($element[$field_key]['#required'] || !empty($value))) {
$start = $value;
$value = preg_replace('@[^-0-9]@', '', $value);
if ($start != $value) {
$error_field = implode('][', $element['#parents']) . '][' . $field_key;
form_set_error($error_field, t('Only numbers are allowed in %field.', array('%field' => t($instance['label']))));
}
else {
form_set_value($element[$field_key], $value, $form_state);
}
}
}
/**
* FAPI validation of an individual decimal element.
*/
function number_decimal_validate($element, &$form_state) {
$field = field_info_field($element['#field_name']);
$instance = field_info_instance($element['#field_name'], $element['#bundle']);
$field_key = $element['#columns'][0];
$value = $element['#value'][$field_key];
if (($element[$field_key]['#required'] || !empty($value))) {
$start = $value;
$value = preg_replace('@[^-0-9\\' . $field['settings']['decimal'] . ']@', '', $value);
if ($start != $value) {
$error_field = implode('][', $element['#parents']) . '][' . $field_key;
form_set_error($error_field, t('Only numbers and the decimal character (%decimal) are allowed in %field.', array('%decimal' => $field['settings']['decimal'], '%field' => t($instance['label']))));
}
else {
$value = str_replace($field['settings']['decimal'], ' .', $value);
$value = round($value, $field['settings']['scale']);
form_set_value($element[$field_key], $value, $form_state);
}
}
}
/**
* FAPI theme for an individual number element.
*
* The textfield is already rendered by the textfield
* theme and the HTML output lives in $element['#children'].
* Override this theme to make custom changes to the output.
*
* $element['#field_name'] contains the field name
* $element['#delta] is the position of this element in the group
*/
function theme_number($element) {
return $element['#children'];
<?php
// $Id$
/**
* @file
* Defines numeric field types.
*/
/**
* Implementation of hook_theme().
*/
function number_theme() {
return array(
'number' => array('arguments' => array('element' => NULL)),
'field_formatter_number_integer' => array('arguments' => array('element' => NULL), 'function' => 'theme_field_formatter_number'),
'field_formatter_number_decimal' => array('arguments' => array('element' => NULL), 'function' => 'theme_field_formatter_number'),
'field_formatter_number_unformatted' => array('arguments' => array('element' => NULL)),
);
}
/**
* Implementation of hook_field_info().
*/
function number_field_info() {
return array(
'number_integer' => array(
'label' => t('Integer'),
'description' => t('This field stores a number in the database as an integer.'),
'instance_settings' => array('min' => '', 'max' => '', 'prefix' => '', 'suffix' => ''),
'default_widget' => 'number',
'default_formatter' => 'number_integer',
),
'number_decimal' => array(
'label' => t('Decimal'),
'description' => t('This field stores a number in the database in a fixed decimal format.'),
'settings' => array('precision' => 10, 'scale' => 2, 'decimal' => ' .'),
'instance_settings' => array('min' => '', 'max' => '', 'prefix' => '', 'suffix' => ''),
'default_widget' => 'number',
'default_formatter' => 'number_integer',
),
'number_float' => array(
'label' => t('Float'),
'description' => t('This field stores a number in the database in a floating point format.'),
'instance_settings' => array('min' => '', 'max' => '', 'prefix' => '', 'suffix' => ''),
'default_widget' => 'number',
'default_formatter' => 'number_integer',
),
);
}
function number_field_columns($field) {
switch ($field['type']) {
case 'number_integer' :
$colums = array(
'value' => array(
'type' => 'int',
'not null' => FALSE
),
);
break;
case 'number_float' :
$colums = array(
'value' => array(
'type' => 'float',
'not null' => FALSE
),
);
break;
case 'number_decimal' :
$colums = array(
'value' => array(
'type' => 'numeric',
'precision' => $field['settings']['precision'],
'scale' => $field['settings']['scale'],
'not null' => FALSE
),
);
break;
}
return $colums;
}
/**
* Implementation of hook_field_validate().
*/
function number_field_validate($obj_type, $node, $field, $instance, &$items, $form) {
if (is_array($items)) {
foreach ($items as $delta => $item) {
$error_element = isset($item['_error_element']) ? $item['_error_element'] : '';
if (is_array($item) && isset($item['_error_element'])) unset($item['_error_element']);
if ($item['value'] != '') {
if (is_numeric($instance['settings']['min']) && $item['value'] < $instance['settings']['min']) {
form_set_error($error_element, t('%name: the value may be no smaller than %min.', array('%name' => t($instance['label']), '%min' => $instance['settings']['min'])));
}
if (is_numeric($instance['settings']['max']) && $item['value'] > $instance['settings']['max']) {
form_set_error($error_element, t('%name: the value may be no larger than %max.', array('%name' => t($instance['label']), '%max' => $instance['settings']['max'])));
}
}
}
}
}
/**
* Implementation of hook_content_is_empty().
*/
function number_field_is_empty($item, $field) {
if (empty($item['value']) && (string)$item['value'] !== '0') {
return TRUE;
}
return FALSE;
}
/**
* Implementation of hook_field_formatter_info().
*/
function number_field_formatter_info() {
return array(
'number_integer' => array(
'label' => t('default'),
'field types' => array('number_integer'),
'settings' => array(
'thousand_separator' => ' ',
'decimal_separator' => '.',
'scale' => 0,
'prefix_suffix' => TRUE,
),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_DEFAULT,
),
),
'number_decimal' => array(
'label' => t('default'),
'field types' => array('number_decimal', 'number_float'),
'settings' => array(
'thousand_separator' => ' ',
'decimal_separator' => '.',
'scale' => 2,
'prefix_suffix' => TRUE,
),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_DEFAULT,
),
),
'number_unformatted' => array(
'label' => t('unformatted'),
'field types' => array('number_integer', 'number_decimal', 'number_float'),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_DEFAULT,
),
),
);
}
/**
* Theme function for 'unformatted' number field formatter.
*/
function theme_field_formatter_number_unformatted($element) {
return $element['#item']['value'];
}
/**
* Proxy theme function for number field formatters.
*/
function theme_field_formatter_number($element) {
$field = field_info_field($element['#field_name']);
$instance = field_info_instance($element['#field_name'], $element['#bundle']);
$value = $element['#item']['value'];
$settings = $element['#settings'];
$formatter_type = $element['#formatter'];
if (empty($value) && $value !== '0') {
return '';
}
$output = number_format($value, $settings['scale'], $settings['decimal_separator'], $settings['thousand_separator']);
if ($settings['prefix_suffix']) {
$prefixes = isset($instance['settings']['prefix']) ? explode('|', check_plain($instance['settings']['prefix'])) : array(0 => '');
$suffixes = isset($instance['settings']['suffix']) ? explode('|', check_plain($instance['settings']['suffix'])) : array(0 => '');
$prefix = (count($prefixes) > 1) ? format_plural($value, $prefixes[0], $prefixes[1]) : $prefixes[0];
$suffix = (count($suffixes) > 1) ? format_plural($value, $suffixes[0], $suffixes[1]) : $suffixes[0];
$output = $prefix . $output . $suffix;
}
return $output;
}
/**
* Implementation of hook_field_widget_info().
*
* Here we indicate that the Field module will handle
* multiple values for these widgets.
*
* Callbacks can be omitted if default handing is used.
* They're included here just so this module can be used
* as an example for custom modules that might do things
* differently.
*/
function number_field_widget_info() {
return array(
'number' => array(
'label' => t('Text field'),
'field types' => array('number_integer', 'number_decimal', 'number_float'),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_DEFAULT,
'default value' => FIELD_BEHAVIOR_DEFAULT,
),
),
);
}
/**
* Implementation of FAPI hook_elements().
*
* Any FAPI callbacks needed for individual widgets can be declared here,
* and the element will be passed to those callbacks for processing.
*
* Drupal will automatically theme the element using a theme with
* the same name as the hook_elements key.
*
* Includes a regex to check for valid values as an additional parameter
* the validator can use. The regex can be overridden if necessary.
*/
function number_elements() {
return array(
'number' => array(
'#input' => TRUE,
'#columns' => array('value'), '#delta' => 0,
'#process' => array('number_process'),
),
);
}
/**
* Implementation of hook_field_widget().
*
* Attach a single form element to the form. It will be built out and
* validated in the callback(s) listed in hook_elements. We build it
* out in the callbacks rather than here in hook_widget so it can be
* plugged into any module that can provide it with valid
* $field information.
*
* Field module will set the weight, field name and delta values
* for each form element.
*
* If there are multiple values for this field, the Field module will
* call this function as many times as needed.
*
* @param $form
* the entire form array, $form['#node'] holds node information
* @param $form_state
* the form_state, $form_state['values'] holds the form values.
* @param $field
* The field structure.
* @param $instance
* the field instance array
* @param $delta
* the order of this item in the array of subelements (0, 1, 2, etc)
*
* @return
* the form item for a single element for this field
*/
function number_field_widget(&$form, &$form_state, $field, $instance, $items, $delta = 0) {
$element = array(
'#type' => $instance['widget']['type'],
'#default_value' => isset($items[$delta]) ? $items[$delta] : NULL,
);
return $element;
}
/**
* Process an individual element.
*
* Build the form element. When creating a form using FAPI #process,
* note that $element['#value'] is already set.
*
* The $field and $instance arrays are in $form['#fields'][$element['#field_name']].
*/
function number_process($element, $edit, $form_state, $form) {
$field_name = $element['#field_name'];
$field = field_info_field($element['#field_name']);
$instance = field_info_instance($element['#field_name'], $element['#bundle']);
$field_key = $element['#columns'][0];
$value = isset($element['#value'][$field_key]) ? $element['#value'][$field_key] : '';
if ($field['type'] == 'number_decimal') {
$value = str_replace('.', $field['settings']['decimal'], $value);
}
$element[$field_key] = array(
'#type' => 'textfield',
'#default_value' => $value,
// Need to allow a slightly larger size that the field length to allow
// for some configurations where all characters won't fit in input field.
'#size' => $field['type'] == 'number_decimal' ? $field['settings']['precision'] + 2 : 12,
'#maxlength' => $field['type'] == 'number_decimal' ? $field['settings']['precision'] : 10,
'#attributes' => array('class' => 'number'),
// The following values were set by the Field module and need
// to be passed down to the nested element.
'#title' => $element['#title'],
'#description' => $element['#description'],
'#required' => $element['#required'],
'#field_name' => $element['#field_name'],
'#bundle' => $element['#bundle'],
'#delta' => $element['#delta'],
'#columns' => $element['#columns'],
);
if (!empty($instance['settings']['prefix'])) {
$prefixes = explode('|', $instance['settings']['prefix']);
$element[$field_key]['#field_prefix'] = array_pop($prefixes);
}
if (!empty($instance['settings']['suffix'])) {
$suffixes = explode('|', $instance['settings']['suffix']);
$element[$field_key]['#field_suffix'] = array_pop($suffixes);
}
// Make sure we don't wipe out element validation added elsewhere.
if (empty($element['#element_validate'])) {
$element['#element_validate'] = array();
}
switch ($field['type']) {
case 'number_float':
$element['#element_validate'][] = 'number_float_validate';
break;
case 'number_integer':
$element['#element_validate'][] = 'number_integer_validate';
break;
case 'number_decimal':
$element['#element_validate'][] = 'number_decimal_validate';
break;
}
// Used so that hook_field('validate') knows where to flag an error.
$element['_error_element'] = array(
'#type' => 'value',
'#value' => implode('][', array_merge($element['#parents'], array($field_key))),
);
return $element;
}
/**
* FAPI validation of an individual float element.
*/
function number_float_validate($element, &$form_state) {
$field = field_info_field($element['#field_name']);
$instance = field_info_instance($element['#field_name'], $element['#bundle']);
$field_key = $element['#columns'][0];
$value = $element['#value'][$field_key];
if (($element[$field_key]['#required'] || !empty($value))) {
$start = $value;
$value = preg_replace('@[^-0-9\.]@', '', $value);
if ($start != $value) {
$error_field = implode('][', $element['#parents']) . '][' . $field_key;
form_set_error($error_field, t('Only numbers and decimals are allowed in %field.', array('%field' => t($instance['label']))));
}
else {
form_set_value($element[$field_key], $value, $form_state);
}
}
}
/**
* FAPI validation of an individual integer element.
*/
function number_integer_validate($element, &$form_state) {
$field = field_info_field($element['#field_name']);
$instance = field_info_instance($element['#field_name'], $element['#bundle']);
$field_key = $element['#columns'][0];
$value = $element['#value'][$field_key];
if (($element[$field_key]['#required'] || !empty($value))) {
$start = $value;
$value = preg_replace('@[^-0-9]@', '', $value);
if ($start != $value) {
$error_field = implode('][', $element['#parents']) . '][' . $field_key;
form_set_error($error_field, t('Only numbers are allowed in %field.', array('%field' => t($instance['label']))));
}
else {
form_set_value($element[$field_key], $value, $form_state);
}
}
}
/**
* FAPI validation of an individual decimal element.
*/
function number_decimal_validate($element, &$form_state) {
$field = field_info_field($element['#field_name']);
$instance = field_info_instance($element['#field_name'], $element['#bundle']);
$field_key = $element['#columns'][0];
$value = $element['#value'][$field_key];
if (($element[$field_key]['#required'] || !empty($value))) {
$start = $value;
$value = preg_replace('@[^-0-9\\' . $field['settings']['decimal'] . ']@', '', $value);
if ($start != $value) {
$error_field = implode('][', $element['#parents']) . '][' . $field_key;
form_set_error($error_field, t('Only numbers and the decimal character (%decimal) are allowed in %field.', array('%decimal' => $field['settings']['decimal'], '%field' => t($instance['label']))));
}
else {
$value = str_replace($field['settings']['decimal'], ' .', $value);
$value = round($value, $field['settings']['scale']);
form_set_value($element[$field_key], $value, $form_state);
}
}
}
/**
* FAPI theme for an individual number element.
*
* The textfield is already rendered by the textfield
* theme and the HTML output lives in $element['#children'].
* Override this theme to make custom changes to the output.
*
* $element['#field_name'] contains the field name
* $element['#delta] is the position of this element in the group
*/
function theme_number($element) {
return $element['#children'];
}

View File

@ -1,422 +1,422 @@
<?php
// $Id$
/**
* @file
* Defines selection, check box and radio button widgets for text and numeric fields.
*/
/**
* Implementation of hook_theme().
*/
function options_theme() {
return array(
'options_select' => array(
'arguments' => array('element' => NULL),
),
'options_buttons' => array(
'arguments' => array('element' => NULL),
),
'options_onoff' => array(
'arguments' => array('element' => NULL),
),
'options_none' => array(
'arguments' => array('widget_type' => NULL, 'field_name' => NULL, 'node_type' => NULL),
),
);
}
/**
* Implementation of hook_field_widget_info().
*
* We need custom handling of multiple values because we need
* to combine them into a options list rather than display
* cardinality elements. We will use the field module's default
* handling for default values.
*
* Callbacks can be omitted if default handing is used.
* They're included here just so this module can be used
* as an example for custom modules that might do things
* differently.
*/
function options_field_widget_info() {
return array(
'options_select' => array(
'label' => t('Select list'),
'field types' => array('list', 'list_boolean', 'list_text', 'list_number'),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_CUSTOM,
'default value' => FIELD_BEHAVIOR_DEFAULT,
),
),
'options_buttons' => array(
'label' => t('Check boxes/radio buttons'),
'field types' => array('list', 'list_boolean', 'list_text', 'list_number'),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_CUSTOM,
'default value' => FIELD_BEHAVIOR_DEFAULT,
),
),
'options_onoff' => array(
'label' => t('Single on/off checkbox'),
'field types' => array('list_boolean'),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_CUSTOM,
'default value' => FIELD_BEHAVIOR_DEFAULT,
),
),
);
}
/**
* Implementation of FAPI hook_elements().
*
* Any FAPI callbacks needed for individual widgets can be declared here,
* and the element will be passed to those callbacks for processing.
*
* Drupal will automatically theme the element using a theme with
* the same name as the hook_elements key.
*/
function options_elements() {
return array(
'options_select' => array(
'#input' => TRUE,
'#columns' => array('value'), '#delta' => 0,
'#process' => array('options_select_process'),
),
'options_buttons' => array(
'#input' => TRUE,
'#columns' => array('value'), '#delta' => 0,
'#process' => array('options_buttons_process'),
),
'options_onoff' => array(
'#input' => TRUE,
'#columns' => array('value'), '#delta' => 0,
'#process' => array('options_onoff_process'),
),
);
}
/**
* Implementation of hook_field_widget().
*/
function options_field_widget(&$form, &$form_state, $field, $instance, $items, $delta = NULL) {
$element = array(
'#type' => $instance['widget']['type'],
'#default_value' => !empty($items) ? $items : array(),
);
return $element;
}
/**
* Process an individual element.
*
* Build the form element. When creating a form using FAPI #process,
* note that $element['#value'] is already set.
*
* The $field and $instance arrays are in $form['#fields'][$element['#field_name']].
*/
function options_buttons_process($element, $edit, &$form_state, $form) {
$field = $form['#fields'][$element['#field_name']]['field'];
$instance = $form['#fields'][$element['#field_name']]['instance'];
$field_key = $element['#columns'][0];
// See if this element is in the database format or the transformed format,
// and transform it if necessary.
if (is_array($element['#value']) && !array_key_exists($field_key, $element['#value'])) {
$element['#value'] = options_data2form($element, $element['#default_value'], $field);
}
$options = options_options($field, $instance);
$multiple = isset($element['#multiple']) ? $element['#multiple'] : $field['cardinality'] > 1 || $field['cardinality'] == FIELD_CARDINALITY_UNLIMITED;
$value = array();
foreach ($element['#value'][$field_key] as $key) {
// Multiple (checkboxes) need the default value in the form of an array.
if ($multiple) {
$value[$key] = 1;
}
// Non-multiple (radios) need single default value.
else {
$value = $key;
break;
}
}
$element[$field_key] = array(
'#type' => $multiple ? 'checkboxes' : 'radios',
'#title' => $element['#title'],
'#description' => $element['#description'],
'#required' => isset($element['#required']) ? $element['#required'] : $instance['required'],
'#multiple' => $multiple,
'#options' => $options,
'#default_value' => $value,
);
// Set #element_validate in a way that it will not wipe out other
// validation functions already set by other modules.
if (empty($element['#element_validate'])) {
$element['#element_validate'] = array();
}
array_unshift($element['#element_validate'], 'options_validate');
// Make sure field info will be available to the validator which
// does not get the values in $form.
$form_state['#fields'][$element['#field_name']] = $form['#fields'][$element['#field_name']];
return $element;
}
/**
* Process an individual element.
*
* Build the form element. When creating a form using FAPI #process,
* note that $element['#value'] is already set.
*
* The $field and $instance arrays are in $form['#fields'][$element['#field_name']].
*/
function options_select_process($element, $edit, &$form_state, $form) {
$field = $form['#fields'][$element['#field_name']]['field'];
$instance = $form['#fields'][$element['#field_name']]['instance'];
$field_key = $element['#columns'][0];
// See if this element is in the database format or the transformed format,
// and transform it if necessary.
if (is_array($element['#value']) && !array_key_exists($field_key, $element['#value'])) {
$element['#value'] = options_data2form($element, $element['#default_value'], $field);
}
$options = options_options($field, $instance);
$element[$field_key] = array(
'#type' => 'select',
'#title' => $element['#title'],
'#description' => $element['#description'],
'#required' => isset($element['#required']) ? $element['#required'] : $instance['required'],
'#multiple' => isset($element['#multiple']) ? $element['#multiple'] : $field['cardinality'] > 1 || $field['cardinality'] == FIELD_CARDINALITY_UNLIMITED,
'#options' => $options,
'#default_value' => isset($element['#value'][$field_key]) ? $element['#value'][$field_key] : NULL,
);
// Set #element_validate in a way that it will not wipe out other
// validation functions already set by other modules.
if (empty($element['#element_validate'])) {
$element['#element_validate'] = array();
}
array_unshift($element['#element_validate'], 'options_validate');
// Make sure field info will be available to the validator which
// does not get the values in $form.
$form_state['#fields'][$element['#field_name']] = $form['#fields'][$element['#field_name']];
return $element;
}
/**
* Process an individual element.
*
* Build the form element. When creating a form using FAPI #process,
* note that $element['#value'] is already set.
*/
function options_onoff_process($element, $edit, &$form_state, $form) {
$field = $form['#fields'][$element['#field_name']]['field'];
$instance = $form['#fields'][$element['#field_name']]['instance'];
$field_key = $element['#columns'][0];
// See if this element is in the database format or the transformed format,
// and transform it if necessary.
if (is_array($element['#value']) && !array_key_exists($field_key, $element['#value'])) {
$element['#value'] = options_data2form($element, $element['#default_value'], $field);
}
$options = options_options($field, $instance);
$keys = array_keys($options);
$on_value = (!empty($keys) && isset($keys[1])) ? $keys[1] : NULL;
$element[$field_key] = array(
'#type' => 'checkbox',
'#title' => isset($options[$on_value]) ? $options[$on_value] : '',
'#description' => $element['#description'],
'#default_value' => isset($element['#value'][$field_key][0]) ? $element['#value'][$field_key][0] == $on_value : FALSE,
'#return_value' => $on_value,
);
// Set #element_validate in a way that it will not wipe out other
// validation functions already set by other modules.
if (empty($element['#element_validate'])) {
$element['#element_validate'] = array();
}
array_unshift($element['#element_validate'], 'options_validate');
// Make sure field info will be available to the validator which
// does not get the values in $form.
$form_state['#fields'][$element['#field_name']] = $form['#fields'][$element['#field_name']];
return $element;
}
/**
* FAPI function to validate options element.
*/
function options_validate($element, &$form_state) {
// Transpose selections from field => delta to delta => field,
// turning cardinality selected options into cardinality parent elements.
// Immediate parent is the delta, need to get back to parent's parent
// to create cardinality elements.
$field = $form_state['#fields'][$element['#field_name']]['field'];
$items = options_form2data($element, $field);
form_set_value($element, $items, $form_state);
// Check we don't exceed the allowed number of values.
if ($field['cardinality'] >= 2) {
// Filter out 'none' value (if present, will always be in key 0)
$field_key = $element['#columns'][0];
if (isset($items[0][$field_key]) && $items[0][$field_key] === '') {
unset($items[0]);
}
if (count($items) > $field['cardinality']) {
$field_key = $element['#columns'][0];
form_error($element[$field_key], t('%name: this field cannot hold more that @count values.', array('%name' => t($field['widget']['label']), '@count' => $field['cardinality'])));
}
}
}
/**
* Helper function to transpose the values as stored in the database
* to the format the widget needs. Can be called anywhere this
* transformation is needed.
*/
function options_data2form($element, $items, $field) {
$field_key = $element['#columns'][0];
$field = field_info_field($element['#field_name']);
$instance = field_info_instance($element['#field_name'], $element['#bundle']);
$options = options_options($field, $instance);
$items_transposed = options_transpose_array_rows_cols($items);
$values = (isset($items_transposed[$field_key]) && is_array($items_transposed[$field_key])) ? $items_transposed[$field_key] : array();
$keys = array();
foreach ($values as $value) {
$key = array_search($value, array_keys($options));
if (isset($key)) {
$keys[] = $value;
}
}
if ($field['cardinality'] || $element['#type'] == 'options_onoff') {
return array($field_key => $keys);
}
else {
return !empty($keys) ? array($field_key => $value) : array();
}
}
/**
* Helper function to transpose the values returned by submitting the widget
* to the format to be stored in the field. Can be called anywhere this
* transformation is needed.
*/
function options_form2data($element, $field) {
$field_key = $element['#columns'][0];
$field = field_info_field($element['#field_name']);
$instance = field_info_instance($element['#field_name'], $element['#bundle']);
$items = (array) $element[$field_key]['#value'];
$options = options_options($field, $instance);
$values = array_values($items);
if ($element['#type'] == 'options_onoff' && ($values[0] === 0)) {
$keys = array_keys($options);
$values = array(array_key_exists(0, $keys) ? $keys[0] : NULL);
}
if (empty($values)) {
$values[] = NULL;
}
$result = options_transpose_array_rows_cols(array($field_key => $values));
return $result;
}
/**
* Manipulate a 2D array to reverse rows and columns.
*
* The default data storage for fields is delta first, column names second.
* This is sometimes inconvenient for field modules, so this function can be
* used to present the data in an alternate format.
*
* @param $array
* The array to be transposed. It must be at least two-dimensional, and
* the subarrays must all have the same keys or behavior is undefined.
* @return
* The transposed array.
*/
function options_transpose_array_rows_cols($array) {
$result = array();
if (is_array($array)) {
foreach ($array as $key1 => $value1) {
if (is_array($value1)) {
foreach ($value1 as $key2 => $value2) {
if (!isset($result[$key2])) {
$result[$key2] = array();
}
$result[$key2][$key1] = $value2;
}
}
}
}
return $result;
}
/**
* Helper function for finding the allowed values list for a field.
*
* See if there is a module hook for the option values.
* Otherwise, try list_allowed_values() for an options list.
*/
function options_options($field, $instance) {
$function = $field['module'] . '_allowed_values';
$options = function_exists($function) ? $function($field) : (array) list_allowed_values($field);
// Add an empty choice for :
// - non required radios
// - non required selects
if (!$instance['required']) {
if ((in_array($instance['widget']['type'], array('options_buttons', 'node_reference_buttons', 'user_reference_buttons')) && !$field['cardinality'])
|| (in_array($instance['widget']['type'], array('options_select', 'node_reference_select', 'user_reference_select')))) {
$options = array('' => theme('options_none', $instance)) + $options;
}
}
return $options;
}
/**
* Theme the label for the empty value for options that are not required.
* The default theme will display N/A for a radio list and blank for a select.
*/
function theme_options_none($instance) {
switch ($instance['widget']['type']) {
case 'options_buttons':
case 'node_reference_buttons':
case 'user_reference_buttons':
return t('N/A');
case 'options_select':
case 'node_reference_select':
case 'user_reference_select':
return t('- None -');
default :
return '';
}
}
/**
* FAPI themes for options.
*
* The select, checkboxes or radios are already rendered by the
* select, checkboxes, or radios themes and the HTML output
* lives in $element['#children']. Override this theme to
* make custom changes to the output.
*
* $element['#field_name'] contains the field name
* $element['#delta] is the position of this element in the group
*/
function theme_options_select($element) {
return $element['#children'];
}
function theme_options_onoff($element) {
return $element['#children'];
}
function theme_options_buttons($element) {
return $element['#children'];
<?php
// $Id$
/**
* @file
* Defines selection, check box and radio button widgets for text and numeric fields.
*/
/**
* Implementation of hook_theme().
*/
function options_theme() {
return array(
'options_select' => array(
'arguments' => array('element' => NULL),
),
'options_buttons' => array(
'arguments' => array('element' => NULL),
),
'options_onoff' => array(
'arguments' => array('element' => NULL),
),
'options_none' => array(
'arguments' => array('widget_type' => NULL, 'field_name' => NULL, 'node_type' => NULL),
),
);
}
/**
* Implementation of hook_field_widget_info().
*
* We need custom handling of multiple values because we need
* to combine them into a options list rather than display
* cardinality elements. We will use the field module's default
* handling for default values.
*
* Callbacks can be omitted if default handing is used.
* They're included here just so this module can be used
* as an example for custom modules that might do things
* differently.
*/
function options_field_widget_info() {
return array(
'options_select' => array(
'label' => t('Select list'),
'field types' => array('list', 'list_boolean', 'list_text', 'list_number'),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_CUSTOM,
'default value' => FIELD_BEHAVIOR_DEFAULT,
),
),
'options_buttons' => array(
'label' => t('Check boxes/radio buttons'),
'field types' => array('list', 'list_boolean', 'list_text', 'list_number'),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_CUSTOM,
'default value' => FIELD_BEHAVIOR_DEFAULT,
),
),
'options_onoff' => array(
'label' => t('Single on/off checkbox'),
'field types' => array('list_boolean'),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_CUSTOM,
'default value' => FIELD_BEHAVIOR_DEFAULT,
),
),
);
}
/**
* Implementation of FAPI hook_elements().
*
* Any FAPI callbacks needed for individual widgets can be declared here,
* and the element will be passed to those callbacks for processing.
*
* Drupal will automatically theme the element using a theme with
* the same name as the hook_elements key.
*/
function options_elements() {
return array(
'options_select' => array(
'#input' => TRUE,
'#columns' => array('value'), '#delta' => 0,
'#process' => array('options_select_process'),
),
'options_buttons' => array(
'#input' => TRUE,
'#columns' => array('value'), '#delta' => 0,
'#process' => array('options_buttons_process'),
),
'options_onoff' => array(
'#input' => TRUE,
'#columns' => array('value'), '#delta' => 0,
'#process' => array('options_onoff_process'),
),
);
}
/**
* Implementation of hook_field_widget().
*/
function options_field_widget(&$form, &$form_state, $field, $instance, $items, $delta = NULL) {
$element = array(
'#type' => $instance['widget']['type'],
'#default_value' => !empty($items) ? $items : array(),
);
return $element;
}
/**
* Process an individual element.
*
* Build the form element. When creating a form using FAPI #process,
* note that $element['#value'] is already set.
*
* The $field and $instance arrays are in $form['#fields'][$element['#field_name']].
*/
function options_buttons_process($element, $edit, &$form_state, $form) {
$field = $form['#fields'][$element['#field_name']]['field'];
$instance = $form['#fields'][$element['#field_name']]['instance'];
$field_key = $element['#columns'][0];
// See if this element is in the database format or the transformed format,
// and transform it if necessary.
if (is_array($element['#value']) && !array_key_exists($field_key, $element['#value'])) {
$element['#value'] = options_data2form($element, $element['#default_value'], $field);
}
$options = options_options($field, $instance);
$multiple = isset($element['#multiple']) ? $element['#multiple'] : $field['cardinality'] > 1 || $field['cardinality'] == FIELD_CARDINALITY_UNLIMITED;
$value = array();
foreach ($element['#value'][$field_key] as $key) {
// Multiple (checkboxes) need the default value in the form of an array.
if ($multiple) {
$value[$key] = 1;
}
// Non-multiple (radios) need single default value.
else {
$value = $key;
break;
}
}
$element[$field_key] = array(
'#type' => $multiple ? 'checkboxes' : 'radios',
'#title' => $element['#title'],
'#description' => $element['#description'],
'#required' => isset($element['#required']) ? $element['#required'] : $instance['required'],
'#multiple' => $multiple,
'#options' => $options,
'#default_value' => $value,
);
// Set #element_validate in a way that it will not wipe out other
// validation functions already set by other modules.
if (empty($element['#element_validate'])) {
$element['#element_validate'] = array();
}
array_unshift($element['#element_validate'], 'options_validate');
// Make sure field info will be available to the validator which
// does not get the values in $form.
$form_state['#fields'][$element['#field_name']] = $form['#fields'][$element['#field_name']];
return $element;
}
/**
* Process an individual element.
*
* Build the form element. When creating a form using FAPI #process,
* note that $element['#value'] is already set.
*
* The $field and $instance arrays are in $form['#fields'][$element['#field_name']].
*/
function options_select_process($element, $edit, &$form_state, $form) {
$field = $form['#fields'][$element['#field_name']]['field'];
$instance = $form['#fields'][$element['#field_name']]['instance'];
$field_key = $element['#columns'][0];
// See if this element is in the database format or the transformed format,
// and transform it if necessary.
if (is_array($element['#value']) && !array_key_exists($field_key, $element['#value'])) {
$element['#value'] = options_data2form($element, $element['#default_value'], $field);
}
$options = options_options($field, $instance);
$element[$field_key] = array(
'#type' => 'select',
'#title' => $element['#title'],
'#description' => $element['#description'],
'#required' => isset($element['#required']) ? $element['#required'] : $instance['required'],
'#multiple' => isset($element['#multiple']) ? $element['#multiple'] : $field['cardinality'] > 1 || $field['cardinality'] == FIELD_CARDINALITY_UNLIMITED,
'#options' => $options,
'#default_value' => isset($element['#value'][$field_key]) ? $element['#value'][$field_key] : NULL,
);
// Set #element_validate in a way that it will not wipe out other
// validation functions already set by other modules.
if (empty($element['#element_validate'])) {
$element['#element_validate'] = array();
}
array_unshift($element['#element_validate'], 'options_validate');
// Make sure field info will be available to the validator which
// does not get the values in $form.
$form_state['#fields'][$element['#field_name']] = $form['#fields'][$element['#field_name']];
return $element;
}
/**
* Process an individual element.
*
* Build the form element. When creating a form using FAPI #process,
* note that $element['#value'] is already set.
*/
function options_onoff_process($element, $edit, &$form_state, $form) {
$field = $form['#fields'][$element['#field_name']]['field'];
$instance = $form['#fields'][$element['#field_name']]['instance'];
$field_key = $element['#columns'][0];
// See if this element is in the database format or the transformed format,
// and transform it if necessary.
if (is_array($element['#value']) && !array_key_exists($field_key, $element['#value'])) {
$element['#value'] = options_data2form($element, $element['#default_value'], $field);
}
$options = options_options($field, $instance);
$keys = array_keys($options);
$on_value = (!empty($keys) && isset($keys[1])) ? $keys[1] : NULL;
$element[$field_key] = array(
'#type' => 'checkbox',
'#title' => isset($options[$on_value]) ? $options[$on_value] : '',
'#description' => $element['#description'],
'#default_value' => isset($element['#value'][$field_key][0]) ? $element['#value'][$field_key][0] == $on_value : FALSE,
'#return_value' => $on_value,
);
// Set #element_validate in a way that it will not wipe out other
// validation functions already set by other modules.
if (empty($element['#element_validate'])) {
$element['#element_validate'] = array();
}
array_unshift($element['#element_validate'], 'options_validate');
// Make sure field info will be available to the validator which
// does not get the values in $form.
$form_state['#fields'][$element['#field_name']] = $form['#fields'][$element['#field_name']];
return $element;
}
/**
* FAPI function to validate options element.
*/
function options_validate($element, &$form_state) {
// Transpose selections from field => delta to delta => field,
// turning cardinality selected options into cardinality parent elements.
// Immediate parent is the delta, need to get back to parent's parent
// to create cardinality elements.
$field = $form_state['#fields'][$element['#field_name']]['field'];
$items = options_form2data($element, $field);
form_set_value($element, $items, $form_state);
// Check we don't exceed the allowed number of values.
if ($field['cardinality'] >= 2) {
// Filter out 'none' value (if present, will always be in key 0)
$field_key = $element['#columns'][0];
if (isset($items[0][$field_key]) && $items[0][$field_key] === '') {
unset($items[0]);
}
if (count($items) > $field['cardinality']) {
$field_key = $element['#columns'][0];
form_error($element[$field_key], t('%name: this field cannot hold more that @count values.', array('%name' => t($field['widget']['label']), '@count' => $field['cardinality'])));
}
}
}
/**
* Helper function to transpose the values as stored in the database
* to the format the widget needs. Can be called anywhere this
* transformation is needed.
*/
function options_data2form($element, $items, $field) {
$field_key = $element['#columns'][0];
$field = field_info_field($element['#field_name']);
$instance = field_info_instance($element['#field_name'], $element['#bundle']);
$options = options_options($field, $instance);
$items_transposed = options_transpose_array_rows_cols($items);
$values = (isset($items_transposed[$field_key]) && is_array($items_transposed[$field_key])) ? $items_transposed[$field_key] : array();
$keys = array();
foreach ($values as $value) {
$key = array_search($value, array_keys($options));
if (isset($key)) {
$keys[] = $value;
}
}
if ($field['cardinality'] || $element['#type'] == 'options_onoff') {
return array($field_key => $keys);
}
else {
return !empty($keys) ? array($field_key => $value) : array();
}
}
/**
* Helper function to transpose the values returned by submitting the widget
* to the format to be stored in the field. Can be called anywhere this
* transformation is needed.
*/
function options_form2data($element, $field) {
$field_key = $element['#columns'][0];
$field = field_info_field($element['#field_name']);
$instance = field_info_instance($element['#field_name'], $element['#bundle']);
$items = (array) $element[$field_key]['#value'];
$options = options_options($field, $instance);
$values = array_values($items);
if ($element['#type'] == 'options_onoff' && ($values[0] === 0)) {
$keys = array_keys($options);
$values = array(array_key_exists(0, $keys) ? $keys[0] : NULL);
}
if (empty($values)) {
$values[] = NULL;
}
$result = options_transpose_array_rows_cols(array($field_key => $values));
return $result;
}
/**
* Manipulate a 2D array to reverse rows and columns.
*
* The default data storage for fields is delta first, column names second.
* This is sometimes inconvenient for field modules, so this function can be
* used to present the data in an alternate format.
*
* @param $array
* The array to be transposed. It must be at least two-dimensional, and
* the subarrays must all have the same keys or behavior is undefined.
* @return
* The transposed array.
*/
function options_transpose_array_rows_cols($array) {
$result = array();
if (is_array($array)) {
foreach ($array as $key1 => $value1) {
if (is_array($value1)) {
foreach ($value1 as $key2 => $value2) {
if (!isset($result[$key2])) {
$result[$key2] = array();
}
$result[$key2][$key1] = $value2;
}
}
}
}
return $result;
}
/**
* Helper function for finding the allowed values list for a field.
*
* See if there is a module hook for the option values.
* Otherwise, try list_allowed_values() for an options list.
*/
function options_options($field, $instance) {
$function = $field['module'] . '_allowed_values';
$options = function_exists($function) ? $function($field) : (array) list_allowed_values($field);
// Add an empty choice for :
// - non required radios
// - non required selects
if (!$instance['required']) {
if ((in_array($instance['widget']['type'], array('options_buttons', 'node_reference_buttons', 'user_reference_buttons')) && !$field['cardinality'])
|| (in_array($instance['widget']['type'], array('options_select', 'node_reference_select', 'user_reference_select')))) {
$options = array('' => theme('options_none', $instance)) + $options;
}
}
return $options;
}
/**
* Theme the label for the empty value for options that are not required.
* The default theme will display N/A for a radio list and blank for a select.
*/
function theme_options_none($instance) {
switch ($instance['widget']['type']) {
case 'options_buttons':
case 'node_reference_buttons':
case 'user_reference_buttons':
return t('N/A');
case 'options_select':
case 'node_reference_select':
case 'user_reference_select':
return t('- None -');
default :
return '';
}
}
/**
* FAPI themes for options.
*
* The select, checkboxes or radios are already rendered by the
* select, checkboxes, or radios themes and the HTML output
* lives in $element['#children']. Override this theme to
* make custom changes to the output.
*
* $element['#field_name'] contains the field name
* $element['#delta] is the position of this element in the group
*/
function theme_options_select($element) {
return $element['#children'];
}
function theme_options_onoff($element) {
return $element['#children'];
}
function theme_options_buttons($element) {
return $element['#children'];
}

View File

@ -3,5 +3,4 @@ name = Text
description = Defines simple text field types.
package = Core - fields
core = 7.x
files[]=text.module

View File

@ -1,400 +1,400 @@
<?php
// $Id$
/**
* @file
* Defines simple text field types.
*/
/**
* Implementation of hook_theme().
*/
function text_theme() {
return array(
'text_textarea' => array(
'arguments' => array('element' => NULL),
),
'text_textfield' => array(
'arguments' => array('element' => NULL),
),
'field_formatter_text_default' => array(
'arguments' => array('element' => NULL),
),
'field_formatter_text_plain' => array(
'arguments' => array('element' => NULL),
),
'field_formatter_text_trimmed' => array(
'arguments' => array('element' => NULL),
),
);
}
/**
* Implementation of hook_field_info().
*/
function text_field_info() {
return array(
'text' => array(
'label' => t('Text'),
'description' => t('This field stores varchar text in the database.'),
'settings' => array('max_length' => 255),
'instance_settings' => array('text_processing' => 0),
'default_widget' => 'text_textfield',
'default_formatter' => 'text_default',
),
'text_long' => array(
'label' => t('Long text'),
'description' => t('This field stores long text in the database.'),
'instance_settings' => array('text_processing' => 0),
'default_widget' => 'text_textarea',
'default_formatter' => 'text_default',
),
);
}
/**
* Implementation of hook_field_schema().
*/
function text_field_columns($field) {
if ($field['type'] == 'text_long') {
$columns = array(
'value' => array(
'type' => 'text',
'size' => 'big',
'not null' => FALSE,
),
);
}
else {
$columns = array(
'value' => array(
'type' => 'varchar',
'length' => $field['settings']['max_length'],
'not null' => FALSE,
),
);
}
$columns += array(
'format' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => FALSE,
),
);
return $columns;
}
/**
* Implementation of hook_field_validate().
*/
function text_field_validate($obj_type, $object, $field, $instance, $items, $form) {
if (is_array($items)) {
foreach ($items as $delta => $item) {
$error_element = isset($item['_error_element']) ? $item['_error_element'] : '';
if (is_array($item) && isset($item['_error_element'])) unset($item['_error_element']);
if (!empty($item['value'])) {
if (!empty($field['settings']['max_length']) && drupal_strlen($item['value']) > $field['settings']['max_length']) {
form_set_error($error_element, t('%name: the value may not be longer than %max characters.', array('%name' => $instance['label'], '%max' => $field['settings']['max_length'])));
}
}
}
}
}
function text_field_sanitize($obj_type, $object, $field, $instance, &$items) {
global $language;
foreach ($items as $delta => $item) {
// TODO D7 : this code is really node-related.
if (!empty($instance['settings']['text_processing'])) {
$check = is_null($object) || (isset($object->build_mode) && $object->build_mode == NODE_BUILD_PREVIEW);
$text = isset($item['value']) ? check_markup($item['value'], $item['format'], isset($object->language) ? $object->language : $language, $check) : '';
}
else {
$text = check_plain($item['value']);
}
$items[$delta]['safe'] = $text;
}
}
/**
* Implementation of hook_field_is_empty().
*/
function text_field_is_empty($item, $field) {
if (empty($item['value']) && (string)$item['value'] !== '0') {
return TRUE;
}
return FALSE;
}
/**
* Implementation of hook_field_formatter_info().
*/
function text_field_formatter_info() {
return array(
'text_default' => array(
'label' => t('Default'),
'field types' => array('text', 'text_long'),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_DEFAULT,
),
),
'text_plain' => array(
'label' => t('Plain text'),
'field types' => array('text', 'text_long'),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_DEFAULT,
),
),
'text_trimmed' => array(
'label' => t('Trimmed'),
'field types' => array('text', 'text_long'),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_DEFAULT,
),
),
);
}
/**
* Theme function for 'default' text field formatter.
*/
function theme_field_formatter_text_default($element) {
return $element['#item']['safe'];
}
/**
* Theme function for 'plain' text field formatter.
*/
function theme_field_formatter_text_plain($element) {
return strip_tags($element['#item']['safe']);
}
/**
* Theme function for 'trimmed' text field formatter.
*/
function theme_field_formatter_text_trimmed($element) {
$field = field_info_field($element['#field_name']);
$instance = field_info_instance($element['#field_name'], $element['#bundle']);
return $instance['settings']['text_processing'] ? $element['#item']['format'] : NULL;
}
/**
* Implementation of hook_field_widget_info().
*
* Here we indicate that the field module will handle
* the default value and multiple values for these widgets.
*
* Callbacks can be omitted if default handing is used.
* They're included here just so this module can be used
* as an example for custom modules that might do things
* differently.
*/
function text_field_widget_info() {
return array(
'text_textfield' => array(
'label' => t('Text field'),
'field types' => array('text'),
'settings' => array('size' => 60),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_DEFAULT,
'default value' => FIELD_BEHAVIOR_DEFAULT,
),
),
'text_textarea' => array(
'label' => t('Text area (multiple rows)'),
'field types' => array('text_long'),
'settings' => array('rows' => 5),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_DEFAULT,
'default value' => FIELD_BEHAVIOR_DEFAULT,
),
),
);
}
/**
* Implementation of FAPI hook_elements().
*
* Any FAPI callbacks needed for individual widgets can be declared here,
* and the element will be passed to those callbacks for processing.
*
* Drupal will automatically theme the element using a theme with
* the same name as the hook_elements key.
*
* Autocomplete_path is not used by text_field_widget but other
* widgets can use it (see nodereference and userreference).
*/
function text_elements() {
return array(
'text_textfield' => array(
'#input' => TRUE,
'#columns' => array('value'), '#delta' => 0,
'#process' => array('text_textfield_process'),
'#autocomplete_path' => FALSE,
),
'text_textarea' => array(
'#input' => TRUE,
'#columns' => array('value', 'format'), '#delta' => 0,
'#process' => array('text_textarea_process'),
'#filter_value' => FILTER_FORMAT_DEFAULT,
),
);
}
/**
* Implementation of hook_field_widget().
*
* Attach a single form element to the form. It will be built out and
* validated in the callback(s) listed in hook_elements. We build it
* out in the callbacks rather than here in hook_field_widget so it can be
* plugged into any module that can provide it with valid
* $field information.
*
* Field module will set the weight, field name and delta values
* for each form element.
*
* If there are multiple values for this field, the field module will
* call this function as many times as needed.
*
* @param $form
* the entire form array, $form['#node'] holds node information
* @param $form_state
* the form_state, $form_state['values'][$field['field_name']]
* holds the field's form values.
* @param $field
* The field structure.
* @param $instance
* the field instance array
* @param $items
* array of default values for this field
* @param $delta
* the order of this item in the array of subelements (0, 1, 2, etc)
*
* @return
* the form item for a single element for this field
*/
function text_field_widget(&$form, &$form_state, $field, $instance, $items, $delta = 0) {
$element = array(
'#type' => $instance['widget']['type'],
'#default_value' => isset($items[$delta]) ? $items[$delta] : '',
);
return $element;
}
/**
* Process an individual element.
*
* Build the form element. When creating a form using FAPI #process,
* note that $element['#value'] is already set.
*
* The $field and $instance arrays are in $form['#fields'][$element['#field_name']].
*
* TODO: For widgets to be actual FAPI 'elements', reusable outside of a
* 'field' context, they shoudn't rely on $field and $instance. The bits of
* information needed to adjust the behavior of the 'element' should be
* extracted in hook_field_widget() above.
*/
function text_textfield_process($element, $edit, $form_state, $form) {
$field = $form['#fields'][$element['#field_name']]['field'];
$instance = $form['#fields'][$element['#field_name']]['instance'];
$field_key = $element['#columns'][0];
$delta = $element['#delta'];
$element[$field_key] = array(
'#type' => 'textfield',
'#default_value' => isset($element['#value'][$field_key]) ? $element['#value'][$field_key] : NULL,
'#autocomplete_path' => $element['#autocomplete_path'],
'#size' => $instance['widget']['settings']['size'],
'#attributes' => array('class' => 'text'),
// The following values were set by the field module and need
// to be passed down to the nested element.
'#title' => $element['#title'],
'#description' => $element['#description'],
'#required' => $element['#required'],
'#field_name' => $element['#field_name'],
'#bundle' => $element['#bundle'],
'#delta' => $element['#delta'],
'#columns' => $element['#columns'],
);
$element[$field_key]['#maxlength'] = !empty($field['settings']['max_length']) ? $field['settings']['max_length'] : NULL;
if (!empty($instance['settings']['text_processing'])) {
$filter_key = $element['#columns'][1];
$format = isset($element['#value'][$filter_key]) ? $element['#value'][$filter_key] : FILTER_FORMAT_DEFAULT;
$parents = array_merge($element['#parents'] , array($filter_key));
$element[$filter_key] = filter_form($format, 1, $parents);
}
// Used so that hook_field('validate') knows where to flag an error.
// TODO: rework that. See http://groups.drupal.org/node/18019.
$element['_error_element'] = array(
'#type' => 'value',
'#value' => implode('][', array_merge($element['#parents'], array($field_key))),
);
return $element;
}
/**
* Process an individual element.
*
* Build the form element. When creating a form using FAPI #process,
* note that $element['#value'] is already set.
*
* The $field and $instance arrays are in $form['#fields'][$element['#field_name']].
*/
function text_textarea_process($element, $edit, $form_state, $form) {
$field = $form['#fields'][$element['#field_name']]['field'];
$instance = $form['#fields'][$element['#field_name']]['instance'];
$field_key = $element['#columns'][0];
$delta = $element['#delta'];
$element[$field_key] = array(
'#type' => 'textarea',
'#default_value' => isset($element['#value'][$field_key]) ? $element['#value'][$field_key] : NULL,
'#rows' => $instance['widget']['settings']['rows'],
'#weight' => 0,
// The following values were set by the field module and need
// to be passed down to the nested element.
'#title' => $element['#title'],
'#description' => $element['#description'],
'#required' => $element['#required'],
'#field_name' => $element['#field_name'],
'#bundle' => $element['#bundle'],
'#delta' => $element['#delta'],
'#columns' => $element['#columns'],
);
if (!empty($instance['settings']['text_processing'])) {
$filter_key = (count($element['#columns']) == 2) ? $element['#columns'][1] : 'format';
$format = isset($element['#value'][$filter_key]) ? $element['#value'][$filter_key] : FILTER_FORMAT_DEFAULT;
$parents = array_merge($element['#parents'] , array($filter_key));
$element[$filter_key] = filter_form($format, 1, $parents);
}
// Used so that hook_field('validate') knows where to flag an error.
$element['_error_element'] = array(
'#type' => 'value',
'#value' => implode('][', array_merge($element['#parents'], array($field_key))),
);
return $element;
}
/**
* FAPI theme for an individual text elements.
*
* The textfield or textarea is already rendered by the
* textfield or textarea themes and the html output
* lives in $element['#children']. Override this theme to
* make custom changes to the output.
*
* $element['#field_name'] contains the field name
* $element['#delta] is the position of this element in the group
*/
function theme_text_textfield($element) {
return $element['#children'];
}
function theme_text_textarea($element) {
return $element['#children'];
<?php
// $Id$
/**
* @file
* Defines simple text field types.
*/
/**
* Implementation of hook_theme().
*/
function text_theme() {
return array(
'text_textarea' => array(
'arguments' => array('element' => NULL),
),
'text_textfield' => array(
'arguments' => array('element' => NULL),
),
'field_formatter_text_default' => array(
'arguments' => array('element' => NULL),
),
'field_formatter_text_plain' => array(
'arguments' => array('element' => NULL),
),
'field_formatter_text_trimmed' => array(
'arguments' => array('element' => NULL),
),
);
}
/**
* Implementation of hook_field_info().
*/
function text_field_info() {
return array(
'text' => array(
'label' => t('Text'),
'description' => t('This field stores varchar text in the database.'),
'settings' => array('max_length' => 255),
'instance_settings' => array('text_processing' => 0),
'default_widget' => 'text_textfield',
'default_formatter' => 'text_default',
),
'text_long' => array(
'label' => t('Long text'),
'description' => t('This field stores long text in the database.'),
'instance_settings' => array('text_processing' => 0),
'default_widget' => 'text_textarea',
'default_formatter' => 'text_default',
),
);
}
/**
* Implementation of hook_field_schema().
*/
function text_field_columns($field) {
if ($field['type'] == 'text_long') {
$columns = array(
'value' => array(
'type' => 'text',
'size' => 'big',
'not null' => FALSE,
),
);
}
else {
$columns = array(
'value' => array(
'type' => 'varchar',
'length' => $field['settings']['max_length'],
'not null' => FALSE,
),
);
}
$columns += array(
'format' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => FALSE,
),
);
return $columns;
}
/**
* Implementation of hook_field_validate().
*/
function text_field_validate($obj_type, $object, $field, $instance, $items, $form) {
if (is_array($items)) {
foreach ($items as $delta => $item) {
$error_element = isset($item['_error_element']) ? $item['_error_element'] : '';
if (is_array($item) && isset($item['_error_element'])) unset($item['_error_element']);
if (!empty($item['value'])) {
if (!empty($field['settings']['max_length']) && drupal_strlen($item['value']) > $field['settings']['max_length']) {
form_set_error($error_element, t('%name: the value may not be longer than %max characters.', array('%name' => $instance['label'], '%max' => $field['settings']['max_length'])));
}
}
}
}
}
function text_field_sanitize($obj_type, $object, $field, $instance, &$items) {
global $language;
foreach ($items as $delta => $item) {
// TODO D7 : this code is really node-related.
if (!empty($instance['settings']['text_processing'])) {
$check = is_null($object) || (isset($object->build_mode) && $object->build_mode == NODE_BUILD_PREVIEW);
$text = isset($item['value']) ? check_markup($item['value'], $item['format'], isset($object->language) ? $object->language : $language, $check) : '';
}
else {
$text = check_plain($item['value']);
}
$items[$delta]['safe'] = $text;
}
}
/**
* Implementation of hook_field_is_empty().
*/
function text_field_is_empty($item, $field) {
if (empty($item['value']) && (string)$item['value'] !== '0') {
return TRUE;
}
return FALSE;
}
/**
* Implementation of hook_field_formatter_info().
*/
function text_field_formatter_info() {
return array(
'text_default' => array(
'label' => t('Default'),
'field types' => array('text', 'text_long'),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_DEFAULT,
),
),
'text_plain' => array(
'label' => t('Plain text'),
'field types' => array('text', 'text_long'),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_DEFAULT,
),
),
'text_trimmed' => array(
'label' => t('Trimmed'),
'field types' => array('text', 'text_long'),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_DEFAULT,
),
),
);
}
/**
* Theme function for 'default' text field formatter.
*/
function theme_field_formatter_text_default($element) {
return $element['#item']['safe'];
}
/**
* Theme function for 'plain' text field formatter.
*/
function theme_field_formatter_text_plain($element) {
return strip_tags($element['#item']['safe']);
}
/**
* Theme function for 'trimmed' text field formatter.
*/
function theme_field_formatter_text_trimmed($element) {
$field = field_info_field($element['#field_name']);
$instance = field_info_instance($element['#field_name'], $element['#bundle']);
return $instance['settings']['text_processing'] ? $element['#item']['format'] : NULL;
}
/**
* Implementation of hook_field_widget_info().
*
* Here we indicate that the field module will handle
* the default value and multiple values for these widgets.
*
* Callbacks can be omitted if default handing is used.
* They're included here just so this module can be used
* as an example for custom modules that might do things
* differently.
*/
function text_field_widget_info() {
return array(
'text_textfield' => array(
'label' => t('Text field'),
'field types' => array('text'),
'settings' => array('size' => 60),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_DEFAULT,
'default value' => FIELD_BEHAVIOR_DEFAULT,
),
),
'text_textarea' => array(
'label' => t('Text area (multiple rows)'),
'field types' => array('text_long'),
'settings' => array('rows' => 5),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_DEFAULT,
'default value' => FIELD_BEHAVIOR_DEFAULT,
),
),
);
}
/**
* Implementation of FAPI hook_elements().
*
* Any FAPI callbacks needed for individual widgets can be declared here,
* and the element will be passed to those callbacks for processing.
*
* Drupal will automatically theme the element using a theme with
* the same name as the hook_elements key.
*
* Autocomplete_path is not used by text_field_widget but other
* widgets can use it (see nodereference and userreference).
*/
function text_elements() {
return array(
'text_textfield' => array(
'#input' => TRUE,
'#columns' => array('value'), '#delta' => 0,
'#process' => array('text_textfield_process'),
'#autocomplete_path' => FALSE,
),
'text_textarea' => array(
'#input' => TRUE,
'#columns' => array('value', 'format'), '#delta' => 0,
'#process' => array('text_textarea_process'),
'#filter_value' => FILTER_FORMAT_DEFAULT,
),
);
}
/**
* Implementation of hook_field_widget().
*
* Attach a single form element to the form. It will be built out and
* validated in the callback(s) listed in hook_elements. We build it
* out in the callbacks rather than here in hook_field_widget so it can be
* plugged into any module that can provide it with valid
* $field information.
*
* Field module will set the weight, field name and delta values
* for each form element.
*
* If there are multiple values for this field, the field module will
* call this function as many times as needed.
*
* @param $form
* the entire form array, $form['#node'] holds node information
* @param $form_state
* the form_state, $form_state['values'][$field['field_name']]
* holds the field's form values.
* @param $field
* The field structure.
* @param $instance
* the field instance array
* @param $items
* array of default values for this field
* @param $delta
* the order of this item in the array of subelements (0, 1, 2, etc)
*
* @return
* the form item for a single element for this field
*/
function text_field_widget(&$form, &$form_state, $field, $instance, $items, $delta = 0) {
$element = array(
'#type' => $instance['widget']['type'],
'#default_value' => isset($items[$delta]) ? $items[$delta] : '',
);
return $element;
}
/**
* Process an individual element.
*
* Build the form element. When creating a form using FAPI #process,
* note that $element['#value'] is already set.
*
* The $field and $instance arrays are in $form['#fields'][$element['#field_name']].
*
* TODO: For widgets to be actual FAPI 'elements', reusable outside of a
* 'field' context, they shoudn't rely on $field and $instance. The bits of
* information needed to adjust the behavior of the 'element' should be
* extracted in hook_field_widget() above.
*/
function text_textfield_process($element, $edit, $form_state, $form) {
$field = $form['#fields'][$element['#field_name']]['field'];
$instance = $form['#fields'][$element['#field_name']]['instance'];
$field_key = $element['#columns'][0];
$delta = $element['#delta'];
$element[$field_key] = array(
'#type' => 'textfield',
'#default_value' => isset($element['#value'][$field_key]) ? $element['#value'][$field_key] : NULL,
'#autocomplete_path' => $element['#autocomplete_path'],
'#size' => $instance['widget']['settings']['size'],
'#attributes' => array('class' => 'text'),
// The following values were set by the field module and need
// to be passed down to the nested element.
'#title' => $element['#title'],
'#description' => $element['#description'],
'#required' => $element['#required'],
'#field_name' => $element['#field_name'],
'#bundle' => $element['#bundle'],
'#delta' => $element['#delta'],
'#columns' => $element['#columns'],
);
$element[$field_key]['#maxlength'] = !empty($field['settings']['max_length']) ? $field['settings']['max_length'] : NULL;
if (!empty($instance['settings']['text_processing'])) {
$filter_key = $element['#columns'][1];
$format = isset($element['#value'][$filter_key]) ? $element['#value'][$filter_key] : FILTER_FORMAT_DEFAULT;
$parents = array_merge($element['#parents'] , array($filter_key));
$element[$filter_key] = filter_form($format, 1, $parents);
}
// Used so that hook_field('validate') knows where to flag an error.
// TODO: rework that. See http://groups.drupal.org/node/18019.
$element['_error_element'] = array(
'#type' => 'value',
'#value' => implode('][', array_merge($element['#parents'], array($field_key))),
);
return $element;
}
/**
* Process an individual element.
*
* Build the form element. When creating a form using FAPI #process,
* note that $element['#value'] is already set.
*
* The $field and $instance arrays are in $form['#fields'][$element['#field_name']].
*/
function text_textarea_process($element, $edit, $form_state, $form) {
$field = $form['#fields'][$element['#field_name']]['field'];
$instance = $form['#fields'][$element['#field_name']]['instance'];
$field_key = $element['#columns'][0];
$delta = $element['#delta'];
$element[$field_key] = array(
'#type' => 'textarea',
'#default_value' => isset($element['#value'][$field_key]) ? $element['#value'][$field_key] : NULL,
'#rows' => $instance['widget']['settings']['rows'],
'#weight' => 0,
// The following values were set by the field module and need
// to be passed down to the nested element.
'#title' => $element['#title'],
'#description' => $element['#description'],
'#required' => $element['#required'],
'#field_name' => $element['#field_name'],
'#bundle' => $element['#bundle'],
'#delta' => $element['#delta'],
'#columns' => $element['#columns'],
);
if (!empty($instance['settings']['text_processing'])) {
$filter_key = (count($element['#columns']) == 2) ? $element['#columns'][1] : 'format';
$format = isset($element['#value'][$filter_key]) ? $element['#value'][$filter_key] : FILTER_FORMAT_DEFAULT;
$parents = array_merge($element['#parents'] , array($filter_key));
$element[$filter_key] = filter_form($format, 1, $parents);
}
// Used so that hook_field('validate') knows where to flag an error.
$element['_error_element'] = array(
'#type' => 'value',
'#value' => implode('][', array_merge($element['#parents'], array($field_key))),
);
return $element;
}
/**
* FAPI theme for an individual text elements.
*
* The textfield or textarea is already rendered by the
* textfield or textarea themes and the html output
* lives in $element['#children']. Override this theme to
* make custom changes to the output.
*
* $element['#field_name'] contains the field name
* $element['#delta] is the position of this element in the group
*/
function theme_text_textfield($element) {
return $element['#children'];
}
function theme_text_textarea($element) {
return $element['#children'];
}

View File

@ -1,103 +1,103 @@
<?php
$field = array(
'field_name' => 'field_single',
'type' => 'text',
);
field_create_field($field);
$instance = array(
'field_name' => 'field_single',
'bundle' => 'article',
'label' => 'Single',
'widget' => array(
'type' => 'text_textfield',
),
'display' => array(
'full' => array(
'label' => 'above',
'type' => 'text_default',
'exclude' => 0,
),
),
);
field_create_instance($instance);
$instance['bundle'] = 'user';
field_create_instance($instance);
$field = array(
'field_name' => 'field_multiple',
'cardinality' => FIELD_CARDINALITY_UNLIMITED,
'type' => 'text',
);
field_create_field($field);
$instance = array(
'field_name' => 'field_multiple',
'bundle' => 'article',
'label' => 'Multiple',
'widget' => array(
'type' => 'text_textfield',
),
'display' => array(
'full' => array(
'label' => 'above',
'type' => 'text_default',
'exclude' => 0,
),
),
);
field_create_instance($instance);
$instance['bundle'] = 'user';
field_create_instance($instance);
// Number
$field = array(
'field_name' => 'field_integer',
'type' => 'number_integer',
);
field_create_field($field);
$instance = array(
'field_name' => 'field_integer',
'bundle' => 'article',
'label' => 'Integer',
'widget' => array(
'type' => 'number',
),
'display' => array(
'full' => array(
'label' => 'above',
'type' => 'number_integer',
'exclude' => 0,
),
),
);
field_create_instance($instance);
$field = array(
'field_name' => 'field_decimal',
'type' => 'number_decimal',
);
field_create_field($field);
$instance = array(
'field_name' => 'field_decimal',
'bundle' => 'article',
'label' => 'Decimal',
'widget' => array(
'type' => 'number',
),
'display' => array(
'full' => array(
'label' => 'above',
'type' => 'number_decimal',
'exclude' => 0,
),
),
);
field_create_instance($instance);
<?php
$field = array(
'field_name' => 'field_single',
'type' => 'text',
);
field_create_field($field);
$instance = array(
'field_name' => 'field_single',
'bundle' => 'article',
'label' => 'Single',
'widget' => array(
'type' => 'text_textfield',
),
'display' => array(
'full' => array(
'label' => 'above',
'type' => 'text_default',
'exclude' => 0,
),
),
);
field_create_instance($instance);
$instance['bundle'] = 'user';
field_create_instance($instance);
$field = array(
'field_name' => 'field_multiple',
'cardinality' => FIELD_CARDINALITY_UNLIMITED,
'type' => 'text',
);
field_create_field($field);
$instance = array(
'field_name' => 'field_multiple',
'bundle' => 'article',
'label' => 'Multiple',
'widget' => array(
'type' => 'text_textfield',
),
'display' => array(
'full' => array(
'label' => 'above',
'type' => 'text_default',
'exclude' => 0,
),
),
);
field_create_instance($instance);
$instance['bundle'] = 'user';
field_create_instance($instance);
// Number
$field = array(
'field_name' => 'field_integer',
'type' => 'number_integer',
);
field_create_field($field);
$instance = array(
'field_name' => 'field_integer',
'bundle' => 'article',
'label' => 'Integer',
'widget' => array(
'type' => 'number',
),
'display' => array(
'full' => array(
'label' => 'above',
'type' => 'number_integer',
'exclude' => 0,
),
),
);
field_create_instance($instance);
$field = array(
'field_name' => 'field_decimal',
'type' => 'number_decimal',
);
field_create_field($field);
$instance = array(
'field_name' => 'field_decimal',
'bundle' => 'article',
'label' => 'Decimal',
'widget' => array(
'type' => 'number',
),
'display' => array(
'full' => array(
'label' => 'above',
'type' => 'number_decimal',
'exclude' => 0,
),
),
);
field_create_instance($instance);

View File

@ -1,3 +1,5 @@
/* $Id$ */
/* Node display */
.field .field-label,
.field .field-label-inline,
@ -27,4 +29,4 @@
.node-form .number {
display:inline;
width:auto;
}
}

View File

@ -257,10 +257,10 @@ function node_form(&$form_state, $node) {
);
}
$form['#validate'][] = 'node_form_validate';
$form['#theme'] = array($node->type . '_node_form', 'node_form');
$form['#builder_function'] = 'node_form_submit_build_node';
field_attach_form('node', $node, $form, $form_state);
$form['#theme'] = array($node->type . '_node_form', 'node_form');
$form['#builder_function'] = 'node_form_submit_build_node';
field_attach_form('node', $node, $form, $form_state);
return $form;
}
@ -468,10 +468,10 @@ function node_form_submit_build_node($form, &$form_state) {
// Unset any button-level handlers, execute all the form-level submit
// functions to process the form values into an updated node.
unset($form_state['submit_handlers']);
form_execute_handlers('submit', $form, $form_state);
$node = node_submit($form_state['values']);
field_attach_submit('node', $node, $form, $form_state);
form_execute_handlers('submit', $form, $form_state);
$node = node_submit($form_state['values']);
field_attach_submit('node', $node, $form, $form_state);
$form_state['node'] = (array)$node;
$form_state['rebuild'] = TRUE;

View File

@ -20,7 +20,7 @@
* - $terms: the themed list of taxonomy term links output from theme_links().
* - $submitted: themed submission information output from
* theme_node_submitted().
* TODO D7 : document $FIELD_NAME_rendered variables.
* TODO D7 : document $FIELD_NAME_rendered variables.
*
* Other variables:
* - $node: Full node object. Contains data that may not be safe.

View File

@ -2,59 +2,59 @@
// $Id$
/**
* Implementation of hook_schema().
* Implementation of hook_schema().
*/
function field_test_schema() {
$schema['test_entity'] = array(
'description' => 'The base table for test_entities.',
'fields' => array(
'ftid' => array(
'description' => 'The primary identifier for a test_entity.',
'type' => 'serial',
'unsigned' => TRUE,
'not null' => TRUE,
),
'ftvid' => array(
'description' => 'The current {test_entity_revision}.ftvid version identifier.',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'fttype' => array(
'description' => 'The type of this test_entity.',
'type' => 'varchar',
'length' => 32,
'not null' => TRUE,
'default' => '',
'description' => 'The base table for test_entities.',
'fields' => array(
'ftid' => array(
'description' => 'The primary identifier for a test_entity.',
'type' => 'serial',
'unsigned' => TRUE,
'not null' => TRUE,
),
'ftvid' => array(
'description' => 'The current {test_entity_revision}.ftvid version identifier.',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'fttype' => array(
'description' => 'The type of this test_entity.',
'type' => 'varchar',
'length' => 32,
'not null' => TRUE,
'default' => '',
),
),
'unique keys' => array(
'ftvid' => array('ftvid'),
),
'unique keys' => array(
'ftvid' => array('ftvid'),
),
'primary key' => array('ftid'),
);
$schema['test_entity_revision'] = array(
'description' => 'Stores information about each saved version of a {test_entity}.',
'fields' => array(
'ftid' => array(
'description' => 'The {test_entity} this version belongs to.',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'ftvid' => array(
'description' => 'The primary identifier for this version.',
'type' => 'serial',
'unsigned' => TRUE,
'not null' => TRUE,
),
),
'indexes' => array(
'nid' => array('ftid'),
),
'primary key' => array('ftvid'),
);
$schema['test_entity_revision'] = array(
'description' => 'Stores information about each saved version of a {test_entity}.',
'fields' => array(
'ftid' => array(
'description' => 'The {test_entity} this version belongs to.',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'ftvid' => array(
'description' => 'The primary identifier for this version.',
'type' => 'serial',
'unsigned' => TRUE,
'not null' => TRUE,
),
),
'indexes' => array(
'nid' => array('ftid'),
),
'primary key' => array('ftvid'),
);
return $schema;

View File

@ -3,299 +3,299 @@
define('FIELD_TEST_ELEMENT_ID', 1);
define('FIELD_TEST_BUNDLE', 'test_bundle');
/**
* Implementation of hook_perm().
*/
function field_test_perm() {
$perms = array(
'access field_test content' => array(
'title' => t('Access field_test content'),
'description' => t('View published field_test content.'),
),
'administer field_test content' => array(
'title' => t('Administer field_test content'),
'description' => t('Manage field_test content'),
),
);
return $perms;
}
/**
* Implementation of hook_menu().
*/
function field_test_menu() {
$items = array();
$info = field_test_fieldable_info();
foreach (array_keys($info['test_entity']['bundles']) as $bundle) {
$bundle_url_str = str_replace('_', '-', $bundle);
$items['test-entity/add/' . $bundle_url_str] = array(
'title' => "Add $bundle test_entity",
'page callback' => 'field_test_entity_add',
'page arguments' => array(2),
'access arguments' => array('administer field_test content'),
'type' => MENU_NORMAL_ITEM,
);
}
$items['test-entity/%field_test_entity/edit'] = array(
'title' => 'Edit test entity',
'page callback' => 'field_test_entity_edit',
'page arguments' => array(1),
'access arguments' => array('administer field_test content'),
'type' => MENU_NORMAL_ITEM,
);
return $items;
}
/**
*
* 'Field attach' API.
*
*/
/**
* Define a test fieldable entity.
*/
function field_test_fieldable_info() {
$bundles = variable_get('field_test_bundles', array('test_bundle' => 'Test Bundle'));
return array(
'test_entity' => array(
'name' => t('Test Entity'),
'id key' => 'ftid',
'revision key' => 'ftvid',
'cacheable' => FALSE,
'bundle key' => 'fttype',
'bundles' => $bundles,
),
// This entity type doesn't get form handling for now...
'test_cacheable_entity' => array(
'name' => t('Test Entity, cacheable'),
'id key' => 'ftid',
'revision key' => 'ftvid',
'cacheable' => TRUE,
'bundle key' => 'fttype',
'bundles' => $bundles,
),
);
}
function field_test_create_bundle($bundle, $text) {
$bundles = variable_get('field_test_bundles', array('field_text_bundle' => 'Test Bundle'));
$bundles += array($bundle => $text);
variable_set('field_test_bundles', $bundles);
field_attach_create_bundle($bundle);
}
function field_test_rename_bundle($bundle_old, $bundle_new) {
$bundles = variable_get('field_test_bundles', array('field_text_bundle' => 'Test Bundle'));
$bundles[$bundle_new] = $bundles[$bundle_old];
unset($bundles[$bundle_old]);
variable_set('field_test_bundles', $bundles);
field_attach_rename_bundle($bundle_old, $bundle_new);
}
function field_test_delete_bundle($bundle) {
$bundles = variable_get('field_test_bundles', array('field_text_bundle' => 'Test Bundle'));
unset($bundles[$bundle]);
variable_set('field_test_bundles', $bundles);
field_attach_delete_bundle($bundle);
}
/**
* Implementation of hook_field_build_modes().
*/
function field_test_field_build_modes($obj_type) {
$modes = array();
if ($obj_type == 'test_entity' || $obj_type == 'test_cacheable_entity') {
$modes = array(
'full' => t('Full node'),
'teaser' => t('Teaser'),
);
}
return $modes;
}
/**
* Helper function to create a basic 'test entity' structure.
*
* TODO : do we stil need this now that we can actualy load and save test_entities ?
*/
function field_test_create_stub_entity($id = 1, $vid = 1, $bundle = FIELD_TEST_BUNDLE) {
$entity = new stdClass();
$entity->ftid = $id;
$entity->ftvid = $vid;
$entity->fttype = $bundle;
return $entity;
}
function field_test_entity_load($ftid, $ftvid = NULL) {
// Load basic strucure.
$query = db_select('test_entity', 'fte', array())
->fields('fte')
->condition('ftid', $ftid);
if ($ftvid) {
$query->condition('ftvid', $ftvid);
}
$entities = $query->execute()->fetchAllAssoc('ftid');
// Attach fields.
if ($ftvid) {
field_attach_load_revision('test_entity', $entities);
}
else {
field_attach_load('test_entity', $entities);
}
return $entities[$ftid];
}
function field_test_entity_save(&$entity) {
field_attach_presave('test_entity', $entity);
$entity->is_new = FALSE;
if (empty($entity->ftid)) {
// Insert a new test_entity.
$entity->is_new = TRUE;
}
elseif (!empty($entity->revision)) {
$entity->old_ftvid = $entity->ftvid;
}
$update_entity = TRUE;
if ($entity->is_new) {
drupal_write_record('test_entity', $entity);
drupal_write_record('test_entity_revision', $entity);
$op = 'insert';
}
else {
drupal_write_record('test_entity', $entity, 'ftid');
if (!empty($entity->revision)) {
drupal_write_record('test_entity_revision', $entity);
}
else {
drupal_write_record('test_entity_revision', $entity, 'ftvid');
$update_entity = FALSE;
}
$op = 'update';
}
if ($update_entity) {
db_update('test_entity')
->fields(array('ftvid' => $entity->ftvid))
->condition('ftid', $entity->ftid)
->execute();
}
// Save fields.
$function = "field_attach_$op";
$function('test_entity', $entity);
}
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);
}
function field_test_entity_edit($entity) {
drupal_set_title(t('test_entity @ftid revision @ftvid', array('@ftid' => $entity->ftid, '@ftvid' => $entity->ftvid)), PASS_THROUGH);
return drupal_get_form('field_test_entity_form', $entity);
}
/**
* Form to set the value of fields attached to our entity.
*/
function field_test_entity_form(&$form_state, $entity) {
$form = array();
if (isset($form_state['test_entity'])) {
$entity = $form_state['test_entity'] + (array)$entity;
}
$entity = (object)$entity;
foreach (array('ftid', 'ftvid', 'fttype') as $key) {
$form[$key] = array(
'#type' => 'value',
'#value' => isset($entity->$key) ? $entity->$key : NULL,
);
}
// Add field widgets.
$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,
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Save'),
'#weight' => 101,
);
return $form;
}
/**
* Validate handler for field_test_set_field_values().
*/
function field_test_entity_form_validate($form, &$form_state) {
$entity = (object)$form_state['values'];
field_attach_validate('test_entity', $entity, $form);
}
/**
* Submit handler for field_test_set_field_values().
*/
function field_test_entity_form_submit($form, &$form_state) {
$entity = field_test_entity_form_submit_builder($form, $form_state);
$insert = empty($entity->ftid);
field_test_entity_save($entity);
$message = $insert ? t('test_entity @id has been created.', array('@id' => $entity->ftid)) : t('test_entity @id has been updated.', array('@id' => $entity->ftid));
drupal_set_message($message);
if ($entity->ftid) {
unset($form_state['rebuild']);
$form_state['redirect'] = 'test-entity/' . $entity->ftid . '/edit';
}
else {
// Error on save.
drupal_set_message(t('The entity could not be saved.'), 'error');
}
}
/**
* Build a test_entity by processing submitted form values and prepare for a form rebuild.
*/
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']);
field_attach_submit('test_entity', $entity, $form, $form_state);
$form_state['test_entity'] = (array)$entity;
$form_state['rebuild'] = TRUE;
return $entity;
}
/**
*
* 'Field type' API.
*
*/
/**
* Implementation of hook_perm().
*/
function field_test_perm() {
$perms = array(
'access field_test content' => array(
'title' => t('Access field_test content'),
'description' => t('View published field_test content.'),
),
'administer field_test content' => array(
'title' => t('Administer field_test content'),
'description' => t('Manage field_test content'),
),
);
return $perms;
}
/**
* Implementation of hook_menu().
*/
function field_test_menu() {
$items = array();
$info = field_test_fieldable_info();
foreach (array_keys($info['test_entity']['bundles']) as $bundle) {
$bundle_url_str = str_replace('_', '-', $bundle);
$items['test-entity/add/' . $bundle_url_str] = array(
'title' => "Add $bundle test_entity",
'page callback' => 'field_test_entity_add',
'page arguments' => array(2),
'access arguments' => array('administer field_test content'),
'type' => MENU_NORMAL_ITEM,
);
}
$items['test-entity/%field_test_entity/edit'] = array(
'title' => 'Edit test entity',
'page callback' => 'field_test_entity_edit',
'page arguments' => array(1),
'access arguments' => array('administer field_test content'),
'type' => MENU_NORMAL_ITEM,
);
return $items;
}
/**
*
* 'Field attach' API.
*
*/
/**
* Define a test fieldable entity.
*/
function field_test_fieldable_info() {
$bundles = variable_get('field_test_bundles', array('test_bundle' => 'Test Bundle'));
return array(
'test_entity' => array(
'name' => t('Test Entity'),
'id key' => 'ftid',
'revision key' => 'ftvid',
'cacheable' => FALSE,
'bundle key' => 'fttype',
'bundles' => $bundles,
),
// This entity type doesn't get form handling for now...
'test_cacheable_entity' => array(
'name' => t('Test Entity, cacheable'),
'id key' => 'ftid',
'revision key' => 'ftvid',
'cacheable' => TRUE,
'bundle key' => 'fttype',
'bundles' => $bundles,
),
);
}
function field_test_create_bundle($bundle, $text) {
$bundles = variable_get('field_test_bundles', array('field_text_bundle' => 'Test Bundle'));
$bundles += array($bundle => $text);
variable_set('field_test_bundles', $bundles);
field_attach_create_bundle($bundle);
}
function field_test_rename_bundle($bundle_old, $bundle_new) {
$bundles = variable_get('field_test_bundles', array('field_text_bundle' => 'Test Bundle'));
$bundles[$bundle_new] = $bundles[$bundle_old];
unset($bundles[$bundle_old]);
variable_set('field_test_bundles', $bundles);
field_attach_rename_bundle($bundle_old, $bundle_new);
}
function field_test_delete_bundle($bundle) {
$bundles = variable_get('field_test_bundles', array('field_text_bundle' => 'Test Bundle'));
unset($bundles[$bundle]);
variable_set('field_test_bundles', $bundles);
field_attach_delete_bundle($bundle);
}
/**
* Implementation of hook_field_build_modes().
*/
function field_test_field_build_modes($obj_type) {
$modes = array();
if ($obj_type == 'test_entity' || $obj_type == 'test_cacheable_entity') {
$modes = array(
'full' => t('Full node'),
'teaser' => t('Teaser'),
);
}
return $modes;
}
/**
* Helper function to create a basic 'test entity' structure.
*
* TODO : do we stil need this now that we can actualy load and save test_entities ?
*/
function field_test_create_stub_entity($id = 1, $vid = 1, $bundle = FIELD_TEST_BUNDLE) {
$entity = new stdClass();
$entity->ftid = $id;
$entity->ftvid = $vid;
$entity->fttype = $bundle;
return $entity;
}
function field_test_entity_load($ftid, $ftvid = NULL) {
// Load basic strucure.
$query = db_select('test_entity', 'fte', array())
->fields('fte')
->condition('ftid', $ftid);
if ($ftvid) {
$query->condition('ftvid', $ftvid);
}
$entities = $query->execute()->fetchAllAssoc('ftid');
// Attach fields.
if ($ftvid) {
field_attach_load_revision('test_entity', $entities);
}
else {
field_attach_load('test_entity', $entities);
}
return $entities[$ftid];
}
function field_test_entity_save(&$entity) {
field_attach_presave('test_entity', $entity);
$entity->is_new = FALSE;
if (empty($entity->ftid)) {
// Insert a new test_entity.
$entity->is_new = TRUE;
}
elseif (!empty($entity->revision)) {
$entity->old_ftvid = $entity->ftvid;
}
$update_entity = TRUE;
if ($entity->is_new) {
drupal_write_record('test_entity', $entity);
drupal_write_record('test_entity_revision', $entity);
$op = 'insert';
}
else {
drupal_write_record('test_entity', $entity, 'ftid');
if (!empty($entity->revision)) {
drupal_write_record('test_entity_revision', $entity);
}
else {
drupal_write_record('test_entity_revision', $entity, 'ftvid');
$update_entity = FALSE;
}
$op = 'update';
}
if ($update_entity) {
db_update('test_entity')
->fields(array('ftvid' => $entity->ftvid))
->condition('ftid', $entity->ftid)
->execute();
}
// Save fields.
$function = "field_attach_$op";
$function('test_entity', $entity);
}
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);
}
function field_test_entity_edit($entity) {
drupal_set_title(t('test_entity @ftid revision @ftvid', array('@ftid' => $entity->ftid, '@ftvid' => $entity->ftvid)), PASS_THROUGH);
return drupal_get_form('field_test_entity_form', $entity);
}
/**
* Form to set the value of fields attached to our entity.
*/
function field_test_entity_form(&$form_state, $entity) {
$form = array();
if (isset($form_state['test_entity'])) {
$entity = $form_state['test_entity'] + (array)$entity;
}
$entity = (object)$entity;
foreach (array('ftid', 'ftvid', 'fttype') as $key) {
$form[$key] = array(
'#type' => 'value',
'#value' => isset($entity->$key) ? $entity->$key : NULL,
);
}
// Add field widgets.
$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,
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Save'),
'#weight' => 101,
);
return $form;
}
/**
* Validate handler for field_test_set_field_values().
*/
function field_test_entity_form_validate($form, &$form_state) {
$entity = (object)$form_state['values'];
field_attach_validate('test_entity', $entity, $form);
}
/**
* Submit handler for field_test_set_field_values().
*/
function field_test_entity_form_submit($form, &$form_state) {
$entity = field_test_entity_form_submit_builder($form, $form_state);
$insert = empty($entity->ftid);
field_test_entity_save($entity);
$message = $insert ? t('test_entity @id has been created.', array('@id' => $entity->ftid)) : t('test_entity @id has been updated.', array('@id' => $entity->ftid));
drupal_set_message($message);
if ($entity->ftid) {
unset($form_state['rebuild']);
$form_state['redirect'] = 'test-entity/' . $entity->ftid . '/edit';
}
else {
// Error on save.
drupal_set_message(t('The entity could not be saved.'), 'error');
}
}
/**
* Build a test_entity by processing submitted form values and prepare for a form rebuild.
*/
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']);
field_attach_submit('test_entity', $entity, $form, $form_state);
$form_state['test_entity'] = (array)$entity;
$form_state['rebuild'] = TRUE;
return $entity;
}
/**
*
* 'Field type' API.
*
*/
/**
* Implementation of hook_field_info().
@ -327,11 +327,11 @@ function field_test_field_columns($field) {
return $columns;
}
/**
* Implementation of hook_instance_settings().
*/
function field_test_field_instance_settings($field_type) {
return array('test_instance_setting' => 'dummy test string');
/**
* Implementation of hook_instance_settings().
*/
function field_test_field_instance_settings($field_type) {
return array('test_instance_setting' => 'dummy test string');
}
/**
@ -395,8 +395,8 @@ function field_test_field_widget_info() {
'field types' => array('test_field'),
'settings' => array('test_widget_setting_multiple' => 'dummy test string'),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_CUSTOM,
'default value' => FIELD_BEHAVIOR_DEFAULT,
'multiple values' => FIELD_BEHAVIOR_CUSTOM,
'default value' => FIELD_BEHAVIOR_DEFAULT,
),
),
);
@ -436,31 +436,31 @@ function field_test_field_widget_info() {
* the form item for a single element for this field
*/
function field_test_field_widget(&$form, &$form_state, $field, $instance, $items, $delta = 0) {
$element = array(
'value' => array(
$element = array(
'value' => array(
'#title' => $instance['label'],
'#type' => 'textfield',
'#default_value' => isset($items[$delta]['value']) ? $items[$delta]['value'] : '',
'#required' => $instance['required'],
'#default_value' => isset($items[$delta]['value']) ? $items[$delta]['value'] : '',
'#required' => $instance['required'],
),
);
return $element;
}
/**
* Implementation of hook_field_formatter_info().
*/
function field_test_field_formatter_info() {
return array(
'field_test_default' => array(
'label' => t('Default'),
'field types' => array('test_field'),
/**
* Implementation of hook_field_formatter_info().
*/
function field_test_field_formatter_info() {
return array(
'field_test_default' => array(
'label' => t('Default'),
'field types' => array('test_field'),
'settings' => array(
'test_formatter_setting' => 'dummy test string',
),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_DEFAULT,
),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_DEFAULT,
),
),
'field_test_multiple' => array(
'label' => t('Default'),
@ -471,32 +471,32 @@ function field_test_field_formatter_info() {
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_CUSTOM,
),
),
);
}
/**
* Implementation of hook_theme().
*/
function field_test_theme() {
return array(
'field_formatter_field_test_default' => array(
'arguments' => array('element' => NULL),
),
'field_formatter_field_test_multiple' => array(
'arguments' => array('element' => NULL),
),
);
}
),
);
}
/**
* Theme function for 'field_test_default' formatter.
*/
/**
* Implementation of hook_theme().
*/
function field_test_theme() {
return array(
'field_formatter_field_test_default' => array(
'arguments' => array('element' => NULL),
),
'field_formatter_field_test_multiple' => array(
'arguments' => array('element' => NULL),
),
);
}
/**
* Theme function for 'field_test_default' formatter.
*/
function theme_field_formatter_field_test_default($element) {
$value = $element['#item']['value'];
$settings = $element['#settings'];
return $settings['test_formatter_setting'] . '|' . $value;
return $settings['test_formatter_setting'] . '|' . $value;
}
/**

View File

@ -38,7 +38,7 @@
* Available variables:
* - $user_profile: All user profile data. Ready for print.
* - $profile: Keyed array of profile categories and their items or other data
* provided by modules.
* provided by modules.
* - TODO D7 : document $FIELD_NAME_rendered variables.
*
* @see template_preprocess_user_profile()