public function ContentEntityCdfNormalizer::denormalize in Acquia Content Hub 8
Denormalizes data back into an object of the given class.
Parameters
mixed $data: Data to restore.
string $class: The expected class to instantiate.
string $format: Format the given data was extracted from.
array $context: Options available to the denormalizer.
Return value
array Returns denormalized data.
File
- src/
Normalizer/ ContentEntityCdfNormalizer.php, line 1176
Class
- ContentEntityCdfNormalizer
- Converts the Drupal entity object to a Acquia Content Hub CDF array.
Namespace
Drupal\acquia_contenthub\NormalizerCode
public function denormalize($data, $class, $format = NULL, array $context = []) {
$context += [
'account' => NULL,
];
// Exit if the class does not support denormalization of the given data,
// class and format.
if (!$this
->supportsDenormalization($data, $class, $format)) {
return NULL;
}
$contenthub_entity = new ContentHubEntity($data);
// Allow other modules to intercept and do changes to the Content Hub CDF
// before it is denormalized to a Drupal Entity.
$this->moduleHandler
->alter('acquia_contenthub_cdf_from_hub', $contenthub_entity);
$entity_type = $contenthub_entity
->getType();
$bundle_key = $this->entityTypeManager
->getDefinition($entity_type)
->getKey('bundle');
$bundle = $contenthub_entity
->getAttribute($bundle_key) ? reset($contenthub_entity
->getAttribute($bundle_key)['value']) : NULL;
$langcodes = !empty($contenthub_entity
->getAttribute('default_langcode')['value']) ? array_keys($contenthub_entity
->getAttribute('default_langcode')['value']) : [
$this->languageManager
->getDefaultLanguage()
->getId(),
];
// Get default langcode and remove from attributes.
if (!empty($contenthub_entity
->getAttribute('default_langcode')['value'])) {
foreach ($contenthub_entity
->getAttribute('default_langcode')['value'] as $key => $value) {
if ($value[0] == TRUE) {
$default_langcode = $key;
continue;
}
}
}
else {
if ($entity_type == 'file') {
$default_langcode = key($data['attributes']['url']['value']);
$langcodes = array_keys($data['attributes']['url']['value']);
}
else {
$default_langcode = $this->languageManager
->getDefaultLanguage()
->getId();
if ($langcode = $contenthub_entity
->getAttribute('langcode')) {
$langcodes = $langcode['value'];
if (!in_array($default_langcode, $langcodes)) {
$default_langcode = reset($langcodes);
}
}
}
}
// Store the translation source outside the CDF.
$content_translation_source = $contenthub_entity
->getAttribute('content_translation_source');
$contenthub_entity
->removeAttribute('content_translation_source');
// Make sure those langcodes exist in the site.
$site_langcodes = array_keys($this->languageManager
->getLanguages());
if (!in_array($default_langcode, $site_langcodes, TRUE)) {
$langcodes = array_intersect($site_langcodes, $langcodes);
// The default language in the CDF does not exist in the site, then we
// can use the site default's language as the entity default language and
// if that does not exist either, then just take the first language of
// the available ones in this site.
$site_default_language = $this->languageManager
->getDefaultLanguage()
->getId();
$default_langcode = in_array($site_default_language, $langcodes, TRUE) ? $site_default_language : reset($langcodes);
}
// Default Langcode is only used for initial entity creation. Remove now.
$contenthub_entity
->removeAttribute('langcode');
// Does this entity exist in this site already?
$source_entity = $this->entityRepository
->loadEntityByUuid($entity_type, $contenthub_entity
->getUuid());
$this
->processPassAlias($entity_type, $contenthub_entity, $langcodes);
if ($source_entity == NULL) {
// Transforming Content Hub Entity into a Drupal Entity.
$values = [
'uuid' => $contenthub_entity
->getUuid(),
];
if ($bundle) {
$values[$bundle_key] = $bundle;
}
// Set the content_translation source of whatever the default langcode
// says.
$values['content_translation_source'] = $content_translation_source['value'][$default_langcode][0] ?? NULL;
if (empty($values['content_translation_source'])) {
unset($values['content_translation_source']);
// Set the default langcode of the parent entity.
$values['default_langcode'] = $default_langcode == $this->languageManager
->getDefaultLanguage()
->getId();
}
else {
if (!in_array($values['content_translation_source'], $langcodes, TRUE)) {
$values['content_translation_source'] = LanguageInterface::LANGCODE_NOT_SPECIFIED;
$contenthub_entity
->removeAttribute('default_langcode');
}
else {
// Set the default langcode of the parent entity.
$values['default_langcode'] = $default_langcode;
}
}
// Special treatment according to entity types.
switch ($entity_type) {
case 'node':
$author = $contenthub_entity
->getAttribute('author') ? $contenthub_entity
->getAttribute('author')['value'][$default_langcode] : FALSE;
$user = Uuid::isValid($author) ? $this->entityRepository
->loadEntityByUuid('user', $author) : \Drupal::currentUser();
$values['uid'] = $user
->id() ? $user
->id() : 0;
// Set a status for the default language entity.
$status = $contenthub_entity
->getAttribute('status') ? $contenthub_entity
->getAttribute('status')['value'][$default_langcode] : 0;
$values['status'] = $status ? $status : 0;
// Check if Workbench Moderation or Content Moderation modules are
// enabled, if so, set the moderation_state to "published".
$workbench_moderation_enabled = \Drupal::moduleHandler()
->moduleExists('workbench_moderation');
$content_moderation_enabled = \Drupal::moduleHandler()
->moduleExists('content_moderation');
if ($values['status'] && ($workbench_moderation_enabled || $content_moderation_enabled)) {
$values['moderation_state'] = 'published';
}
break;
case 'media':
$attribute = $contenthub_entity
->getAttribute($bundle_key);
foreach ($langcodes as $lang) {
if (isset($attribute['value'][$lang])) {
$value = reset($attribute['value'][$lang]);
// Media entity didn't import by previous version of the module.
$values[$bundle_key] = $value;
}
}
// Remove an attribute to avoid the 'Error reading entity with
// UUID="image" from Content Hub' error.
if (!empty($values[$bundle_key])) {
$contenthub_entity
->removeAttribute($bundle_key);
}
break;
case 'file':
// If this is a file, then download the asset (image) locally.
$attribute = $contenthub_entity
->getAttribute('url');
foreach ($langcodes as $lang) {
if (isset($attribute['value'][$lang])) {
$remote_uri = is_array($attribute['value'][$lang]) ? array_values($attribute['value'][$lang])[0] : $attribute['value'][$lang];
$filepath = $this
->getFilePath($contenthub_entity);
if ($file_drupal_path = system_retrieve_file($remote_uri, $filepath, FALSE)) {
$values['uri'] = $file_drupal_path;
}
else {
// If the file URL is not publicly accessible, then this file
// entity cannot be created. There is no point in trying to
// complete the creation of this entity because it will fail
// to be saved in the system.
// Return a NULL entity and deal with it afterwards.
$message = $this
->t('File Entity with UUID = "%uuid" cannot be created: The remote resource %uri could not be downloaded into the system. Make sure this resource has a publicly accessible URL.', [
'%uuid' => $values['uuid'],
'%uri' => $remote_uri,
]);
$this->loggerFactory
->get('acquia_contenthub')
->error($message);
\Drupal::messenger()
->addError($message);
return NULL;
}
}
}
break;
case 'taxonomy_term':
// If it is a taxonomy_term, assing the vocabulary.
// @todo This is a hack. It should work with vocabulary entities.
$attribute = $contenthub_entity
->getAttribute('vocabulary');
foreach ($langcodes as $lang) {
$vocabulary_machine_name = $attribute['value'][$lang];
$vocabulary = $this
->getVocabularyByName($vocabulary_machine_name);
if (isset($vocabulary)) {
$values['vid'] = $vocabulary
->getOriginalId();
}
}
break;
case 'paragraph':
// In case of paragraphs, we need to strip out the parent_uuid and
// change it for parent_id.
// Fix a bug happening during export where parent_uuid only includes
// one language, which will fail during multilingual import. Extract
// the parent UUID and replicate it into all the languages.
$parent_uuid = current(array_filter($contenthub_entity
->getAttribute('parent_uuid')['value']));
$parent_type = current(current(array_filter($contenthub_entity
->getAttribute('parent_type')['value'])));
$parent_entity = $this->entityRepository
->loadEntityByUuid($parent_type, $parent_uuid);
$parent_id_attribute = new Attribute(Attribute::TYPE_ARRAY_STRING);
foreach ($langcodes as $lang) {
$parent_id_attribute
->setValue([
$parent_entity
->id(),
], $lang);
}
// Add parent_id attribute to entity and remove parent_uuid.
$attributes = $contenthub_entity
->getAttributes();
$attributes['parent_id'] = (array) $parent_id_attribute;
$contenthub_entity
->setAttributes($attributes);
$contenthub_entity
->removeAttribute('parent_uuid');
break;
}
if ($contenthub_entity
->getAttribute('path_uuid')) {
$contenthub_entity
->removeAttribute('path_uuid');
}
$langcode_key = $this->entityTypeManager
->getDefinition($entity_type)
->getKey('langcode');
$values[$langcode_key] = [
$default_langcode,
];
$source_entity = $this->entityTypeManager
->getStorage($entity_type)
->create($values);
}
else {
$contenthub_entity
->removeAttribute('default_langcode');
$delete_translations = $this->config
->get('acquia_contenthub.entity_config')
->get('delete_mismatching_translations');
if ($delete_translations) {
// Make sure that if there are local translations that have been deleted
// from Content Hub, they are deleted locally too.
$local_languages = $source_entity
->getTranslationLanguages();
$local_langcodes = array_keys($local_languages);
$delete_translations = array_diff($local_langcodes, array_values($langcodes));
foreach ($delete_translations as $lang) {
if ($source_entity
->hasTranslation($lang)) {
try {
$translated = $source_entity
->getTranslation($lang);
// We cannot remove default translations.
if (!$translated
->isDefaultTranslation()) {
$source_entity
->removeTranslation($lang);
}
} catch (\Exception $e) {
$this->loggerFactory
->get('acquia_contenthub')
->error('Cannot remove translation "@lang" for entity type = @type, id = @id, uuid = @uuid: @message', [
'@lang' => $lang,
'@type' => $source_entity
->getEntityTypeId(),
'@id' => $source_entity
->id(),
'@uuid' => $source_entity
->uuid(),
'@message' => $e
->getMessage(),
]);
}
}
}
}
}
$entity = $source_entity;
foreach ($langcodes as $langcode) {
// If this language exist in incoming data but is not supported in the
// importing site, don't import the data under this language.
if (!$this->languageManager
->getLanguage($langcode)) {
continue;
}
// Make sure the entity language is one of the language contained in the
// Content Hub Entity.
if ($source_entity
->hasTranslation($langcode)) {
$localized_entity = $source_entity
->getTranslation($langcode);
$entity = $this
->addFieldsToDrupalEntity($localized_entity, $contenthub_entity, $langcode, $context);
continue;
}
if ($langcode == LanguageInterface::LANGCODE_NOT_SPECIFIED || $langcode == LanguageInterface::LANGCODE_NOT_APPLICABLE) {
$entity = $this
->addFieldsToDrupalEntity($source_entity, $contenthub_entity, $langcode, $context);
continue;
}
$localized_entity = $source_entity
->addTranslation($langcode, $source_entity
->toArray());
$localized_entity->content_translation_source = $content_translation_source['value'][$langcode][0];
// Grab status for the language.
$status = $contenthub_entity
->getAttribute('status') ? $contenthub_entity
->getAttribute('status')['value'][$langcode] : 0;
$localized_entity->status = $status ? $status : 0;
$entity = $this
->addFieldsToDrupalEntity($localized_entity, $contenthub_entity, $langcode, $context);
}
// Allow other modules to intercept and do changes to the Drupal entity
// after it has been denormalized from a Content Hub CDF.
$this->moduleHandler
->alter('acquia_contenthub_drupal_from_cdf', $entity_type, $entity);
return $entity;
}