function FieldTranslationSynchronizer::synchronizeItems

Same name in other branches
  1. 9 core/modules/content_translation/src/FieldTranslationSynchronizer.php \Drupal\content_translation\FieldTranslationSynchronizer::synchronizeItems()
  2. 8.9.x core/modules/content_translation/src/FieldTranslationSynchronizer.php \Drupal\content_translation\FieldTranslationSynchronizer::synchronizeItems()
  3. 11.x core/modules/content_translation/src/FieldTranslationSynchronizer.php \Drupal\content_translation\FieldTranslationSynchronizer::synchronizeItems()
1 call to FieldTranslationSynchronizer::synchronizeItems()
FieldTranslationSynchronizer::synchronizeFields in core/modules/content_translation/src/FieldTranslationSynchronizer.php

File

core/modules/content_translation/src/FieldTranslationSynchronizer.php, line 206

Class

FieldTranslationSynchronizer
Provides field translation synchronization capabilities.

Namespace

Drupal\content_translation

Code

public function synchronizeItems(array &$values, array $unchanged_items, $sync_langcode, array $translations, array $properties) {
    $source_items = $values[$sync_langcode];
    // Make sure we can detect any change in the source items.
    $change_map = [];
    // By picking the maximum size between updated and unchanged items, we make
    // sure to process also removed items.
    $total = max([
        count($source_items),
        count($unchanged_items),
    ]);
    // As a first step we build a map of the deltas corresponding to the column
    // values to be synchronized. Recording both the old values and the new
    // values will allow us to detect any change in the order of the new items
    // for each column.
    for ($delta = 0; $delta < $total; $delta++) {
        foreach ([
            'old' => $unchanged_items,
            'new' => $source_items,
        ] as $key => $items) {
            if ($item_id = $this->itemHash($items, $delta, $properties)) {
                $change_map[$item_id][$key][] = $delta;
            }
        }
    }
    // Backup field values and the change map.
    $original_field_values = $values;
    $original_change_map = $change_map;
    // Reset field values so that no spurious one is stored. Source values must
    // be preserved in any case.
    $values = [
        $sync_langcode => $source_items,
    ];
    // Update field translations.
    foreach ($translations as $langcode) {
        // We need to synchronize only values different from the source ones.
        if ($langcode != $sync_langcode) {
            // Reinitialize the change map as it is emptied while processing each
            // language.
            $change_map = $original_change_map;
            // By using the maximum cardinality we ensure to process removed items.
            for ($delta = 0; $delta < $total; $delta++) {
                // By inspecting the map we built before we can tell whether a value
                // has been created or removed. A changed value will be interpreted as
                // a new value, in fact it did not exist before.
                $created = TRUE;
                $removed = TRUE;
                $old_delta = NULL;
                $new_delta = NULL;
                if ($item_id = $this->itemHash($source_items, $delta, $properties)) {
                    if (!empty($change_map[$item_id]['old'])) {
                        $old_delta = array_shift($change_map[$item_id]['old']);
                    }
                    if (!empty($change_map[$item_id]['new'])) {
                        $new_delta = array_shift($change_map[$item_id]['new']);
                    }
                    $created = $created && !isset($old_delta);
                    $removed = $removed && !isset($new_delta);
                }
                // If an item has been removed we do not store its translations.
                if ($removed) {
                    continue;
                }
                elseif ($created && !empty($original_field_values[$langcode][$delta])) {
                    $values[$langcode][$delta] = $this->createMergedItem($source_items[$delta], $original_field_values[$langcode][$delta], $properties);
                }
                elseif ($created) {
                    $values[$langcode][$delta] = $source_items[$delta];
                }
                elseif (isset($old_delta) && isset($new_delta)) {
                    // If for any reason the old value is not defined for the current
                    // language we fall back to the new source value, this way we ensure
                    // the new values are at least propagated to all the translations.
                    // If the value has only been reordered we just move the old one in
                    // the new position.
                    $item = $original_field_values[$langcode][$old_delta] ?? $source_items[$new_delta];
                    // When saving a default revision starting from a pending revision,
                    // we may have desynchronized field values, so we make sure that
                    // untranslatable properties are synchronized, even if in any other
                    // situation this would not be necessary.
                    $values[$langcode][$new_delta] = $this->createMergedItem($source_items[$new_delta], $item, $properties);
                }
            }
        }
    }
}

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.