function inline_entity_form_field_widget_form in Inline Entity Form 7
Implements hook_field_widget_form().
File
- ./
inline_entity_form.module, line 372 - Provides a widget for inline management (creation, modification, removal) of referenced entities. The primary use case is the parent -> children one (for example, order -> line items), where the child entities are never managed outside the…
Code
function inline_entity_form_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
$widget = $instance['widget'];
$settings = inline_entity_form_settings($field, $instance);
$entity_info = entity_get_info($settings['entity_type']);
$controller = inline_entity_form_get_controller($instance);
// The current entity type is not supported, execution can't continue.
if (!$controller) {
return array();
}
// Get the entity type labels for the UI strings.
$labels = $controller
->labels();
// Build a parents array for this element's values in the form.
$parents = array_merge($element['#field_parents'], array(
$element['#field_name'],
$element['#language'],
));
// Get the langcode of the parent entity.
$parent_langcode = entity_language($element['#entity_type'], $element['#entity']);
// Assign a unique identifier to each IEF widget.
// Since $parents can get quite long, sha1() ensures that every id has
// a consistent and relatively short length while maintaining uniqueness.
$ief_id = sha1(implode('-', $parents));
// Determine the wrapper ID for the entire element.
$wrapper = 'inline-entity-form-' . $ief_id;
$element = array(
'#type' => 'fieldset',
'#tree' => TRUE,
'#description' => filter_xss_admin($instance['description']),
'#prefix' => '<div id="' . $wrapper . '">',
'#suffix' => '</div>',
'#attached' => array(
'css' => array(),
),
'#ief_id' => $ief_id,
'#ief_root' => TRUE,
) + $element;
if (module_exists('file')) {
// file.js triggers uploads when the main Submit button is clicked.
$element['#attached']['js'] = array(
drupal_get_path('module', 'file') . '/file.js',
drupal_get_path('module', 'inline_entity_form') . '/inline_entity_form.js',
);
}
$base_css = array(
'base' => drupal_get_path('module', 'inline_entity_form') . '/theme/inline_entity_form.css',
'seven' => drupal_get_path('module', 'inline_entity_form') . '/theme/inline_entity_form.seven.css',
);
// Add the base module CSS.
_inline_entity_form_attach_css($base_css, $element['#attached']['css']);
// Add entity type specific CSS.
_inline_entity_form_attach_css($controller
->css(), $element['#attached']['css']);
// Initialize the IEF array in form state.
if (empty($form_state['inline_entity_form'][$ief_id])) {
$form_state['inline_entity_form'][$ief_id] = array(
'form' => NULL,
'settings' => $settings,
'instance' => $instance,
);
// Load the entities from the $items array and store them in the form
// state for further manipulation.
$form_state['inline_entity_form'][$ief_id]['entities'] = array();
$entity_ids = array();
foreach ($items as $item) {
$entity_ids[] = $item[$settings['column']];
}
$delta = 0;
foreach (entity_load($settings['entity_type'], $entity_ids) as $entity) {
$form_state['inline_entity_form'][$ief_id]['entities'][$delta] = array(
'entity' => $entity,
'weight' => $delta,
'form' => NULL,
'needs_save' => FALSE,
);
$delta++;
}
}
// Prepare cardinality information.
$cardinality = $field['cardinality'];
$entity_count = count($form_state['inline_entity_form'][$ief_id]['entities']);
$cardinality_reached = $cardinality > 0 && $entity_count == $cardinality;
// Build the appropriate widget.
// The "Single value" widget assumes it is operating on a required single
// value reference field with 1 allowed bundle.
if ($widget['type'] == 'inline_entity_form_single') {
// Intentionally not using $settings['create_bundles'] here because this
// widget doesn't care about permissions because of its use case.
$bundle = reset($settings['bundles']);
// Uh oh, the parent entity type and bundle are the same as the inline
// entity type and bundle. We have recursion. Abort.
if ($element['#entity_type'] == $settings['entity_type'] && $element['#bundle'] == $bundle) {
return array();
}
$form_state['inline_entity_form'][$ief_id]['form settings'] = array(
'bundle' => $bundle,
);
$element['form'] = array(
'#type' => 'container',
'#op' => 'add',
// Used by Field API and controller methods to find the relevant
// values in $form_state.
'#parents' => array_merge($parents, array(
'form',
)),
// Pass the current entity type.
'#entity_type' => $settings['entity_type'],
// Pass the langcode of the parent entity,
'#parent_language' => $parent_langcode,
// Identifies the IEF widget to which the form belongs.
'#ief_id' => $ief_id,
);
if (!empty($form_state['inline_entity_form'][$ief_id]['entities'])) {
$element['form']['#op'] = 'edit';
$element['form']['#entity'] = $form_state['inline_entity_form'][$ief_id]['entities'][0]['entity'];
$element['form']['#ief_row_delta'] = 0;
}
$element['form'] = inline_entity_form_entity_form($controller, $element['form'], $form_state);
// Hide all actions, the widget form behaves like a part of the main form.
$element['form']['actions']['#access'] = FALSE;
}
else {
// Build the "Multiple value" widget.
$element['#element_validate'] = array(
'inline_entity_form_update_row_weights',
);
// Add the required element marker & validation.
if ($element['#required']) {
$element['#title'] .= ' ' . theme('form_required_marker', array(
'element' => $element,
));
$element['#element_validate'][] = 'inline_entity_form_required_field';
}
$element['entities'] = array(
'#tree' => TRUE,
'#theme' => 'inline_entity_form_entity_table',
'#entity_type' => $settings['entity_type'],
'#cardinality' => (int) $cardinality,
);
// Get the fields that should be displayed in the table.
$fields = $controller
->tableFields($settings['bundles']);
$context = array(
'parent_entity_type' => $instance['entity_type'],
'parent_bundle' => $instance['bundle'],
'field_name' => $instance['field_name'],
'entity_type' => $settings['entity_type'],
'allowed_bundles' => $settings['bundles'],
);
drupal_alter('inline_entity_form_table_fields', $fields, $context);
$element['entities']['#table_fields'] = $fields;
$weight_delta = max(ceil(count($form_state['inline_entity_form'][$ief_id]['entities']) * 1.2), 50);
foreach ($form_state['inline_entity_form'][$ief_id]['entities'] as $key => $value) {
// Data used by theme_inline_entity_form_entity_table().
$element['entities'][$key]['#entity'] = $entity = $value['entity'];
$element['entities'][$key]['#needs_save'] = $value['needs_save'];
// Handle row weights.
$element['entities'][$key]['#weight'] = $value['weight'];
// First check to see if this entity should be displayed as a form.
if (!empty($value['form'])) {
$element['entities'][$key]['delta'] = array(
'#type' => 'value',
'#value' => $value['weight'],
);
$element['entities'][$key]['form'] = array(
'#type' => 'container',
'#attributes' => array(
'class' => array(
'ief-form',
'ief-form-row',
),
),
'#op' => $value['form'],
// Used by Field API and controller methods to find the relevant
// values in $form_state.
'#parents' => array_merge($parents, array(
'entities',
$key,
'form',
)),
// Store the entity on the form, later modified in the controller.
'#entity' => $entity,
'#entity_type' => $settings['entity_type'],
// Pass the langcode of the parent entity,
'#parent_language' => $parent_langcode,
// Identifies the IEF widget to which the form belongs.
'#ief_id' => $ief_id,
// Identifies the table row to which the form belongs.
'#ief_row_delta' => $key,
);
// Prepare data for the form callbacks.
$form =& $element['entities'][$key]['form'];
// Add the appropriate form.
if ($value['form'] == 'edit') {
$form += inline_entity_form_entity_form($controller, $form, $form_state);
}
elseif ($value['form'] == 'remove') {
$form += inline_entity_form_remove_form($controller, $form, $form_state);
}
}
else {
$row =& $element['entities'][$key];
$row['delta'] = array(
'#type' => 'weight',
'#delta' => $weight_delta,
'#default_value' => $value['weight'],
'#attributes' => array(
'class' => array(
'ief-entity-delta',
),
),
);
// Add an actions container with edit and delete buttons for the entity.
$row['actions'] = array(
'#type' => 'container',
'#attributes' => array(
'class' => array(
'ief-entity-operations',
),
),
);
// Make sure entity_access is not checked for unsaved entities.
list($entity_id) = entity_extract_ids($controller
->entityType(), $entity);
if (empty($entity_id) || entity_access('update', $controller
->entityType(), $entity)) {
$row['actions']['ief_entity_edit'] = array(
'#type' => 'submit',
'#value' => t('Edit'),
'#name' => 'ief-' . $ief_id . '-entity-edit-' . $key,
'#limit_validation_errors' => array(),
'#ajax' => array(
'callback' => 'inline_entity_form_get_element',
'wrapper' => $wrapper,
),
'#submit' => array(
'inline_entity_form_open_row_form',
),
'#ief_row_delta' => $key,
'#ief_row_form' => 'edit',
);
}
// Add the clone button, if allowed.
// The clone form follows the same semantics as the create form, so
// it's opened below the table.
if ($controller
->getSetting('allow_clone') && !$cardinality_reached && entity_access('create', $controller
->entityType(), $entity)) {
$row['actions']['ief_entity_clone'] = array(
'#type' => 'submit',
'#value' => t('Clone'),
'#name' => 'ief-' . $ief_id . '-entity-clone-' . $key,
'#limit_validation_errors' => array(
array_merge($parents, array(
'actions',
)),
),
'#ajax' => array(
'callback' => 'inline_entity_form_get_element',
'wrapper' => $wrapper,
),
'#submit' => array(
'inline_entity_form_open_form',
),
'#ief_row_delta' => $key,
'#ief_form' => 'clone',
);
}
// If 'allow_existing' is on, the default removal operation is unlink
// and the access check for deleting happens inside the controller
// removeForm() method.
if (empty($entity_id) || $controller
->getSetting('allow_existing') || entity_access('delete', $controller
->entityType(), $entity)) {
$row['actions']['ief_entity_remove'] = array(
'#type' => 'submit',
'#value' => t('Remove'),
'#name' => 'ief-' . $ief_id . '-entity-remove-' . $key,
'#limit_validation_errors' => array(),
'#ajax' => array(
'callback' => 'inline_entity_form_get_element',
'wrapper' => $wrapper,
),
'#submit' => array(
'inline_entity_form_open_row_form',
),
'#ief_row_delta' => $key,
'#ief_row_form' => 'remove',
);
}
}
}
if ($cardinality > 1) {
// Add a visual cue of cardinality count.
$message = t('You have added @entities_count out of @cardinality_count allowed @label.', array(
'@entities_count' => $entity_count,
'@cardinality_count' => $cardinality,
'@label' => $labels['plural'],
));
$element['cardinality_count'] = array(
'#markup' => '<div class="ief-cardinality-count">' . $message . '</div>',
);
}
// Do not return the rest of the form if cardinality count has been reached.
if ($cardinality_reached) {
return $element;
}
$hide_cancel = FALSE;
// If the field is required and empty try to open one of the forms.
if (empty($form_state['inline_entity_form'][$ief_id]['entities']) && $instance['required']) {
if ($controller
->getSetting('allow_existing') && !$controller
->getSetting('allow_new')) {
$form_state['inline_entity_form'][$ief_id]['form'] = 'ief_add_existing';
$hide_cancel = TRUE;
}
elseif (count($settings['create_bundles']) == 1 && $controller
->getSetting('allow_new') && !$controller
->getSetting('allow_existing')) {
$bundle = reset($settings['create_bundles']);
// The parent entity type and bundle must not be the same as the inline
// entity type and bundle, to prevent recursion.
if ($element['#entity_type'] != $settings['entity_type'] || $element['#bundle'] != $bundle) {
$form_state['inline_entity_form'][$ief_id]['form'] = 'add';
$form_state['inline_entity_form'][$ief_id]['form settings'] = array(
'bundle' => $bundle,
);
$hide_cancel = TRUE;
}
}
}
// If no form is open, show buttons that open one.
if (empty($form_state['inline_entity_form'][$ief_id]['form'])) {
$element['actions'] = array(
'#attributes' => array(
'class' => array(
'container-inline',
),
),
'#type' => 'container',
'#weight' => 100,
);
// The user is allowed to create an entity of at least one bundle.
if (count($settings['create_bundles'])) {
// Let the user select the bundle, if multiple are available.
if (count($settings['create_bundles']) > 1) {
$bundles = array();
foreach ($entity_info['bundles'] as $bundle_name => $bundle_info) {
if (in_array($bundle_name, $settings['create_bundles'])) {
$bundles[$bundle_name] = $bundle_info['label'];
}
}
asort($bundles);
$element['actions']['bundle'] = array(
'#type' => 'select',
'#options' => $bundles,
);
}
else {
$element['actions']['bundle'] = array(
'#type' => 'value',
'#value' => reset($settings['create_bundles']),
);
}
if ($controller
->getSetting('allow_new')) {
$element['actions']['ief_add'] = array(
'#type' => 'submit',
'#value' => t('Add new @type_singular', array(
'@type_singular' => $labels['singular'],
)),
'#name' => 'ief-' . $ief_id . '-add',
'#limit_validation_errors' => array(
array_merge($parents, array(
'actions',
)),
),
'#ajax' => array(
'callback' => 'inline_entity_form_get_element',
'wrapper' => $wrapper,
),
'#submit' => array(
'inline_entity_form_open_form',
),
'#ief_form' => 'add',
);
}
}
if ($controller
->getSetting('allow_existing')) {
$element['actions']['ief_add_existing'] = array(
'#type' => 'submit',
'#value' => t('Add existing @type_singular', array(
'@type_singular' => $labels['singular'],
)),
'#name' => 'ief-' . $ief_id . '-add-existing',
'#limit_validation_errors' => array(
array_merge($parents, array(
'actions',
)),
),
'#ajax' => array(
'callback' => 'inline_entity_form_get_element',
'wrapper' => $wrapper,
),
'#submit' => array(
'inline_entity_form_open_form',
),
'#ief_form' => 'ief_add_existing',
);
}
}
else {
// There's a form open, show it.
$element['form'] = array(
'#type' => 'fieldset',
'#attributes' => array(
'class' => array(
'ief-form',
'ief-form-bottom',
),
),
// Identifies the IEF widget to which the form belongs.
'#ief_id' => $ief_id,
// Used by Field API and controller methods to find the relevant
// values in $form_state.
'#parents' => array_merge($parents, array(
'form',
)),
// Pass the current entity type.
'#entity_type' => $settings['entity_type'],
// Pass the langcode of the parent entity,
'#parent_language' => $parent_langcode,
);
if ($form_state['inline_entity_form'][$ief_id]['form'] == 'add') {
$element['form']['#op'] = 'add';
$element['form'] += inline_entity_form_entity_form($controller, $element['form'], $form_state);
}
elseif ($form_state['inline_entity_form'][$ief_id]['form'] == 'ief_add_existing') {
$element['form'] += inline_entity_form_reference_form($controller, $element['form'], $form_state);
}
elseif ($form_state['inline_entity_form'][$ief_id]['form'] == 'clone') {
$element['form']['#op'] = 'clone';
$element['form'] += inline_entity_form_entity_form($controller, $element['form'], $form_state);
}
// Pre-opened forms can't be closed in order to force the user to
// add / reference an entity.
if ($hide_cancel) {
if (isset($element['form']['actions']['ief_add_cancel'])) {
$element['form']['actions']['ief_add_cancel']['#access'] = FALSE;
}
elseif (isset($element['form']['actions']['ief_reference_cancel'])) {
$element['form']['actions']['ief_reference_cancel']['#access'] = FALSE;
}
}
// No entities have been added. Remove the outer fieldset to reduce
// visual noise caused by having two titles.
if (empty($form_state['inline_entity_form'][$ief_id]['entities'])) {
$element['#type'] = 'container';
}
}
}
return $element;
}