diff --git a/entity_translation.admin.inc b/entity_translation.admin.inc index 8efadfd..86880cc 100644 --- a/entity_translation.admin.inc +++ b/entity_translation.admin.inc @@ -384,6 +384,7 @@ function theme_entity_translation_overview_outdated($variables){ */ function entity_translation_delete_confirm($form, $form_state, $entity_type, $entity, $langcode) { $handler = entity_translation_get_handler($entity_type, $entity); + $handler->setFormLanguage($langcode); $languages = language_list(); $form = array( diff --git a/entity_translation.info b/entity_translation.info index 74ef491..e59a3ce 100644 --- a/entity_translation.info +++ b/entity_translation.info @@ -5,6 +5,7 @@ core = 7.x configure = admin/config/regional/entity_translation dependencies[] = locale (>7.14) +files[] = includes/translation.handler_factory.inc files[] = includes/translation.handler.inc files[] = includes/translation.handler.comment.inc files[] = includes/translation.handler.node.inc diff --git a/entity_translation.install b/entity_translation.install index f93aa30..8b39013 100644 --- a/entity_translation.install +++ b/entity_translation.install @@ -254,3 +254,10 @@ function entity_translation_update_7003() { function entity_translation_update_7004() { entity_info_cache_clear(); } + +/** + * Rebuild the class registry to pick up the translation handler factory class. + */ +function entity_translation_update_7005() { + registry_rebuild(); +} diff --git a/entity_translation.module b/entity_translation.module index d9d8400..33f04f3 100644 --- a/entity_translation.module +++ b/entity_translation.module @@ -1128,8 +1128,10 @@ function entity_translation_field_attach_delete($entity_type, $entity) { * Implementation of hook_field_attach_form(). */ function entity_translation_field_attach_form($entity_type, $entity, &$form, &$form_state, $langcode) { - // Skip recursing into the source form. - if (empty($form['#entity_translation_source_form']) && ($handler = entity_translation_entity_form_get_handler($form, $form_state))) { + // Avoid recursing into the source form. + list($id, , $bundle) = entity_extract_ids($entity_type, $entity); + if (empty($form['#entity_translation_source_form']) && entity_translation_enabled($entity_type, $bundle)) { + $handler = entity_translation_get_handler($entity_type, $entity); $langcode = !empty($langcode) ? $langcode : $handler->getLanguage(); $form_langcode = $handler->getFormLanguage(); $translations = $handler->getTranslations(); @@ -1146,8 +1148,6 @@ function entity_translation_field_attach_form($entity_type, $entity, &$form, &$f // with the correct form language and replace the field elements with the // correct ones. if ($update_langcode || ($source && !isset($translations->data[$form_langcode]) && isset($translations->data[$source]) && empty($form_state['rebuild']))) { - list(, , $bundle) = entity_extract_ids($entity_type, $entity); - foreach (field_info_instances($entity_type, $bundle) as $instance) { $field_name = $instance['field_name']; $field = field_info_field($field_name); @@ -1157,25 +1157,30 @@ function entity_translation_field_attach_form($entity_type, $entity, &$form, &$f // 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']) { - $form[$field_name]['#field_name'] = $field_name; - $form[$field_name]['#source'] = $update_langcode ? $form_langcode : $source; - $form[$field_name]['#previous'] = NULL; + $element = &$form[$field_name]; + $element['#entity_type'] = $entity_type; + $element['#entity'] = $entity; + $element['#entity_id'] = $id; + $element['#field_name'] = $field_name; + $element['#source'] = $update_langcode ? $form_langcode : $source; + $element['#previous'] = NULL; + $element['#form_parents'] = $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) { - $form[$field_name]['#previous'] = $form[$field_name]['#language']; - $form[$field_name]['#language'] = $form_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($form[$field_name]['#process'])) { - $form[$field_name]['#process'] = array(); + if (!isset($element['#process'])) { + $element['#process'] = array(); } - array_unshift($form[$field_name]['#process'], 'entity_translation_prepare_element'); + array_unshift($element['#process'], 'entity_translation_prepare_element'); } } } @@ -1209,18 +1214,31 @@ function entity_translation_field_attach_form($entity_type, $entity, &$form, &$f * Form element process callback. */ function entity_translation_prepare_element($element, &$form_state) { - $source_form = &drupal_static(__FUNCTION__, array()); + static $drupal_static_fast; + if (!isset($drupal_static_fast)) { + $drupal_static_fast['source_forms'] = &drupal_static(__FUNCTION__, array()); + } + + $source_forms = &$drupal_static_fast['source_forms']; $form = $form_state['complete form']; $build_id = $form['#build_id']; $source = $element['#source']; - - if (!isset($source_form[$build_id][$source])) { - $source_form[$build_id][$source] = array('#entity_translation_source_form' => TRUE); + $entity_type = $element['#entity_type']; + $id = $element['#entity_id']; + + // Key the source form cache per entity type and entity id to allow for + // multiple entities on the same entity form. + if (!isset($source_forms[$build_id][$source][$entity_type][$id])) { + $source_form = array( + '#entity_translation_source_form' => TRUE, + '#parents' => $element['#form_parents'], + ); $source_form_state = $form_state; - $info = entity_translation_edit_form_info($form, $form_state); - field_attach_form($info['entity type'], $info['entity'], $source_form[$build_id][$source], $source_form_state, $source); + field_attach_form($entity_type, $element['#entity'], $source_form, $source_form_state, $source); + $source_forms[$build_id][$source][$entity_type][$id] = &$source_form; } + $source_form = &$source_forms[$build_id][$source][$entity_type][$id]; $langcode = $element['#language']; $field_name = $element['#field_name']; @@ -1228,8 +1246,8 @@ function entity_translation_prepare_element($element, &$form_state) { // 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 (isset($source_form[$build_id][$source][$field_name][$source])) { - $element[$langcode] = $source_form[$build_id][$source][$field_name][$source]; + if (isset($source_form[$field_name][$source])) { + $element[$langcode] = $source_form[$field_name][$source]; entity_translation_form_element_language_replace($element, $source, $langcode); unset($element[$element['#previous']]); } @@ -1249,7 +1267,7 @@ function entity_translation_form_element_language_replace(&$element, $source, $l // Replace specific occurrences of the source language with the target // language. foreach (element_properties($element) as $key) { - if ($key === '#language') { + if ($key === '#language' && $element[$key] != LANGUAGE_NONE) { $element[$key] = $langcode; } elseif ($key === '#parents' || $key === '#field_parents') { @@ -1366,30 +1384,32 @@ function _entity_translation_element_title_append(&$element, $suffix) { * Implements hook_form_alter(). */ function entity_translation_form_alter(&$form, &$form_state) { - if ($handler = entity_translation_entity_form_get_handler($form, $form_state)) { - if (!$handler->isNewEntity()) { - $handler->entityForm($form, $form_state); - $translations = $handler->getTranslations(); - $form_langcode = $handler->getFormLanguage(); - if (!isset($translations->data[$form_langcode]) || count($translations->data) > 1) { - // Hide shared form elements if the user is not allowed to edit them. - $handler->entityFormSharedElements($form); + if ($info = entity_translation_edit_form_info($form, $form_state)) { + $handler = entity_translation_get_handler($info['entity type'], $info['entity']); + if (entity_translation_enabled($info['entity type'], $info['entity'])) { + if (!$handler->isNewEntity()) { + $handler->entityForm($form, $form_state); + $translations = $handler->getTranslations(); + $form_langcode = $handler->getFormLanguage(); + if (!isset($translations->data[$form_langcode]) || count($translations->data) > 1) { + // Hide shared form elements if the user is not allowed to edit them. + $handler->entityFormSharedElements($form); + } } + else { + $handler->entityFormLanguageWidget($form, $form_state); + } + // We need to process the posted form as early as possible to update the + // form language value. + array_unshift($form['#validate'], 'entity_translation_entity_form_validate'); } + // We might have an entity form for an entity or a bundle not enabled for + // translation. In this case we might need to deal with entity and field + // languages anyway, since fields may be shared among different bundles and + // entity types. else { $handler->entityFormLanguageWidget($form, $form_state); } - // We need to process the posted form as early as possible to update the - // form language value. - array_unshift($form['#validate'], 'entity_translation_entity_form_validate'); - } - // We might have an entity form for an entity or a bundle not enabled for - // translation. In this case we might need to deal with entity and field - // languages anyway, since fields may be shared among different bundles and - // entity types. - elseif ($info = entity_translation_edit_form_info($form, $form_state)) { - $handler = entity_translation_get_handler($info['entity type'], $info['entity']); - $handler->entityFormLanguageWidget($form, $form_state); } } @@ -1435,16 +1455,22 @@ function entity_translation_entity_form_validate($form, &$form_state) { } /** - * Submit handler for the entity language widget. + * Validation handler for the entity language widget. */ -function entity_translation_language_widget_submit($form, &$form_state) { +function entity_translation_entity_form_language_update($form, &$form_state) { $handler = entity_translation_entity_form_get_handler($form, $form_state); - // On non-translatable entities, we need to handle just the entity and field - // language. - if (empty($handler) && ($info = entity_translation_edit_form_info($form, $form_state))) { - $handler = entity_translation_get_handler($info['entity type'], $info['entity']); + // Ensure the handler form language match the actual one. This is mainly + // needed when responding to an AJAX request where the languages cannot be set + // from the usual page callback. + if (!empty($form_state['entity_translation']['form_langcode'])) { + $handler->setFormLanguage($form_state['entity_translation']['form_langcode']); + } + // When responding to an AJAX request we should ignore any change in the + // language widget as it may alter the field language expected by the AJAX + // callback. + if (empty($form_state['triggering_element']['#ajax'])) { + $handler->entityFormLanguageWidgetSubmit($form, $form_state); } - $handler->entityFormLanguageWidgetSubmit($form, $form_state); } /** @@ -1466,7 +1492,7 @@ function entity_translation_entity_form_submit($form, &$form_state) { * Mark translations as outdated if the submitted value is true. */ function entity_translation_field_attach_submit($entity_type, $entity, $form, &$form_state) { - if ($handler = entity_translation_entity_form_get_handler($form, $form_state)) { + if (($handler = entity_translation_entity_form_get_handler($form, $form_state)) && entity_translation_enabled($entity_type, $entity)) { // Update the wrapped entity with the submitted values. $handler->setEntity($entity); $handler->entityFormSubmit($form, $form_state); @@ -1711,32 +1737,7 @@ function entity_translation_settings($entity_type, $bundle) { * A valid language code. */ function entity_translation_language($entity_type, $entity) { - // If a form has been post, we need to check its state to verify if any form - // translation handler is stored there. This is mainly needed when responding - // to an AJAX request where the form language cannot be set from the page - // callback. - $handler = entity_translation_current_form_get_handler(); - - // Make sure we always have a translation handler instance available. - if (empty($handler)) { - $handler = entity_translation_get_handler($entity_type, $entity); - } - // If a translation handler associated to the current form is found, we need - // to update the wrapped entity. This way submitted values will be picked up. - // Other entities may be created or saved while submitting the current one, - // hence we need to check we are dealing with it. - elseif ($handler->isWrappedEntity($entity_type, $entity)) { - $langcode = $handler->getLanguage(); - $handler->setEntity($entity); - $submitted_langcode = $handler->getLanguage(); - // If the entity language has changed we are editing the original values. In - // this case we need to update the current form language with the submitted - // one. - if ($submitted_langcode != $langcode) { - $handler->setFormLanguage($submitted_langcode); - } - } - + $handler = entity_translation_get_handler($entity_type, $entity); $langcode = $handler->getFormLanguage(); return !empty($langcode) ? $langcode : $handler->getLanguage(); } @@ -1749,64 +1750,20 @@ function entity_translation_language($entity_type, $entity) { * @param $entity * (optional) The entity to be translated. A bundle name may be passed to * instantiate an empty entity. - * @param $update - * (optional) Instances are statically cached: if this is TRUE the wrapped - * entity will be replaced by the passed one. * * @return EntityTranslationHandlerInterface * A class implementing EntityTranslationHandlerInterface. */ -function entity_translation_get_handler($entity_type = NULL, $entity = NULL, $update = FALSE) { - static $drupal_static_fast; - if (!isset($drupal_static_fast['handlers'])) { - $drupal_static_fast['handlers'] = &drupal_static(__FUNCTION__, array()); - } - $handlers = &$drupal_static_fast['handlers']; - - // Workaround the lack of a context object. - if (empty($entity)) { - if (isset($handlers[$entity_type]['#current'])) { - return $handlers[$entity_type]['#current']; - } - elseif (empty($entity_type) && isset($handlers['#current']['#current'])) { - return $handlers['#current']['#current']; - } - else { - return NULL; - } - } - elseif (is_numeric($entity)) { - $entity = reset(entity_load($entity_type, array($entity))); - } - elseif (is_string($entity)) { - $entity = entity_create_stub_entity($entity_type, array(NULL, NULL, $entity)); +function entity_translation_get_handler($entity_type = NULL, $entity = NULL) { + if (class_exists('EntityTranslationHandlerFactory')) { + $factory = EntityTranslationHandlerFactory::getInstance(); + return empty($entity) ? $factory->getLastHandler($entity_type) : $factory->getHandler($entity_type, $entity); } - - list($entity_id) = entity_extract_ids($entity_type, $entity); - - if (!isset($handlers[$entity_type][$entity_id])) { + // @todo BC layer. Remove before the first stable release. + elseif (!empty($entity_type) && is_object($entity)) { $entity_info = entity_get_info($entity_type); - $class = $entity_info['translation']['entity_translation']['class']; - // @todo remove fourth parameter once 3rd-party translation handlers have - // been fixed and no longer require the deprecated entity_id parameter. - $handler = new $class($entity_type, $entity_info, $entity, NULL); - - // If the entity id is empty we cannot cache the translation handler - // instance. - if (empty($entity_id)) { - return $handler; - } - else { - $handlers[$entity_type][$entity_id] = $handler; - } - } - elseif ($update) { - $handlers[$entity_type][$entity_id]->setEntity($entity); + return new EntityTranslationDefaultHandler($entity_type, $entity_info, $entity); } - - $handlers[$entity_type]['#current'] = $handlers[$entity_type][$entity_id]; - $handlers['#current']['#current'] = $handlers[$entity_type][$entity_id]; - return $handlers[$entity_type][$entity_id]; } /** @@ -1820,24 +1777,11 @@ function entity_translation_get_handler($entity_type = NULL, $entity = NULL, $up * @return EntityTranslationHandlerInterface * A class implementing EntityTranslationHandlerInterface. */ -function entity_translation_entity_form_get_handler($form, &$form_state) { +function entity_translation_entity_form_get_handler($form, $form_state) { $handler = FALSE; - $entity_type = isset($form['#entity_type']) && is_string($form['#entity_type']) ? $form['#entity_type'] : FALSE; - - if ($entity_type) { - if (empty($form_state['storage']['entity_translation']['handler'][$entity_type])) { - if ($info = entity_translation_edit_form_info($form, $form_state)) { - if (entity_translation_enabled($info['entity type'], $info['entity'])) { - $handler = entity_translation_get_handler($info['entity type'], $info['entity']); - $form_state['storage']['entity_translation']['handler'][$info['entity type']] = $handler; - } - } - } - else { - $handler = $form_state['storage']['entity_translation']['handler'][$entity_type]; - } + if ($info = entity_translation_edit_form_info($form, $form_state)) { + $handler = entity_translation_get_handler($info['entity type'], $info['entity']); } - return $handler; } @@ -1846,14 +1790,18 @@ function entity_translation_entity_form_get_handler($form, &$form_state) { * * @return EntityTranslationHandlerInterface * A translation handler instance if available, FALSE oterwise. + * + * @deprecated This is no longer used and will be removed in the first stable + * release. */ function entity_translation_current_form_get_handler() { $handler = FALSE; if (!empty($_POST['form_build_id'])) { $form_state = form_state_defaults(); - $form = form_get_cache($_POST['form_build_id'], $form_state); - $handler = entity_translation_entity_form_get_handler($form, $form_state); + if ($form = form_get_cache($_POST['form_build_id'], $form_state)) { + $handler = entity_translation_entity_form_get_handler($form, $form_state); + } } return $handler; diff --git a/includes/translation.handler.inc b/includes/translation.handler.inc index 184626f..1425437 100644 --- a/includes/translation.handler.inc +++ b/includes/translation.handler.inc @@ -15,6 +15,21 @@ interface EntityTranslationHandlerInterface { /** + * Injects the translation handler factory. + */ + public function setFactory(EntityTranslationHandlerFactory $factory); + + /** + * Registers a child translation handler for the given entity. + */ + public function addChild($entity_type, $entity); + + /** + * Removes a previously registered child translation handler. + */ + public function removeChild($entity_type, $entity); + + /** * Loads the translation data into the wrapped entity. */ public function loadTranslations(); @@ -98,6 +113,9 @@ interface EntityTranslationHandlerInterface { /** * Returns TRUE if the entity is currently being translated. + * + * @deprecated This is no longer used and will be removed before the first + * stable release. */ public function isTranslating(); @@ -106,6 +124,9 @@ interface EntityTranslationHandlerInterface { * * @param $translating * A boolean value. + * + * @deprecated This is no longer used and will be removed before the first + * stable release. */ public function setTranslating($translating); @@ -310,6 +331,20 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa protected $entityId; protected $bundle; + /** + * The translation handler factory. + * + * @var EntityTranslationHandlerFactory + */ + protected $factory; + + /** + * The translation handler hierarchy storage. + * + * @var array + */ + protected $children = array(); + private $entityForm; private $translating; private $outdated; @@ -403,6 +438,46 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa } /** + * @see EntityTranslationHandlerInterface::setFactory() + */ + public function setFactory(EntityTranslationHandlerFactory $factory) { + $this->factory = $factory; + } + + /** + * @see EntityTranslationHandlerInterface::addChild() + */ + public function addChild($entity_type, $entity) { + if (!empty($this->factory)) { + $handler = $this->factory->getHandler($entity_type, $entity); + $handler->setFormLanguage($this->getFormLanguage()); + $handler->setSourceLanguage($this->getSourceLanguage()); + // Avoid registering more than one child handler for each entity. + $hid = $this->factory->getHandlerId($entity_type, $entity); + $this->children[$hid] = $handler; + } + } + + /** + * @see EntityTranslationHandlerInterface::removeChild() + */ + public function removeChild($entity_type, $entity) { + if (!empty($this->factory)) { + $hid = $this->factory->getHandlerId($entity_type, $entity); + unset($this->children[$hid]); + } + } + + /** + * Proxies the specified method invocation to a child translation handler. + */ + protected function notifyChildren($method, $args) { + foreach ($this->children as $handler) { + call_user_func_array(array($handler, $method), $args); + } + } + + /** * @see EntityTranslationHandlerInterface::loadTranslations() */ public function loadTranslations() { @@ -538,6 +613,9 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa } } } + + $args = func_get_args(); + $this->notifyChildren(__FUNCTION__, $args); } /** @@ -608,7 +686,7 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa if (empty($this->getTranslations()->data)) { $this->initTranslations(); } - elseif (!empty($langcode) && !$this->isTranslating()) { + elseif (!empty($langcode)) { $this->setOriginalLanguage($langcode); } } @@ -710,13 +788,17 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa public function setOriginalLanguage($langcode) { $translations = $this->getTranslations(); - if (isset($translations->original) && $translations->original != $langcode) { - $translations->data[$langcode] = $translations->data[$translations->original]; - $translations->data[$langcode]['language'] = $langcode; - unset($translations->data[$translations->original]); - } + if (!isset($translations->original) || $translations->original != $langcode) { + if (isset($translations->original)) { + $translations->data[$langcode] = $translations->data[$translations->original]; + $translations->data[$langcode]['language'] = $langcode; + unset($translations->data[$translations->original]); + } - $translations->original = $langcode; + $translations->original = $langcode; + $args = func_get_args(); + $this->notifyChildren(__FUNCTION__, $args); + } } /** @@ -754,6 +836,11 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa // Update bundle and entity id properties. list($this->entityId, , $this->bundle) = entity_extract_ids($this->entityType, $this->entity); + + // Initialize the handler id if needed. + if (!empty($this->factory)) { + $this->factory->getHandlerId($this->entityType, $entity); + } } /** @@ -782,6 +869,8 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa $translation['translate'] = 1; } } + $args = func_get_args(); + $this->notifyChildren(__FUNCTION__, $args); } } @@ -937,6 +1026,8 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa */ public function setFormLanguage($langcode) { $this->formLanguage = $langcode; + $args = func_get_args(); + $this->notifyChildren(__FUNCTION__, $args); } /** @@ -951,6 +1042,8 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa */ public function setSourceLanguage($langcode) { $this->sourceLanguage = $langcode; + $args = func_get_args(); + $this->notifyChildren(__FUNCTION__, $args); } /** @@ -989,12 +1082,16 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa $languages = language_list(); $access = user_access('translate any entity') || user_access("translate $this->entityType entities"); + // Store contextual information in the form state. + $form_state['entity_translation']['form_langcode'] = $form_langcode; + $form_state['entity_translation']['source_langcode'] = $this->getSourceLanguage(); // The only way to determine whether we are editing the original values is // comparing form language and entity language. Since a language change // might render impossible to make this check after form submission, we // store the related information here. $form_state['entity_translation']['is_translation'] = $is_translation; + // Adjust page title to specify the current language being edited, if we // have at least one translation. if ($form_langcode != LANGUAGE_NONE && (!$no_translations || $new_translation)) { @@ -1157,8 +1254,9 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa * Either remove access or add a translatability clue depending on the current * user's "edit translation shared fields" permissions. */ - public function entityFormSharedElements(&$element) { - static $ignored_types, $shared_labels, $access; + public function entityFormSharedElements(&$element, $access = NULL) { + static $ignored_types, $shared_labels; + if (!isset($ignored_types)) { $ignored_types = array_flip(array('actions', 'value', 'hidden', 'vertical_tabs', 'token')); } @@ -1171,7 +1269,7 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa foreach (element_children($element) as $key) { if (!isset($element[$key]['#type'])) { - $this->entityFormSharedElements($element[$key]); + $this->entityFormSharedElements($element[$key], $access); } else { // Ignore non-widget form elements. @@ -1198,7 +1296,7 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa public function entityFormLanguageWidget(&$form, &$form_state) { if (entity_translation_enabled($this->entityType, $this->bundle)) { $is_new = $this->isNewEntity(); - $is_translation = !$is_new && !empty($form_state['entity_translation']['is_translation']); + $is_translation = !empty($form_state['entity_translation']['is_translation']); $translations = $this->getTranslations(); $settings = entity_translation_settings($this->entityType, $this->bundle); $languages = entity_translation_languages($this->entityType, $this->entity); @@ -1206,8 +1304,8 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa foreach ($languages as $langcode => $language) { // Disable languages for existing translations, so it is not possible to - // switch this entity to some language which is already in the translation - // set. + // switch this entity to some language which is already in the + // translation set. if (!isset($translations->data[$langcode]) || empty($translations->data[$langcode]['source'])) { $options[$langcode] = t($language->name); } @@ -1232,17 +1330,14 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa } } - if (!empty($form['actions']['submit']['#submit'])) { - $submit = &$form['actions']['submit']['#submit']; - } - else { - if (!isset($form['#submit'])) { - $form['#submit'] = array(); - } - $submit = &$form['#submit']; - } - - array_unshift($submit, 'entity_translation_language_widget_submit'); + // Prepend an empty form element to the form array so that we can update the + // form language before any other form handler has been called. + $form = array( + 'entity_translation_entity_form_language_update' => array( + '#element_validate' => array('entity_translation_entity_form_language_update'), + '#entity_type' => $this->entityType, + ), + ) + $form; } /** @@ -1275,28 +1370,32 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa protected function updateFormLanguage($form_state) { // Update the form language as it might have changed. We exploit the // validation phase to be sure to act as early as possible. - if (isset($form_state['values']['language']) && !$this->isTranslationForm()) { - $this->setFormLanguage($form_state['values'][$this->getLanguageKey()]); + $language_key = $this->getLanguageKey(); + if (isset($form_state['values'][$language_key]) && !$this->isTranslationForm()) { + $langcode = $form_state['values'][$language_key]; + $this->setFormLanguage($langcode); } } /** * @see EntityTranslationHandlerInterface::entityFormLanguageWidgetSubmit() */ - function entityFormLanguageWidgetSubmit($form, &$form_state) { + public function entityFormLanguageWidgetSubmit($form, &$form_state) { $this->updateFormLanguage($form_state); $form_langcode = $this->getFormLanguage(); foreach (field_info_instances($this->entityType, $this->bundle) as $instance) { $field_name = $instance['field_name']; - $field = field_info_field($field_name); - $previous_langcode = $form[$field_name]['#language']; + if (isset($form[$field_name]['#language'])) { + $field = field_info_field($field_name); + $previous_langcode = $form[$field_name]['#language']; - // Handle a possible language change: new language values are inserted, - // previous ones are deleted. - if ($field['translatable'] && $previous_langcode != $form_langcode) { - $form_state['values'][$field_name][$form_langcode] = $form_state['values'][$field_name][$previous_langcode]; - $form_state['values'][$field_name][$previous_langcode] = array(); + // Handle a possible language change: new language values are inserted, + // previous ones are deleted. + if ($field['translatable'] && $previous_langcode != $form_langcode && isset($form_state['values'][$field_name][$previous_langcode])) { + $form_state['values'][$field_name][$form_langcode] = $form_state['values'][$field_name][$previous_langcode]; + $form_state['values'][$field_name][$previous_langcode] = array(); + } } } } diff --git a/includes/translation.handler_factory.inc b/includes/translation.handler_factory.inc new file mode 100644 index 0000000..59fd742 --- /dev/null +++ b/includes/translation.handler_factory.inc @@ -0,0 +1,137 @@ +getHandlerId($entity_type, $entity); + if (!isset($this->handlers[$entity_type][$id])) { + $entity_info = entity_get_info($entity_type); + $class = $entity_info['translation']['entity_translation']['class']; + // @todo Remove the fourth parameter once 3rd-party translation handlers + // have been fixed and no longer require the deprecated entity_id + // parameter. + $handler = new $class($entity_type, $entity_info, $entity, NULL); + $handler->setFactory($this); + $this->handlers[$entity_type][$id] = $handler; + } + + $this->last = $this->handlers[$entity_type][$id]; + $this->lastByType[$entity_type] = $this->last; + $this->last->setEntity($entity); + + return $this->last; + } + + /** + * Retrieves the translation handler identifier for the given entity. + * + * @param $entity_type + * The type of the entity the translation handler will wrap. + * @param $entity + * The entity the translation handler will wrap. + */ + public function getHandlerId($entity_type, $entity) { + if (!isset($entity->entity_translation_handler_id)) { + list($id, , ) = entity_extract_ids($entity_type, $entity); + $entity->entity_translation_handler_id = $entity_type . '-' . (!empty($id) ? 'eid-' . $id : 'new-' . self::$newId++); + } + return $entity->entity_translation_handler_id; + } + + /** + * Returns the last translation handler retrieved. + * + * @param $entity_type + * (optional) The entity type of the translation handler. Defaults to the + * last one. + * + * @return EntityTranslationHandlerInterface + * A class implementing EntityTranslationHandlerInterface. + */ + public function getLastHandler($entity_type = NULL) { + if (isset($entity_type)) { + return isset($this->lastByType[$entity_type]) ? $this->lastByType[$entity_type] : NULL; + } + return $this->last; + } + +} diff --git a/tests/entity_translation.test b/tests/entity_translation.test index 6a1bdc4..f440b4b 100644 --- a/tests/entity_translation.test +++ b/tests/entity_translation.test @@ -477,7 +477,7 @@ class EntityTranslationHookTestCase extends EntityTranslationTestCase { $handler->setTranslation($translation); $handler->saveTranslations(); $node = node_load($node->nid, NULL, TRUE); - $handler = entity_translation_get_handler('node', $node, TRUE); + $handler = entity_translation_get_handler('node', $node); $translations = $handler->getTranslations(); $this->assertTrue(!empty($translations->data['it']), t('An Italian translation has been created')); $info = $this->getHookInfo(); @@ -497,7 +497,7 @@ class EntityTranslationHookTestCase extends EntityTranslationTestCase { $handler->setTranslation($translation); $handler->saveTranslations(); $node = node_load($node->nid, NULL, TRUE); - $handler = entity_translation_get_handler('node', $node, TRUE); + $handler = entity_translation_get_handler('node', $node); $translations = $handler->getTranslations(); $this->assertTrue(!empty($translations->data['es']), t('A Spanish translation has been created')); $info = $this->getHookInfo();