You are here

function entity_translation_sync in Entity Translation 7

Performs field column synchronization.

1 call to entity_translation_sync()
entity_translation_field_attach_presave in ./entity_translation.module
Implements hook_field_attach_presave().

File

./entity_translation.module, line 1040

Code

function entity_translation_sync($entity_type, $entity) {

  // If we are creating a new entity or if we have no translations for the
  // current entity, there is nothing to synchronize.
  $handler = entity_translation_get_handler($entity_type, $entity, TRUE);
  $translations = $handler
    ->getTranslations();
  $original_langcode = $handler
    ->getSourceLanguage();
  if ($handler
    ->isNewEntity() || count($translations->data) < 2 && !$original_langcode) {
    return;
  }
  list($id, , $bundle) = entity_extract_ids($entity_type, $entity);
  $instances = field_info_instances($entity_type, $bundle);
  $entity_unchanged = isset($entity->original) ? $entity->original : entity_load_unchanged($entity_type, $id);

  // If the entity language is being changed there is nothing to synchronize.
  $langcode = $handler
    ->getLanguage();
  $handler
    ->setEntity($entity_unchanged);
  if ($langcode != $handler
    ->getLanguage()) {
    return;
  }
  foreach ($instances as $field_name => $instance) {
    $field = field_info_field($field_name);

    // If the field is empty there is nothing to synchronize. Synchronization
    // makes sense only for translatable fields.
    if (!empty($entity->{$field_name}) && !empty($instance['settings']['entity_translation_sync']) && field_is_translatable($entity_type, $field)) {
      $columns = $field['settings']['entity_translation_sync'];
      $change_map = array();
      $source_langcode = entity_language($entity_type, $entity);
      $source_items = $entity->{$field_name}[$source_langcode];

      // If a translation is being created, the original values should be used
      // as the unchanged items. In fact there are no unchanged items to check
      // against.
      $langcode = $original_langcode ? $original_langcode : $source_langcode;
      $unchanged_items = !empty($entity_unchanged->{$field_name}[$langcode]) ? $entity_unchanged->{$field_name}[$langcode] : array();

      // By picking the maximum size between updated and unchanged items, we
      // make sure to process also removed items.
      $total = max(array(
        count($source_items),
        count($unchanged_items),
      ));

      // Make sure we can detect any change in the source items.
      for ($delta = 0; $delta < $total; $delta++) {
        foreach ($columns as $column) {

          // Store the delta for the unchanged column value.
          if (isset($unchanged_items[$delta][$column])) {
            $value = $unchanged_items[$delta][$column];
            $change_map[$column][$value]['old'] = $delta;
          }

          // Store the delta for the new column value.
          if (isset($source_items[$delta][$column])) {
            $value = $source_items[$delta][$column];
            $change_map[$column][$value]['new'] = $delta;
          }
        }
      }

      // Backup field values.
      $field_values = $entity->{$field_name};

      // Reset field values so that no spurious translation value is stored.
      // Source values and anything else must be preserved in any case.
      $entity->{$field_name} = array(
        $source_langcode => $source_items,
      ) + array_diff_key($entity->{$field_name}, $translations->data);

      // Update translations.
      foreach ($translations->data as $langcode => $translation) {

        // We need to synchronize only values different from the source ones.
        if ($langcode != $source_langcode) {

          // Process even removed items.
          for ($delta = 0; $delta < $total; $delta++) {
            $created = TRUE;
            $removed = TRUE;
            foreach ($columns as $column) {
              if (isset($source_items[$delta][$column])) {
                $value = $source_items[$delta][$column];
                $created = $created && !isset($change_map[$column][$value]['old']);
                $removed = $removed && !isset($change_map[$column][$value]['new']);
              }
            }

            // If an item has been removed we do not store its translations.
            if ($removed) {

              // Ensure items are actually removed.
              if (!isset($entity->{$field_name}[$langcode])) {
                $entity->{$field_name}[$langcode] = array();
              }
              continue;
            }
            elseif ($created) {
              $entity->{$field_name}[$langcode][$delta] = $source_items[$delta];
            }
            elseif (!empty($change_map[$column][$value])) {
              $old_delta = $change_map[$column][$value]['old'];
              $new_delta = $change_map[$column][$value]['new'];

              // If for nay reason the old value is not defined for the current
              // we language we fall back to the new source value.
              $items = isset($field_values[$langcode][$old_delta]) ? $field_values[$langcode][$old_delta] : $source_items[$new_delta];
              $entity->{$field_name}[$langcode][$new_delta] = $items;
            }
          }
        }
      }
    }
  }
}