Issue #2013837 by yched, plach: Rewrite field sync on top of NG entities.
parent
9ddac9e9fa
commit
e56a599e83
|
@ -9,6 +9,8 @@ namespace Drupal\translation_entity;
|
|||
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Entity\EntityManager;
|
||||
use Drupal\Core\Entity\EntityNG;
|
||||
use Drupal\Core\Entity\Field\FieldInterface;
|
||||
|
||||
/**
|
||||
* Provides field translation synchronization capabilities.
|
||||
|
@ -33,9 +35,15 @@ class FieldTranslationSynchronizer implements FieldTranslationSynchronizerInterf
|
|||
}
|
||||
|
||||
/**
|
||||
* Implements \Drupal\translation_entity\FieldTranslationSynchronizerInterface::synchronizeFields().
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function synchronizeFields(EntityInterface $entity, $sync_langcode, $original_langcode = NULL) {
|
||||
// Field synchronization is only supported for NG entities.
|
||||
$entity = $entity->getNGEntity();
|
||||
if (!($entity instanceof EntityNG)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$translations = $entity->getTranslationLanguages();
|
||||
|
||||
// If we have no information about what to sync to, if we are creating a new
|
||||
|
@ -52,17 +60,14 @@ class FieldTranslationSynchronizer implements FieldTranslationSynchronizerInterf
|
|||
return;
|
||||
}
|
||||
|
||||
// Enable compatibility mode for NG entities.
|
||||
$entity_unchanged = $entity_unchanged->getBCEntity();
|
||||
|
||||
// @todo Use Entity Field API to retrieve field definitions.
|
||||
$instances = field_info_instances($entity_type, $entity->bundle());
|
||||
foreach ($instances as $field_name => $instance) {
|
||||
$field = field_info_field($field_name);
|
||||
$field = $instance->getField();
|
||||
|
||||
// Sync when the field is not empty, when the synchronization translations
|
||||
// setting is set, and the field is translatable.
|
||||
if (!empty($entity->{$field_name}) && !empty($instance['settings']['translation_sync']) && field_is_translatable($entity_type, $field)) {
|
||||
if (!$entity->get($field_name)->isEmpty() && !empty($instance['settings']['translation_sync']) && field_is_translatable($entity_type, $field)) {
|
||||
// Retrieve all the untranslatable column groups and merge them into
|
||||
// single list.
|
||||
$groups = array_keys(array_diff($instance['settings']['translation_sync'], array_filter($instance['settings']['translation_sync'])));
|
||||
|
@ -74,12 +79,21 @@ class FieldTranslationSynchronizer implements FieldTranslationSynchronizerInterf
|
|||
$columns = array_merge($columns, isset($info['columns']) ? $info['columns'] : array($group));
|
||||
}
|
||||
if (!empty($columns)) {
|
||||
$values = array();
|
||||
foreach ($translations as $langcode => $language) {
|
||||
$values[$langcode] = $entity->getTranslation($langcode)->get($field_name)->getValue();
|
||||
}
|
||||
|
||||
// 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 ?: $sync_langcode;
|
||||
$unchanged_items = !empty($entity_unchanged->{$field_name}[$langcode]) ? $entity_unchanged->{$field_name}[$langcode] : array();
|
||||
$this->synchronizeItems($entity->{$field_name}, $unchanged_items, $sync_langcode, array_keys($translations), $columns);
|
||||
$unchanged_items = $entity_unchanged->getTranslation($langcode)->get($field_name)->getValue();
|
||||
$this->synchronizeItems($values, $unchanged_items, $sync_langcode, array_keys($translations), $columns);
|
||||
|
||||
foreach ($translations as $langcode => $language) {
|
||||
$entity->getTranslation($langcode)->get($field_name)->setValue($values[$langcode]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -87,10 +101,10 @@ class FieldTranslationSynchronizer implements FieldTranslationSynchronizerInterf
|
|||
}
|
||||
|
||||
/**
|
||||
* Implements \Drupal\translation_entity\FieldTranslationSynchronizerInterface::synchronizeItems().
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function synchronizeItems(array &$field_values, array $unchanged_items, $sync_langcode, array $translations, array $columns) {
|
||||
$source_items = $field_values[$sync_langcode];
|
||||
public function synchronizeItems(array &$values, array $unchanged_items, $sync_langcode, array $translations, array $columns) {
|
||||
$source_items = $values[$sync_langcode];
|
||||
|
||||
// Make sure we can detect any change in the source items.
|
||||
$change_map = array();
|
||||
|
@ -112,15 +126,16 @@ class FieldTranslationSynchronizer implements FieldTranslationSynchronizerInterf
|
|||
}
|
||||
|
||||
// Backup field values and the change map.
|
||||
$original_field_values = $field_values;
|
||||
$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.
|
||||
$field_values = array($sync_langcode => $source_items);
|
||||
$values = array($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
|
||||
|
@ -155,7 +170,7 @@ class FieldTranslationSynchronizer implements FieldTranslationSynchronizerInterf
|
|||
// If a synchronized column has changed or has been created from
|
||||
// scratch we need to override the full items array for all languages.
|
||||
elseif ($created) {
|
||||
$field_values[$langcode][$delta] = $source_items[$delta];
|
||||
$values[$langcode][$delta] = $source_items[$delta];
|
||||
}
|
||||
// Otherwise the current item might have been reordered.
|
||||
elseif (isset($old_delta) && isset($new_delta)) {
|
||||
|
@ -165,7 +180,7 @@ class FieldTranslationSynchronizer implements FieldTranslationSynchronizerInterf
|
|||
// If the value has only been reordered we just move the old one in
|
||||
// the new position.
|
||||
$item = isset($original_field_values[$langcode][$old_delta]) ? $original_field_values[$langcode][$old_delta] : $source_items[$new_delta];
|
||||
$field_values[$langcode][$new_delta] = $item;
|
||||
$values[$langcode][$new_delta] = $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,7 +88,7 @@ class EntityTranslationSyncImageTest extends EntityTranslationTestBase {
|
|||
$langcode = $this->langcodes[1];
|
||||
|
||||
// Populate the required contextual values.
|
||||
$attributes = drupal_container()->get('request')->attributes;
|
||||
$attributes = $this->container->get('request')->attributes;
|
||||
$attributes->set('working_langcode', $langcode);
|
||||
$attributes->set('source_langcode', $default_langcode);
|
||||
|
||||
|
@ -98,7 +98,7 @@ class EntityTranslationSyncImageTest extends EntityTranslationTestBase {
|
|||
'user_id' => mt_rand(1, 128),
|
||||
'langcode' => $default_langcode,
|
||||
);
|
||||
$entity = entity_create($this->entityType, $values)->getBCEntity();
|
||||
$entity = entity_create($this->entityType, $values);
|
||||
|
||||
// Create some file entities from the generated test files and store them.
|
||||
$values = array();
|
||||
|
@ -122,10 +122,10 @@ class EntityTranslationSyncImageTest extends EntityTranslationTestBase {
|
|||
// the entity.
|
||||
$item = array(
|
||||
'fid' => $fid,
|
||||
'alt' => $this->randomName(),
|
||||
'title' => $this->randomName(),
|
||||
'alt' => $default_langcode . '_' . $fid . '_' . $this->randomName(),
|
||||
'title' => $default_langcode . '_' . $fid . '_' . $this->randomName(),
|
||||
);
|
||||
$entity->{$this->fieldName}[$default_langcode][$delta] = $item;
|
||||
$entity->{$this->fieldName}->offsetGet($delta)->setValue($item);
|
||||
|
||||
// Store the generated values keying them by fid for easier lookup.
|
||||
$values[$default_langcode][$fid] = $item;
|
||||
|
@ -147,10 +147,10 @@ class EntityTranslationSyncImageTest extends EntityTranslationTestBase {
|
|||
$fid = $this->files[$index]->fid;
|
||||
$item = array(
|
||||
'fid' => $fid,
|
||||
'alt' => $this->randomName(),
|
||||
'title' => $this->randomName(),
|
||||
'alt' => $langcode . '_' . $fid . '_' . $this->randomName(),
|
||||
'title' => $langcode . '_' . $fid . '_' . $this->randomName(),
|
||||
);
|
||||
$entity->{$this->fieldName}[$langcode][$delta] = $item;
|
||||
$entity->getTranslation($langcode)->{$this->fieldName}->offsetGet($delta)->setValue($item);
|
||||
|
||||
// Again store the generated values keying them by fid for easier lookup.
|
||||
$values[$langcode][$fid] = $item;
|
||||
|
@ -161,18 +161,18 @@ class EntityTranslationSyncImageTest extends EntityTranslationTestBase {
|
|||
$entity = $this->saveEntity($entity);
|
||||
|
||||
// Check that one value has been dropped from the original values.
|
||||
$assert = count($entity->{$this->fieldName}[$default_langcode]) == 2;
|
||||
$assert = count($entity->{$this->fieldName}) == 2;
|
||||
$this->assertTrue($assert, 'One item correctly removed from the synchronized field values.');
|
||||
|
||||
// Check that fids have been synchronized and translatable column values
|
||||
// have been retained.
|
||||
$fids = array();
|
||||
foreach ($entity->{$this->fieldName}[$default_langcode] as $delta => $item) {
|
||||
$value = $values[$default_langcode][$item['fid']];
|
||||
$source_item = $entity->{$this->fieldName}[$langcode][$delta];
|
||||
$assert = $item['fid'] == $source_item['fid'] && $item['alt'] == $value['alt'] && $item['title'] == $value['title'];
|
||||
$this->assertTrue($assert, format_string('Field item @fid has been successfully synchronized.', array('@fid' => $item['fid'])));
|
||||
$fids[$item['fid']] = TRUE;
|
||||
foreach ($entity->{$this->fieldName} as $delta => $item) {
|
||||
$value = $values[$default_langcode][$item->fid];
|
||||
$source_item = $entity->getTranslation($langcode)->{$this->fieldName}->offsetGet($delta);
|
||||
$assert = $item->fid == $source_item->fid && $item->alt == $value['alt'] && $item->title == $value['title'];
|
||||
$this->assertTrue($assert, format_string('Field item @fid has been successfully synchronized.', array('@fid' => $item->fid)));
|
||||
$fids[$item->fid] = TRUE;
|
||||
}
|
||||
|
||||
// Check that the dropped value is the right one.
|
||||
|
@ -180,30 +180,29 @@ class EntityTranslationSyncImageTest extends EntityTranslationTestBase {
|
|||
$this->assertTrue(!isset($fids[$removed_fid]), format_string('Field item @fid has been correctly removed.', array('@fid' => $removed_fid)));
|
||||
|
||||
// Add back an item for the dropped value and perform synchronization again.
|
||||
// @todo Actually we would need to reset the contextual information to test
|
||||
// an update, but there is no entity field class for image fields yet,
|
||||
// hence field translation update does not work properly for those.
|
||||
$values[$langcode][$removed_fid] = array(
|
||||
'fid' => $removed_fid,
|
||||
'alt' => $this->randomName(),
|
||||
'title' => $this->randomName(),
|
||||
'alt' => $langcode . '_' . $removed_fid . '_' . $this->randomName(),
|
||||
'title' => $langcode . '_' . $removed_fid . '_' . $this->randomName(),
|
||||
);
|
||||
$entity->{$this->fieldName}[$langcode] = array_values($values[$langcode]);
|
||||
$entity->getTranslation($langcode)->{$this->fieldName}->setValue(array_values($values[$langcode]));
|
||||
// When updating an entity we do not have a source language defined.
|
||||
$attributes->remove('source_langcode');
|
||||
$entity = $this->saveEntity($entity);
|
||||
|
||||
// Check that the value has been added to the default language.
|
||||
$assert = count($entity->{$this->fieldName}[$default_langcode]) == 3;
|
||||
$assert = count($entity->{$this->fieldName}->getValue()) == 3;
|
||||
$this->assertTrue($assert, 'One item correctly added to the synchronized field values.');
|
||||
|
||||
foreach ($entity->{$this->fieldName}[$default_langcode] as $delta => $item) {
|
||||
foreach ($entity->{$this->fieldName} as $delta => $item) {
|
||||
// When adding an item its value is copied over all the target languages,
|
||||
// thus in this case the source language needs to be used to check the
|
||||
// values instead of the target one.
|
||||
$fid_langcode = $item['fid'] != $removed_fid ? $default_langcode : $langcode;
|
||||
$value = $values[$fid_langcode][$item['fid']];
|
||||
$source_item = $entity->{$this->fieldName}[$langcode][$delta];
|
||||
$assert = $item['fid'] == $source_item['fid'] && $item['alt'] == $value['alt'] && $item['title'] == $value['title'];
|
||||
$this->assertTrue($assert, format_string('Field item @fid has been successfully synchronized.', array('@fid' => $item['fid'])));
|
||||
$fid_langcode = $item->fid != $removed_fid ? $default_langcode : $langcode;
|
||||
$value = $values[$fid_langcode][$item->fid];
|
||||
$source_item = $entity->getTranslation($langcode)->{$this->fieldName}->offsetGet($delta);
|
||||
$assert = $item->fid == $source_item->fid && $item->alt == $value['alt'] && $item->title == $value['title'];
|
||||
$this->assertTrue($assert, format_string('Field item @fid has been successfully synchronized.', array('@fid' => $item->fid)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -219,7 +218,7 @@ class EntityTranslationSyncImageTest extends EntityTranslationTestBase {
|
|||
protected function saveEntity(EntityInterface $entity) {
|
||||
$entity->save();
|
||||
$entity = entity_test_mul_load($entity->id(), TRUE);
|
||||
return $entity->getBCEntity();
|
||||
return $entity;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue