public function LingotekContentTranslationService::saveTargetData in Lingotek Translation 8
Same name and namespace in other branches
- 8.2 src/LingotekContentTranslationService.php \Drupal\lingotek\LingotekContentTranslationService::saveTargetData()
- 4.0.x src/LingotekContentTranslationService.php \Drupal\lingotek\LingotekContentTranslationService::saveTargetData()
- 3.0.x src/LingotekContentTranslationService.php \Drupal\lingotek\LingotekContentTranslationService::saveTargetData()
- 3.1.x src/LingotekContentTranslationService.php \Drupal\lingotek\LingotekContentTranslationService::saveTargetData()
- 3.2.x src/LingotekContentTranslationService.php \Drupal\lingotek\LingotekContentTranslationService::saveTargetData()
- 3.3.x src/LingotekContentTranslationService.php \Drupal\lingotek\LingotekContentTranslationService::saveTargetData()
- 3.4.x src/LingotekContentTranslationService.php \Drupal\lingotek\LingotekContentTranslationService::saveTargetData()
- 3.5.x src/LingotekContentTranslationService.php \Drupal\lingotek\LingotekContentTranslationService::saveTargetData()
- 3.6.x src/LingotekContentTranslationService.php \Drupal\lingotek\LingotekContentTranslationService::saveTargetData()
- 3.7.x src/LingotekContentTranslationService.php \Drupal\lingotek\LingotekContentTranslationService::saveTargetData()
- 3.8.x src/LingotekContentTranslationService.php \Drupal\lingotek\LingotekContentTranslationService::saveTargetData()
Save the entity translation.
Parameters
\Drupal\Core\Entity\ContentEntityInterface &$entity: The entity we want to save a translation for.
$locale: The locale of the translation being saved.
$data: The data being saved.
Return value
ContentEntityInterface Returns the entity which translations are saved.
Overrides LingotekContentTranslationServiceInterface::saveTargetData
1 call to LingotekContentTranslationService::saveTargetData()
- LingotekContentTranslationService::downloadDocument in src/
LingotekContentTranslationService.php - Downloads a document from the Lingotek service for a given locale.
File
- src/
LingotekContentTranslationService.php, line 853 - Contains \Drupal\lingotek\LingotekContentTranslationService.
Class
- LingotekContentTranslationService
- Service for managing Lingotek content translations.
Namespace
Drupal\lingotekCode
public function saveTargetData(ContentEntityInterface &$entity, $langcode, $data) {
// Without a defined langcode, we can't proceed
if (!$langcode) {
// TODO: log warning that downloaded translation's langcode is not enabled.
return FALSE;
}
$storage_definitions = $this->entityManager
->getFieldStorageDefinitions($entity
->getEntityTypeId());
$lock = \Drupal::lock();
$lock_name = __FUNCTION__ . ':' . $entity
->getEntityTypeId() . ':' . $entity
->id();
$held = $lock
->acquire($lock_name);
// It is critical that we acquire a lock on this entity since we want to ensure
// that our translation is saved.
if (!$held) {
if ($lock
->wait($lock_name) === FALSE) {
$held = $lock
->acquire($lock_name);
}
}
if (!$held) {
// We were unable to acquire the lock even after waiting, so we have to bail.
// (We don't have to call release() here since we never succeeded at acquiring it)
throw new \Exception(new FormattableMarkup('Unable to acquire lock for entity @id of type @type.', [
'@id' => $entity
->id(),
'@type' => $entity
->getEntityTypeId(),
]));
}
try {
// We need to load the revision that was uploaded for consistency. For that,
// we check if we have a valid revision in the response, and if not, we
// check the date of the uploaded document.
/** @var ContentEntityInterface $entity */
$revision = isset($data['_lingotek_metadata']) ? $data['_lingotek_metadata']['_entity_revision'] : NULL;
$revision = $this
->loadUploadedRevision($entity, $revision);
// Initialize the translation on the Drupal side, if necessary.
/** @var ContentEntityInterface $translation */
if (!$entity
->hasTranslation($langcode)) {
$entity
->addTranslation($langcode, $revision
->toArray());
}
$translation = $entity
->getTranslation($langcode);
foreach ($data as $name => $field_data) {
if (strpos($name, '_') === 0) {
// Skip special fields underscored.
break;
}
$field_definition = $entity
->getFieldDefinition($name);
if (($field_definition
->isTranslatable() || $field_definition
->getType() === 'entity_reference_revisions') && $this->lingotekConfiguration
->isFieldLingotekEnabled($entity
->getEntityTypeId(), $entity
->bundle(), $name)) {
// First we check if this is a entity reference, and save the translated entity.
$field_type = $field_definition
->getType();
if ($field_type === 'entity_reference' || $field_type === 'er_viewmode') {
$target_entity_type_id = $field_definition
->getFieldStorageDefinition()
->getSetting('target_type');
$index = 0;
foreach ($field_data as $field_item) {
if (isset($field_item['_lingotek_metadata'])) {
$target_entity_type_id = $field_item['_lingotek_metadata']['_entity_type_id'];
$embedded_entity_id = $field_item['_lingotek_metadata']['_entity_id'];
$embedded_entity_revision_id = $field_item['_lingotek_metadata']['_entity_revision'];
}
else {
// Try to get it from the revision itself. It may have been
// modified, so this can be a source of errors, but we need this
// because we didn't have metadata before.
$embedded_entity_id = $revision->{$name}
->get($index)
->get('target_id')
->getValue();
}
$embedded_entity = $this->entityManager
->getStorage($target_entity_type_id)
->load($embedded_entity_id);
// We may have orphan references, so ensure that they exist before
// continuing.
if ($embedded_entity !== NULL) {
// ToDo: It can be a content entity, or a config entity.
if ($embedded_entity instanceof ContentEntityInterface) {
if ($this->lingotekConfiguration
->isEnabled($embedded_entity
->getEntityTypeId(), $embedded_entity
->bundle())) {
$this
->saveTargetData($embedded_entity, $langcode, $field_item);
}
else {
\Drupal::logger('lingotek')
->warning($this
->t('Field %field not saved as it\'s referenced entity is not translatable by Lingotek', [
'%field' => $name,
]));
}
}
elseif ($embedded_entity instanceof ConfigEntityInterface) {
$this->lingotekConfigTranslation
->saveTargetData($embedded_entity, $langcode, $field_item);
}
// Now the embedded entity is saved, but we need to ensure
// the reference will be saved too.
$translation->{$name}
->set($index, $embedded_entity_id);
}
++$index;
}
}
else {
if ($field_type === 'entity_reference_revisions') {
$target_entity_type_id = $field_definition
->getFieldStorageDefinition()
->getSetting('target_type');
$index = 0;
foreach ($field_data as $field_item) {
$embedded_entity_id = $revision->{$name}
->get($index)
->get('target_id')
->getValue();
/** @var \Drupal\Core\Entity\RevisionableInterface $embedded_entity */
$embedded_entity = $this->entityManager
->getStorage($target_entity_type_id)
->load($embedded_entity_id);
$this
->saveTargetData($embedded_entity, $langcode, $field_item);
// Now the embedded entity is saved, but we need to ensure
// the reference will be saved too. Ensure it's the same revision.
$translation->{$name}
->set($index, [
'target_id' => $embedded_entity_id,
'target_revision_id' => $embedded_entity
->getRevisionId(),
]);
++$index;
}
}
else {
if ($field_type === 'path') {
$pid = NULL;
$source = '/' . $entity
->toUrl()
->getInternalPath();
/** @var \Drupal\Core\Path\AliasStorageInterface $aliasStorage */
$alias_storage = \Drupal::service('path.alias_storage');
$path = $alias_storage
->load([
'source' => $source,
'langcode' => $langcode,
]);
$original_path = $alias_storage
->load([
'source' => $source,
'langcode' => $entity
->getUntranslated()
->language()
->getId(),
]);
if ($path) {
$pid = $path['pid'];
}
$alias = $field_data[0]['alias'];
// Validate the alias before saving.
if (!\Drupal::pathValidator()
->isValid($alias)) {
\Drupal::logger('lingotek')
->warning($this
->t('Alias for %type %label in language %langcode not saved, invalid uri "%uri"', [
'%type' => $entity
->getEntityTypeId(),
'%label' => $entity
->label(),
'%langcode' => $langcode,
'%uri' => $alias,
]));
// Default to the original path.
$alias = $original_path ? $original_path['alias'] : $source;
}
if ($alias !== NULL) {
\Drupal::service('path.alias_storage')
->save($source, $alias, $langcode, $pid);
}
}
else {
if ($field_type === 'metatag') {
$index = 0;
foreach ($field_data as $field_item) {
$metatag_value = serialize($field_item);
$translation->{$name}
->set($index, $metatag_value);
++$index;
}
}
else {
// Initialize delta in case there are no items in $field_data.
$delta = -1;
// Save regular fields.
foreach ($field_data as $delta => $delta_data) {
foreach ($delta_data as $property => $property_data) {
$property_definition = $storage_definitions[$name]
->getPropertyDefinition($property);
$data_type = $property_definition
->getDataType();
if ($data_type === 'uri') {
// Validate an uri.
if (!\Drupal::pathValidator()
->isValid($property_data)) {
\Drupal::logger('lingotek')
->warning($this
->t('Field %field for %type %label in language %langcode not saved, invalid uri "%uri"', [
'%field' => $name,
'%type' => $entity
->getEntityTypeId(),
'%label' => $entity
->label(),
'%langcode' => $langcode,
'%uri' => $property_data,
]));
// Let's default to the original value given that there was a problem.
$property_data = $revision
->get($name)
->offsetGet($delta)->{$property};
}
}
if (method_exists($translation
->get($name)
->offsetGet($delta), "set")) {
$translation
->get($name)
->offsetGet($delta)
->set($property, $property_data);
}
elseif ($translation
->get($name)) {
$translation
->get($name)
->appendItem()
->set($property, $property_data);
}
}
}
// Remove the rest of deltas that were no longer found in the document downloaded from lingotek.
$continue = TRUE;
while ($continue) {
if ($translation
->get($name)
->offsetExists($delta + 1)) {
$translation
->get($name)
->removeItem($delta + 1);
}
else {
$continue = FALSE;
}
}
}
}
}
}
}
}
// We need to set the content_translation source so the files are synced
// properly. See https://www.drupal.org/node/2544696 for more information.
$translation
->set('content_translation_source', $entity
->getUntranslated()
->language()
->getId());
$entity->lingotek_processed = TRUE;
// Allow other modules to alter the translation before is saved.
\Drupal::moduleHandler()
->invokeAll('lingotek_content_entity_translation_presave', [
&$translation,
$langcode,
$data,
]);
$status_field = $entity
->getEntityType()
->getKey('status');
$status_field_definition = $entity
->getFieldDefinition($status_field);
if ($status_field_definition !== NULL && $status_field_definition
->isTranslatable()) {
$status_setting = $this->lingotekConfiguration
->getPreference('target_download_status');
if ($status_setting !== "same-as-source") {
$status_value = $status_setting === 'published' ? NODE_PUBLISHED : NODE_NOT_PUBLISHED;
$translation
->set($status_field, $status_value);
}
}
$translation
->save();
return $entity;
} catch (EntityStorageException $storage_exception) {
throw new LingotekContentEntityStorageException($entity, $storage_exception);
} finally {
// Ensure the lock is released, even if we crash.
$lock
->release($lock_name);
}
}