| 7 field.attach.inc | field_attach_form( |
| 8 field.attach.inc | field_attach_form(EntityInterface $entity, &$form, &$form_state, $langcode = NULL, array $options = array()) |
Add form elements for all fields for an entity to a form structure.
The form elements for the entity's fields are added by reference as direct children in the $form parameter. This parameter can be a full form structure (most common case for entity edit forms), or a sub-element of a larger form.
By default, submitted field values appear at the top-level of $form_state['values']. A different location within $form_state['values'] can be specified by setting the '#parents' property on the incoming $form parameter. Because of name clashes, two instances of the same field cannot appear within the same $form element, or within the same '#parents' space.
For each call to field_attach_form(), field values are processed by calling field_attach_form_validate() and field_attach_submit() on the same $form element.
Sample resulting structure in $form:
'#parents' => The location of field values in $form_state['values'],
'#entity_type' => The name of the entity type,
'#bundle' => The name of the bundle,
// One sub-array per field appearing in the entity, keyed by field name.
// The structure of the array differs slightly depending on whether the
// widget is 'single-value' (provides the input for one field value,
// most common case), and will therefore be repeated as many times as
// needed, or 'multiple-values' (one single widget allows the input of
// several values, e.g checkboxes, select box...).
// The sub-array is nested into a $langcode key where $langcode has the
// same value of the $langcode parameter above.
// The '#language' key holds the same value of $langcode and it is used
// to access the field sub-array when $langcode is unknown.
'field_foo' => array(
'#tree' => TRUE,
'#field_name' => The name of the field,
'#language' => $langcode,
$langcode => array(
'#field_name' => The name of the field,
'#language' => $langcode,
'#field_parents' => The 'parents' space for the field in the form,
equal to the #parents property of the $form parameter received by
field_attach_form(),
'#required' => Whether or not the field is required,
'#title' => The label of the field instance,
'#description' => The description text for the field instance,
// Only for 'single' widgets:
'#theme' => 'field_multiple_value_form',
'#cardinality' => The field cardinality,
// One sub-array per copy of the widget, keyed by delta.
0 => array(
'#entity_type' => The name of the entity type,
'#bundle' => The name of the bundle,
'#field_name' => The name of the field,
'#field_parents' => The 'parents' space for the field in the form,
equal to the #parents property of the $form parameter received by
field_attach_form(),
'#title' => The title to be displayed by the widget,
'#default_value' => The field value for delta 0,
'#required' => Whether the widget should be marked required,
'#delta' => 0,
'#columns' => The array of field columns,
// The remaining elements in the sub-array depend on the widget.
'#type' => The type of the widget,
...
),
1 => array(
...
),
// Only for multiple widgets:
'#entity_type' => The name of the entity type,
'#bundle' => $instance['bundle'],
'#columns' => array_keys($field['columns']),
// The remaining elements in the sub-array depend on the widget.
'#type' => The type of the widget,
...
),
...
),
)
Additionally, some processing data is placed in $form_state, and can be accessed by field_form_get_state() and field_form_set_state().
Parameters
$entity_type: The type of $entity; e.g. 'node' or 'user'.
$entity: The entity for which to load form elements, used to initialize default form values.
$form: The form structure to fill in. This can be a full form structure, or a sub-element of a larger form. The #parents property can be set to control the location of submitted field values within $form_state['values']. If not specified, $form['#parents'] is set to an empty array, placing field values at the top-level of $form_state['values'].
$form_state: An associative array containing the current state of the form.
$langcode: The language the field values are going to be entered, if no language is provided the default site language will be used.
array $options: An associative array of additional options. See _field_invoke() for details.
See also
Related topics
- comment_form in modules/
comment/ comment.module - Generate the basic commenting form, for appending to a node or display on a separate page.
- FieldAttachOtherTestCase::testFieldAttachForm in modules/
field/ tests/ field.test - Test field_attach_form().
- FieldAttachOtherTestCase::testFieldAttachSubmit in modules/
field/ tests/ field.test - Test field_attach_submit().
- FieldFormTestCase::testFieldFormAccess in modules/
field/ tests/ field.test - Tests fields with no 'edit' access.
- field_test_entity_form in modules/
field/ tests/ field_test.entity.inc - Test_entity form.
File
- modules/
field/ field.attach.inc, line 564 - Field attach API, allowing entities (nodes, users, ...) to be 'fieldable'.
Code
function field_attach_form($entity_type, $entity, &$form, &$form_state, $langcode = NULL, $options = array()) {
// Validate $options since this is a new parameter added after Drupal 7 was
// released.
$options = is_array($options) ? $options : array();
// Set #parents to 'top-level' by default.
$form += array('#parents' => array());
// If no language is provided use the default site language.
$options['language'] = field_valid_language($langcode);
$form += (array) _field_invoke_default('form', $entity_type, $entity, $form, $form_state, $options);
// Add custom weight handling.
list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
$form['#pre_render'][] = '_field_extra_fields_pre_render';
$form['#entity_type'] = $entity_type;
$form['#bundle'] = $bundle;
// Let other modules make changes to the form.
// Avoid module_invoke_all() to let parameters be taken by reference.
foreach (module_implements('field_attach_form') as $module) {
$function = $module . '_field_attach_form';
$function($entity_type, $entity, $form, $form_state, $langcode);
}
}
Comments
Recommended $langcode value
PermalinkThe value returned by entity_language() is now the recommended value to be passed as
$langcodeparameter, when the logic being implemented does not explicitly dictate a different one. See the change record and hook_entity_info().to attach a single form field from one bundle in another form
PermalinkTwo approaches that work to add a single field off an arbitrary entity bundle: Append the whole form and unset() unneeded fields or create a temporary form and copy in the field(s) needed. Here, I demonstrate implementing an existing autocomplete nodereference textfield from a node form onto another form: create the form as a temporary form and formstate, and copy in to place that field definition. In my case, I'm working on a Commerce checkout form alter:
<?phpfunction example_form_commerce_checkout_form_checkout_alter(&$form, &$form_state, $form_id) {
$tmpform = array();
$tmpform_state = array();
$tmpnode = new stdClass();
$tmpnode->type = 'card';
// Create the temporary form/state by reference
field_attach_form('node', $tmpnode, $tmpform, $tmpform_state);
// Create a new fieldset on the Commerce checkout form
$form['cart_contents']['org_ref_wrap'] = array(
'#type' => 'fieldset',
'#title' => t('Support Organization'),
'#description' => t('Optionally, select an organization to benefit from your membership purchase (no additional cost!).'),
);
// Place a copy of the new form field within the new fieldset
$form['cart_contents']['org_ref_wrap'][] = $tmpform['field_card_organization'];
// Copy over the $form_state field element as well to avoid notices <code>Undefined index .. field in field_widget_field() line 578</code>
$form_state['field']['field_card_organization'] = $tmpform_state['field']['field_card_organization'];
..
?>
Another approach
Permalinkanother approach to attach a specific field from a entity to a form.
this option only works if you want only one field attached.
<?php
function my_module_form_alter(&$form, &$form_state, $form_id) {
if($form_id == 'form_i_want_to_attach') {
//need a entity object from the entity i want the field
$nid = $form_state["build_info"]["args"][0];
$node = entity_load('node',array($nid));
//necessary to avoid errors$form += array('#parents' => array());
$options = array(//specify the languaje, or use like this for the default language.
'language' => field_valid_language(NULL),
//IMPORTANT : the field you want to attach to the form
'field_name'=>'field_my_special_field'
);
$form += (array) _field_invoke_default(
'form','node',$node, $form,$form_state,$options
);
}
}
?>
If there's a better way to do it please let us know
Attached field doesn't submit value
PermalinkHi texas-bronius, I followed your instructions and attached a single field from one content type to a custom form (a slickgrid modal edit form) of another content type. Everything seemed to be fine but when I looked for the values just submitted by this field I couldn't find any record in the database. What I did wrong or misunderstood? Thank you in advance!