diff --git a/includes/commerce_line_item.inline_entity_form.inc b/includes/commerce_line_item.inline_entity_form.inc index 642affb..c07cbc4 100644 --- a/includes/commerce_line_item.inline_entity_form.inc +++ b/includes/commerce_line_item.inline_entity_form.inc @@ -98,7 +98,8 @@ class CommerceLineItemInlineEntityFormController extends EntityInlineEntityFormC '#weight' => $extra_fields['label']['weight'], '#fieldset' => 'line_item_details', ); - field_attach_form('commerce_line_item', $line_item, $entity_form, $form_state); + + $entity_form = parent::entityForm($entity_form, $form_state); // Tweaks specific to product line items. if (in_array($line_item->type, $this->productLineItemTypes())) { diff --git a/includes/commerce_product.inline_entity_form.inc b/includes/commerce_product.inline_entity_form.inc index 07b5724..49d56ed 100644 --- a/includes/commerce_product.inline_entity_form.inc +++ b/includes/commerce_product.inline_entity_form.inc @@ -194,9 +194,7 @@ class CommerceProductInlineEntityFormController extends EntityInlineEntityFormCo '#weight' => $extra_fields['status']['weight'], ); - // Attach fields. - $langcode = entity_language('commerce_product', $product); - field_attach_form('commerce_product', $product, $entity_form, $form_state, $langcode); + $entity_form = parent::entityForm($entity_form, $form_state); // Hide or disable the SKU field if it is auto-generated by Commerce AutoSKU. if (module_exists('commerce_autosku') && $settings = commerce_autosku_get_settings($product)) { @@ -247,6 +245,10 @@ class CommerceProductInlineEntityFormController extends EntityInlineEntityFormCo } } + // Ensure our fieldsets are not hidden by the field translation handler. + $entity_form['product_image']['#access'] = TRUE; + $entity_form['product_details']['#access'] = TRUE; + return $entity_form; } @@ -349,7 +351,10 @@ class CommerceProductInlineEntityFormController extends EntityInlineEntityFormCo // Generate the product title. Take the parent entity title as the base. if ($this->settings['autogenerate_title']) { - $entity->title = entity_label($context['parent_entity_type'], $context['parent_entity']); + // Update the entity label only with a valid value. + if ($label = entity_label($context['parent_entity_type'], $context['parent_entity'])) { + $entity->title = $label; + } $attributes = $this->attributes($entity->type); if (!empty($attributes)) { $wrapper = entity_metadata_wrapper('commerce_product', $entity); @@ -365,6 +370,18 @@ class CommerceProductInlineEntityFormController extends EntityInlineEntityFormCo $entity->title .= ' (' . implode(', ', $attribute_values) . ')'; } } + + // Update the autogenerated title field, otherwise when dealing with + // translations the source language would be used. + if (module_exists('title') && entity_label($this->entityType, $entity)) { + $legacy_field = 'title'; + list(, , $bundle) = entity_extract_ids($this->entityType, $entity); + if (title_field_replacement_enabled($this->entityType, $bundle, $legacy_field)) { + $info = title_field_replacement_info($this->entityType, $legacy_field); + $langcode = $info['field']['translatable'] ? entity_language($this->entityType, $entity) : LANGUAGE_NONE; + title_field_sync_set($this->entityType, $entity, $legacy_field, $info, $langcode); + } + } } entity_save('commerce_product', $entity); diff --git a/includes/entity.inline_entity_form.inc b/includes/entity.inline_entity_form.inc index 7b3891d..c9766eb 100644 --- a/includes/entity.inline_entity_form.inc +++ b/includes/entity.inline_entity_form.inc @@ -261,9 +261,83 @@ class EntityInlineEntityFormController { field_attach_form($this->entityType, $entity, $entity_form, $form_state, $langcode); } + // Process multilingual and shared form elements. + $this->entityFormSharedElements($entity_form); + return $entity_form; } + /** + * Marks shared form elements or hides them if the user has no access to them. + * + * @param $entity_form + * The entity form. + */ + protected function entityFormSharedElements(&$entity_form) { + if (($handler = module_invoke('entity_translation', 'get_handler', $this->entityType, $entity_form['#entity'])) && !$handler->isNewEntity()) { + $form_langcode = $handler->getFormLanguage(); + $langcode = !empty($entity_form['#parent_language']) ? $entity_form['#parent_language'] : $handler->getLanguage(); + $translations = $handler->getTranslations(); + $update_langcode = $form_langcode && ($form_langcode != $langcode); + $source = $handler->getSourceLanguage(); + $new_translation = !isset($translations->data[$form_langcode]); + + if (!isset($translations->data[$form_langcode]) || count($translations->data) > 1) { + $handler->entityFormSharedElements($entity_form); + } + + // If we are creating a new translation we need to retrieve form elements + // populated with the source language values. In this case source values + // have already been populated, so we need to preserve possible changes. + // There might be situations, e.g. ajax calls, where the form language + // has not been properly initialized before calling field_attach_form(). + // In this case we need to rebuild the form with the correct form language + // and replace the field elements with the correct ones. + // Borrowed some code from entity_translation_field_attach_form() + // that won't get run because $form_state['rebuild'] is TRUE for all IEF forms. + if ($update_langcode || ($source && !isset($translations->data[$form_langcode]) && isset($translations->data[$source]))) { + $entity_type = $entity_form['#entity_type']; + list($id, , $bundle) = entity_extract_ids($entity_type, $entity_form['#entity']); + foreach (field_info_instances($entity_type, $bundle) as $instance) { + + $field_name = $instance['field_name']; + $field = field_info_field($field_name); + + // If we are creating a new translation we have to change the form item + // language information from source to target language, this way the + // user can find the form items already populated with the source values + // while the field form element holds the correct language information. + if ($field['translatable']) { + $element = &$entity_form[$field_name]; + $element['#entity_type'] = $entity_type; + $element['#entity'] = $entity_form['#entity']; + $element['#entity_id'] = $id; + $element['#field_name'] = $field_name; + $element['#source'] = $update_langcode ? $form_langcode : $source; + $element['#previous'] = NULL; + $element['#form_parents'] = $entity_form['#parents']; + + // If we are updating the form language we need to make sure that the + // wrong language is unset and the right one is stored in the field + // element (see entity_translation_prepare_element()). + if ($update_langcode) { + $element['#previous'] = $element['#language']; + $element['#language'] = $form_langcode; + } + + // Swap default values during form processing to avoid recursion. We + // try to act before any other callback so that the correct values are + // already in place for them. + if (!isset($element['#process'])) { + $element['#process'] = array(); + } + array_unshift($element['#process'], 'entity_translation_prepare_element'); + } + } + } + } + } + /** * Validates the entity form. * @@ -297,7 +371,7 @@ class EntityInlineEntityFormController { $info = entity_get_info($this->entityType); list(, , $bundle) = entity_extract_ids($this->entityType, $entity_form['#entity']); $entity = $entity_form['#entity']; - $entity_values = drupal_array_get_nested_value($form_state['values'], $entity_form['#parents']); + $entity_values = &drupal_array_get_nested_value($form_state['values'], $entity_form['#parents']); // Copy top-level form values that are not for fields to entity properties, // without changing existing entity properties that are not being edited by @@ -307,12 +381,65 @@ class EntityInlineEntityFormController { $entity->$key = $value; } + // Update the entity language using the parent entity submitted value. + if (!empty($info['entity keys']['language'])) { + $parent_info = entity_get_info($entity_form['#parent_entity_type']); + if (isset($parent_info['entity keys']['language']) && isset($form_state['values'][$parent_info['entity keys']['language']])) { + $entity->{$info['entity keys']['language']} = $form_state['values'][$parent_info['entity keys']['language']]; + $handler = module_invoke('entity_translation', 'get_handler', $this->entityType, $entity); + $lang = $handler->getFormLanguage(); + if ($lang == 'und') { + if ($entity_form['#parent_language'] != 'und') { + $handler->setFormLanguage($entity_form['#parent_language']); + } + else { + $handler->setFormLanguage($form_state['values'][$parent_info['entity keys']['language']]); + } + } + } + } + if ($info['fieldable']) { + // Retrieve the current entity form language. + $langcode = entity_language($this->entityType, $entity); + + // Handle a possible language change: new language values are inserted, + // previous ones are deleted. + foreach (field_info_instances($this->entityType, $bundle) as $instance) { + $field_name = $instance['field_name']; + $field = field_info_field($field_name); + $previous_langcode = $entity_form[$field_name]['#language']; + if ($field['translatable'] && $previous_langcode != $langcode) { + $entity_values[$field_name][$langcode] = $entity_values[$field_name][$previous_langcode]; + $entity_values[$field_name][$previous_langcode] = array(); + } + } + field_attach_submit($this->entityType, $entity, $entity_form, $form_state); + + // Handle translation submission. + $this->entityTranslationFormSubmit($entity_form, $entity); } } /** + * Creates an entity translation if needed. + */ + protected function entityTranslationFormSubmit($entity_form, $entity) { + if (($handler = module_invoke('entity_translation', 'get_handler', $this->entityType, $entity)) && ($source = $handler->getSourceLanguage())) { + list($id, , ) = entity_extract_ids($this->entityType, $entity); + $translation = array( + 'entity_type' => $this->entityType, + 'entity_id' => $id, + 'language' => $handler->getFormLanguage(), + 'source' => $source, + 'status' => 1, + ); + $handler->setTranslation($translation); + } + } + + /** * Returns the remove form to be shown through the IEF widget. * * @param $remove_form diff --git a/includes/node.inline_entity_form.inc b/includes/node.inline_entity_form.inc index ceccb3a..fc4f722 100644 --- a/includes/node.inline_entity_form.inc +++ b/includes/node.inline_entity_form.inc @@ -65,10 +65,7 @@ class NodeInlineEntityFormController extends EntityInlineEntityFormController { '#weight' => 99, ); - $langcode = entity_language('node', $node); - field_attach_form('node', $node, $entity_form, $form_state, $langcode); - - return $entity_form; + return parent::entityForm($entity_form, $form_state); } /** diff --git a/includes/taxonomy_term.inline_entity_form.inc b/includes/taxonomy_term.inline_entity_form.inc index b6ef7ff..af50c8d 100644 --- a/includes/taxonomy_term.inline_entity_form.inc +++ b/includes/taxonomy_term.inline_entity_form.inc @@ -85,10 +85,7 @@ class TaxonomyTermInlineEntityFormController extends EntityInlineEntityFormContr '#weight' => $extra_fields['description']['weight'], ); - $langcode = entity_language('taxonomy_term', $term); - field_attach_form('taxonomy_term', $term, $entity_form, $form_state, $langcode); - - return $entity_form; + return parent::entityForm($entity_form, $form_state); } diff --git a/inline_entity_form.module b/inline_entity_form.module index 0e39c5d..798eb16 100644 --- a/inline_entity_form.module +++ b/inline_entity_form.module @@ -191,6 +191,46 @@ function inline_entity_form_entity_delete($entity, $type) { } /** + * Implements hook_entity_translation_delete(). + * + * Deletes a translation of the referenced entity. + */ +function inline_entity_form_entity_translation_delete($entity_type, $entity, $langcode) { + list(,, $bundle) = entity_extract_ids($entity_type, $entity); + foreach (field_info_instances($entity_type, $bundle) as $field_name => $instance) { + if (strpos($instance['widget']['type'], 'inline_entity_form') === 0) { + $controller = inline_entity_form_get_controller($instance); + + // The controller specified that referenced entities should be deleted. + if ($controller && $controller->getSetting('delete_references')) { + $items = field_get_items($entity_type, $entity, $field_name, $langcode); + if ($items) { + $field = field_info_field($field_name); + $ief_settings = inline_entity_form_settings($field, $instance); + + $ids = array(); + foreach ($items as $item) { + $ids[] = $item[$ief_settings['column']]; + } + + $ref_entity_type = $ief_settings['entity_type']; + $context = array( + 'parent_entity_type' => $entity_type, + 'parent_entity' => $entity, + ); + + foreach (entity_load($ref_entity_type, $ids) as $id => $entity) { + $handler = entity_translation_get_handler($ref_entity_type, $entity); + $handler->removeTranslation($langcode); + $controller->save($entity, $context); + } + } + } + } + } +} + +/** * Attaches theme specific CSS files. * * @param $theme_css @@ -504,6 +544,8 @@ function inline_entity_form_field_widget_form(&$form, &$form_state, $field, $ins '#parents' => array_merge($parents, array('form')), // Pass the current entity type. '#entity_type' => $settings['entity_type'], + '#parent_entity' => $element['#entity'], + '#parent_entity_type' => $element['#entity_type'], // Pass the langcode of the parent entity, '#parent_language' => $parent_langcode, // Identifies the IEF widget to which the form belongs. @@ -571,6 +613,8 @@ function inline_entity_form_field_widget_form(&$form, &$form_state, $field, $ins '#entity' => $entity, '#entity_type' => $settings['entity_type'], // Pass the langcode of the parent entity, + '#parent_entity' => $element['#entity'], + '#parent_entity_type' => $element['#entity_type'], '#parent_language' => $parent_langcode, // Identifies the IEF widget to which the form belongs. '#ief_id' => $ief_id, @@ -748,6 +792,8 @@ function inline_entity_form_field_widget_form(&$form, &$form_state, $field, $ins '#parents' => array_merge($parents, array('form')), // Pass the current entity type. '#entity_type' => $settings['entity_type'], + '#parent_entity' => $element['#entity'], + '#parent_entity_type' => $element['#entity_type'], // Pass the langcode of the parent entity, '#parent_language' => $parent_langcode, ); @@ -843,18 +889,28 @@ function inline_entity_form_entity_form($controller, $entity_form, &$form_state) $labels = $controller->labels(); // Build a deta suffix that's appended to button #name keys for uniqueness. $delta = $entity_form['#ief_id']; + if ($entity_form['#op'] == 'edit') { $delta .= '-' . $entity_form['#ief_row_delta']; $save_label = t('Update @type_singular', array('@type_singular' => $labels['singular'])); } elseif ($entity_form['#op'] == 'add') { // Create a new entity that will be passed to the form. - $form_settings = $form_state['inline_entity_form'][$entity_form['#ief_id']]['form settings']; - $entity_form['#entity'] = inline_entity_form_create_entity($entity_form['#entity_type'], $form_settings['bundle'], $entity_form['#parent_language']); + $bundle = reset($form_state['inline_entity_form'][$entity_form['#ief_id']]['settings']['bundles']); + $entity_form['#entity'] = inline_entity_form_create_entity($entity_form['#entity_type'], $bundle, $entity_form['#parent_language']); $entity_form['#title'] = t('Add new @type_singular', array('@type_singular' => $labels['singular'])); $save_label = t('Create @type_singular', array('@type_singular' => $labels['singular'])); } + // Register a child entity translation handler to properly deal with the entity form language. + list(, , $bundle) = entity_extract_ids($entity_form['#entity_type'], $entity_form['#entity']); + if (module_invoke('entity_translation', 'enabled', $entity_form['#entity_type'], $bundle)) { + inline_entity_form_add_child_translation_handler($entity_form); + // Ensure this is executed even with cached forms. This is mainly useful + // when dealing with AJAX calls. + $entity_form['#process'][] = 'inline_entity_form_add_child_translation_handler'; + } + // Retrieve the form provided by the controller. $entity_form = $controller->entityForm($entity_form, $form_state); @@ -928,6 +984,22 @@ function inline_entity_form_entity_form($controller, $entity_form, &$form_state) } /** + * Registers a child entity translation handler for the given element. + */ +function inline_entity_form_add_child_translation_handler($element) { + $handler = entity_translation_get_handler($element['#parent_entity_type'], $element['#parent_entity']); + + $handler->setFormLanguage($element['#parent_language']); + $source = $handler->getSourceLanguage(); + if (!($source) && $element['#parent_entity']->translations->original != $element['#parent_language']) { + $handler->setSourceLanguage($element['#parent_entity']->translations->original); + } + + $handler->addChild($element['#entity_type'], $element['#entity']); + return $element; +} + +/** * Validates an entity form. * * @param $entity_form