View source
<?php
namespace Drupal\acquia_contenthub\Normalizer;
use Acquia\ContentHubClient\Asset;
use Acquia\ContentHubClient\Attribute;
use Acquia\ContentHubClient\Entity as ContentHubEntity;
use Drupal\acquia_contenthub\ContentHubEntityEmbedHandler;
use Drupal\acquia_contenthub\ContentHubEntityLinkFieldHandler;
use Drupal\acquia_contenthub\ContentHubException;
use Drupal\acquia_contenthub\EntityManager;
use Drupal\acquia_contenthub\Session\ContentHubUserSession;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Component\Utility\UrlHelper;
use Drupal\Component\Uuid\Uuid;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Config\Entity\ConfigEntityBase;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityRepositoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Field\EntityReferenceFieldItemListInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Url;
use Drupal\path\Plugin\Field\FieldType\PathFieldItemList;
use Drupal\taxonomy\Entity\Vocabulary;
use Symfony\Component\HttpKernel\HttpKernelInterface;
class ContentEntityCdfNormalizer extends NormalizerBase {
use StringTranslationTrait;
protected $format = 'acquia_contenthub_cdf';
protected $baseUrl;
protected $supportedInterfaceOrClass = 'Drupal\\Core\\Entity\\ContentEntityInterface';
protected $config;
protected $contentEntityViewModesNormalizer;
protected $moduleHandler;
protected $entityRepository;
protected $baseRoot;
protected $kernel;
protected $renderer;
protected $entityManager;
protected $entityTypeManager;
protected $loggerFactory;
protected $languageManager;
protected $translationManager;
public function __construct(ConfigFactoryInterface $config_factory, ContentEntityViewModesExtractorInterface $content_entity_view_modes_normalizer, ModuleHandlerInterface $module_handler, EntityRepositoryInterface $entity_repository, HttpKernelInterface $kernel, RendererInterface $renderer, EntityManager $entity_manager, EntityTypeManagerInterface $entity_type_manager, LoggerChannelFactoryInterface $logger_factory, LanguageManagerInterface $language_manager) {
global $base_url;
$this->baseUrl = $base_url;
$this->config = $config_factory;
$this->contentEntityViewModesNormalizer = $content_entity_view_modes_normalizer;
$this->moduleHandler = $module_handler;
$this->entityRepository = $entity_repository;
$this->kernel = $kernel;
$this->renderer = $renderer;
$this->entityManager = $entity_manager;
$this->entityTypeManager = $entity_type_manager;
$this->loggerFactory = $logger_factory;
$this->languageManager = $language_manager;
if ($this->moduleHandler
->moduleExists('content_translation')) {
$this->translationManager = \Drupal::getContainer()
->get("content_translation.manager");
}
}
protected function getSerializer() {
return \Drupal::service('serializer');
}
public function getBaseRoot() {
if (isset($GLOBALS['base_root'])) {
return $GLOBALS['base_root'];
}
return '';
}
public function normalize($entity, $format = NULL, array $context = []) {
if (!$this
->supportsNormalization($entity, $format)) {
return NULL;
}
$account = new ContentHubUserSession($this->config
->get('acquia_contenthub.entity_config')
->get('user_role'));
$context += [
'account' => $account,
];
$entity_access = $entity
->access('view', $account, TRUE);
if (!$entity_access
->isAllowed() && !$entity_access
->isNeutral()) {
return NULL;
}
$cache = [
'#cache' => [
'contexts' => [
'url.query_args:include_references',
],
],
];
$this->renderer
->renderPlain($cache);
$current_uri = \Drupal::request()
->getRequestUri();
$uri = UrlHelper::parse($current_uri);
$context += [
'query_params' => $uri['query'],
];
$entity_type_id = $context['entity_type'] = $entity
->getEntityTypeId();
$entity_uuid = $entity
->uuid();
$origin = $this->config
->get('acquia_contenthub.admin_settings')
->get('origin');
$this->moduleHandler
->alter('acquia_contenthub_drupal_to_cdf', $entity_type_id, $entity);
if ($entity
->hasField('created') && $entity
->get('created')) {
$created = date('c', $entity
->get('created')
->getValue()[0]['value']);
}
else {
$created = date('c');
}
$modified = date('c');
$base_root = $this
->getBaseRoot();
$contenthub_entity = new ContentHubEntity();
$contenthub_entity
->setUuid($entity_uuid)
->setType($entity_type_id)
->setOrigin($origin)
->setCreated($created)
->setModified($modified);
if ($view_modes = $this->contentEntityViewModesNormalizer
->getRenderedViewModes($entity)) {
$contenthub_entity
->setMetadata([
'base_root' => $base_root,
'view_modes' => $view_modes,
]);
}
$languages = $entity
->getTranslationLanguages();
foreach ($languages as $language) {
$langcode = $language
->getId();
$localized_entity = $entity
->getTranslation($langcode);
if (!empty($this->translationManager) && $this->translationManager
->isEnabled($entity_type_id, $entity
->bundle())) {
$translation_metadata = $this->translationManager
->getTranslationMetadata($localized_entity);
if (!$translation_metadata
->isPublished()) {
continue;
}
}
$contenthub_entity = $this
->addFieldsToContentHubEntity($contenthub_entity, $localized_entity, $langcode, $context);
}
$this->moduleHandler
->alter('acquia_contenthub_cdf_from_drupal', $contenthub_entity);
$normalized = [
'entities' => [
$contenthub_entity,
],
];
if (!empty($context['query_params']['include_references']) && $context['query_params']['include_references'] == 'true') {
$referenced_entities = [];
$referenced_entities = $this
->getMultilevelReferencedFields($entity, $referenced_entities, $context);
$path_uuid_attribute = $contenthub_entity
->getAttribute('path_uuid');
if ($path_uuid_attribute) {
foreach ($path_uuid_attribute
->getValues() as $values) {
foreach ($values as $path_alias_uuid) {
$path_alias_entity = $this->entityRepository
->loadEntityByUuid('path_alias', $path_alias_uuid);
if ($this->entityManager
->isEligibleDependency($path_alias_entity)) {
$referenced_entities[$path_alias_uuid] = $path_alias_entity;
}
}
}
}
$referenced_entities = array_values($referenced_entities);
foreach ($referenced_entities as $entity) {
if (!$this->entityManager
->isPublished($entity)) {
continue;
}
try {
$context['query_params']['include_references'] = 'false';
$referenced_entity_list_cdf = $this
->normalize($entity, $format, $context);
$referenced_entity_list_cdf = array_pop($referenced_entity_list_cdf);
if (is_array($referenced_entity_list_cdf)) {
foreach ($referenced_entity_list_cdf as $referenced_entity_cdf) {
$normalized['entities'][] = $referenced_entity_cdf;
}
}
} catch (\Exception $e) {
}
}
}
return $normalized;
}
protected function addFieldsToContentHubEntity(ContentHubEntity $contenthub_entity, ContentEntityInterface $entity, $langcode = 'und', array $context = []) {
$fields = $entity
->getFields();
$type_mapping = $this
->getFieldTypeMapping($entity);
$excluded_fields = $this
->excludedProperties($entity);
foreach ($fields as $name => $field) {
if (in_array($field
->getFieldDefinition()
->getName(), $excluded_fields) || !$field
->access('view', $context['account'])) {
continue;
}
if ($name === 'metatag') {
$serialized_field = $this
->getSerializer()
->normalize($field, 'json', $context);
}
else {
$serialized_field = $field
->getValue();
}
$items = $serialized_field;
if ($name === 'vid' && $entity
->getEntityTypeId() === 'taxonomy_term') {
if (!$contenthub_entity
->getAttribute('vocabulary')) {
$attribute = new Attribute(Attribute::TYPE_STRING);
$attribute
->setValue($items[0]['target_id'], $langcode);
$contenthub_entity
->setAttribute('vocabulary', $attribute);
}
else {
$contenthub_entity
->setAttributeValue('vocabulary', $items[0]['target_id'], $langcode);
}
continue;
}
if ($entity
->get($name)
->getFieldDefinition()
->getType() === 'path' && version_compare(\Drupal::VERSION, '8.8.0', '>=')) {
$storage = $this->entityTypeManager
->getStorage('path_alias');
$aliases = $storage
->loadByProperties([
'path' => "/{$entity->toUrl()->getInternalPath()}",
]);
if ($aliases) {
$alias_uuid_attribute = new Attribute(Attribute::TYPE_ARRAY_REFERENCE);
$uuids = [];
foreach ($aliases as $alias) {
$uuids[$alias
->language()
->getId()][] = $alias
->uuid();
}
foreach ($uuids as $uuid_langcode => $values) {
$alias_uuid_attribute
->setValue($values, $uuid_langcode);
}
$contenthub_entity
->setAttribute('path_uuid', $alias_uuid_attribute);
}
}
if ($name === 'path' && $entity
->getEntityTypeId() === 'path_alias') {
$route_params = Url::fromUserInput($entity
->getPath())
->getRouteParameters();
$target_entity_uuid_attribute = new Attribute(Attribute::TYPE_ARRAY_REFERENCE);
$target_entity_type_attribute = new Attribute(Attribute::TYPE_STRING);
foreach ($route_params as $entity_type_id => $entity_id) {
if (!$this->entityTypeManager
->hasDefinition($entity_type_id)) {
continue;
}
$entity_from_route = $this->entityTypeManager
->getStorage($entity_type_id)
->load($entity_id);
if ($entity
->getPath() !== "/{$entity_from_route->toUrl()->getInternalPath()}") {
continue;
}
$target_entity_uuid_attribute
->setValue([
$entity_from_route
->uuid(),
], $langcode);
$target_entity_type_attribute
->setValue($entity_type_id, $langcode);
}
$contenthub_entity
->setAttribute('title', (new Attribute(Attribute::TYPE_STRING))
->setValue($entity
->getAlias(), $langcode));
$contenthub_entity
->setAttribute('path_uuid', $target_entity_uuid_attribute);
$contenthub_entity
->setAttribute('target_entity_type', $target_entity_type_attribute);
}
if ($name === 'parent_id' && $entity
->getEntityTypeId() === 'paragraph') {
$attribute = new Attribute(Attribute::TYPE_STRING);
$parent_id = $items[0]['value'];
$parent_type = $fields['parent_type']
->getValue()[0]['value'];
$parent = $this->entityTypeManager
->getStorage($parent_type)
->load($parent_id);
$parent_uuid = $parent
->uuid();
$attribute
->setValue($parent_uuid, $langcode);
$contenthub_entity
->setAttribute('parent_uuid', $attribute);
continue;
}
if ($name == 'bundle' && $entity
->getEntityTypeId() === 'media') {
$attribute = new Attribute(Attribute::TYPE_ARRAY_STRING);
$attribute
->setValue([
$entity
->bundle(),
], $langcode);
$contenthub_entity
->setAttribute('bundle', $attribute);
continue;
}
$field_type = $field
->getFieldDefinition()
->getType();
$type = $type_mapping['fallback'];
if (isset($type_mapping[$name])) {
$type = $type_mapping[$name];
}
elseif (isset($type_mapping[$field_type])) {
$type = $type_mapping[$field_type];
}
if ($type == NULL) {
continue;
}
$values = [];
if ($field instanceof EntityReferenceFieldItemListInterface) {
if ($name === 'parent' && $entity
->getEntityTypeId() === 'taxonomy_term') {
$storage = $this->entityTypeManager
->getStorage('taxonomy_term');
$referenced_entities = $storage
->loadParents($entity
->id());
}
else {
$referenced_entities = $field
->referencedEntities();
}
$values[$langcode] = [];
foreach ($referenced_entities as $key => $referenced_entity) {
$file_types = [
'image',
'file',
'video',
];
$type_names = [
'type',
'bundle',
];
if (in_array($name, $type_names, TRUE) && $referenced_entity instanceof ConfigEntityBase) {
$values[$langcode][] = $referenced_entity
->id();
}
elseif (in_array($field_type, $file_types)) {
$uuid_token = '[' . $referenced_entity
->uuid() . ']';
$asset_url = file_create_url($referenced_entity
->getFileUri());
$asset = new Asset();
$asset
->setUrl($asset_url);
$asset
->setReplaceToken($uuid_token);
$contenthub_entity
->addAsset($asset);
$data = [
'alt' => isset($items[$key]['alt']) ? $items[$key]['alt'] : '',
'title' => isset($items[$key]['title']) ? $items[$key]['title'] : '',
'target_uuid' => $uuid_token,
];
$values[$langcode][] = json_encode($data, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT);
}
else {
$values[$langcode][] = $referenced_entity
->uuid();
}
}
}
else {
if ($items == NULL) {
$values[$langcode] = NULL;
}
else {
if ($link_field = ContentHubEntityLinkFieldHandler::load($field)
->validate()) {
$items = $link_field
->normalizeItems($items);
}
foreach ($items as $item) {
if (isset($item['_attributes'])) {
unset($item['_attributes']);
}
$keys = is_array($item) ? array_keys($item) : [];
if (count($keys) == 1 && isset($item['value'])) {
$value = $item['value'];
}
else {
if ($field instanceof PathFieldItemList) {
$item = $field
->first()
->getValue();
$item['pid'] = "";
$item['source'] = "";
}
$value = json_encode($item, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT);
}
$values[$langcode][] = $value;
}
}
}
try {
$attribute = new Attribute($type);
} catch (\Exception $e) {
$args['%type'] = $type;
$message = new FormattableMarkup('No type could be registered for %type.', $args);
throw new ContentHubException($message);
}
if (strstr($type, 'array')) {
$attribute
->setValues($values);
}
else {
$value = array_pop($values[$langcode]);
$attribute
->setValue($value, $langcode);
}
if (!empty($contenthub_entity
->getAttribute($name))) {
$existing_attribute = $contenthub_entity
->getAttribute($name);
$this
->appendToAttribute($existing_attribute, $attribute
->getValues());
$attribute = $existing_attribute;
}
$contenthub_entity
->setAttribute($name, $attribute);
}
$context['entity'] = $entity;
$context['langcode'] = $langcode;
$this->moduleHandler
->alter('acquia_contenthub_cdf', $contenthub_entity, $context);
$value = NULL;
if (empty($contenthub_entity
->getAttribute('url'))) {
switch ($entity
->getEntityTypeId()) {
case 'file':
$value = file_create_url($entity
->getFileUri());
$filepath_attribute = new Attribute(Attribute::TYPE_STRING);
$contenthub_entity
->setAttribute('_filepath', $filepath_attribute
->setValue($entity
->getFileUri()));
break;
default:
if (!$entity
->isNew() && $entity
->hasLinkTemplate('canonical')) {
$url = $entity
->toUrl();
$url
->setAbsolute(TRUE);
$value = $url
->toString();
}
break;
}
if (isset($value)) {
$url_attribute = new Attribute(Attribute::TYPE_STRING);
$contenthub_entity
->setAttribute('url', $url_attribute
->setValue($value, $langcode));
}
}
return $contenthub_entity;
}
public function getReferencedFields(ContentEntityInterface $entity, array $context = []) {
$content_hub_entity_type_ids = $this->entityManager
->getContentHubEntityTypeConfigurationEntities();
$bundle_key = $this->entityTypeManager
->getDefinition($entity
->getEntityTypeId())
->getKey('bundle');
$exists_entity_embed = \Drupal::moduleHandler()
->moduleExists('entity_embed');
$referenced_entities = [];
if ($entity
->getEntityTypeId() === 'taxonomy_term') {
$parents = $this->entityTypeManager
->getStorage('taxonomy_term')
->loadParents($entity
->id());
foreach ($parents as $parent) {
if ($this->entityManager
->isEligibleDependency($parent)) {
$referenced_entities[$parent
->uuid()] = $parent;
}
}
}
$excluded_fields = $this
->excludedProperties($entity);
$languages = $entity
->getTranslationLanguages();
foreach ($languages as $language) {
$langcode = $language
->getId();
$localized_entity = $entity
->getTranslation($langcode);
$fields = $localized_entity
->getFields();
foreach ($fields as $name => $field) {
$context['account'] = isset($context['account']) ? $context['account'] : NULL;
if (in_array($field
->getFieldDefinition()
->getName(), $excluded_fields) || !$field
->access('view', $context['account']) || $name === $bundle_key) {
continue;
}
if ($exists_entity_embed) {
$entity_embed_handler = new ContentHubEntityEmbedHandler($field);
if ($entity_embed_handler
->isProcessable()) {
$embed_entities = $entity_embed_handler
->getReferencedEntities();
foreach ($embed_entities as $uuid => $embedded_entity) {
$referenced_entities[$uuid] = $embedded_entity;
}
}
}
if ($link_field = ContentHubEntityLinkFieldHandler::load($field)
->validate()) {
$link_entities = $link_field
->getReferencedEntities($field
->getValue());
foreach ($link_entities as $link_entity) {
$referenced_entities[$link_entity
->uuid()] = $link_entity;
}
}
if ($field instanceof EntityReferenceFieldItemListInterface && !$field
->isEmpty()) {
$skip_entities = FALSE;
$settings = $field
->getFieldDefinition()
->getSettings();
$target_type = isset($settings['target_type']) ? $settings['target_type'] : NULL;
if (isset($settings['handler_settings']['target_bundles'])) {
$target_bundles = $settings['handler_settings']['target_bundles'];
}
else {
$target_bundles = [];
$field_entities = $field
->referencedEntities();
foreach ($field_entities as $field_entity) {
if ($field_entity instanceof EntityInterface) {
$target_bundles[] = $field_entity
->bundle();
}
}
$target_bundles = array_unique($target_bundles);
if (empty($target_bundles)) {
$target_bundles = [
$target_type,
];
}
}
if (!empty($target_type)) {
$skip_entities = TRUE;
foreach ($target_bundles as $target_bundle) {
if (isset($content_hub_entity_type_ids[$target_type]) && $content_hub_entity_type_ids[$target_type]
->isEnableIndex($target_bundle)) {
$skip_entities = FALSE;
break;
}
}
}
if (!$skip_entities) {
$field_entities = $field
->referencedEntities();
foreach ($field_entities as $field_entity) {
if ($this->entityManager
->isEligibleDependency($field_entity)) {
$referenced_entities[$field_entity
->uuid()] = $field_entity;
}
}
}
}
}
}
return $referenced_entities;
}
public function getMultilevelReferencedFields(ContentEntityInterface $entity, array &$referenced_entities, array $context = [], $depth = 0) {
$depth++;
$maximum_depth = $this->config
->get('acquia_contenthub.entity_config')
->get('dependency_depth');
$maximum_depth = is_int($maximum_depth) ? $maximum_depth : 3;
$uuids = array_keys($referenced_entities);
$ref_entities = $this
->getReferencedFields($entity, $context);
foreach ($ref_entities as $uuid => $entity) {
if (!in_array($uuid, $uuids)) {
if ($entity instanceof ContentEntityInterface) {
$referenced_entities[$uuid] = $entity;
if ($depth < $maximum_depth) {
$this
->getMultilevelReferencedFields($entity, $referenced_entities, $context, $depth);
}
}
}
}
return $referenced_entities;
}
protected function addFieldsToDrupalEntity(ContentEntityInterface $entity, ContentHubEntity $contenthub_entity, $langcode = LanguageInterface::LANGCODE_NOT_SPECIFIED, array $context = []) {
$fields = $entity
->getFields();
$excluded_fields = $this
->excludedProperties($entity);
$bundle_key = $this->entityTypeManager
->getDefinition($entity
->getEntityTypeId())
->getKey('bundle');
$excluded_fields[] = $bundle_key;
if ($entity
->hasTranslation($langcode)) {
$excluded_fields[] = 'langcode';
}
foreach ($contenthub_entity
->getAttributes() as $name => $attribute) {
$attribute = (array) $attribute;
if (in_array($name, $excluded_fields)) {
continue;
}
$file_types = [
'image',
'file',
'video',
];
$field = isset($fields[$name]) ? $fields[$name] : NULL;
if (isset($field)) {
$field_type = $field
->getFieldDefinition()
->getType();
$settings = $field
->getFieldDefinition()
->getSettings();
$value = isset($attribute['value'][$langcode]) ? $attribute['value'][$langcode] : NULL;
$field
->setValue([]);
if ($value === NULL) {
continue;
}
$field
->setLangcode($langcode);
if ($field instanceof EntityReferenceFieldItemListInterface) {
$entity_type = $settings['target_type'];
$field_item = NULL;
foreach ($value as $item) {
$item = json_decode($item, TRUE) ?: $item;
if (in_array($field_type, $file_types)) {
if (is_array($item) && isset($item['target_uuid'])) {
$uuid = $this
->removeBracketsUuid($item['target_uuid']);
$referenced_entity = $this->entityRepository
->loadEntityByUuid($entity_type, $uuid);
}
else {
$uuid = $this
->removeBracketsUuid($item);
$referenced_entity = $this->entityRepository
->loadEntityByUuid($entity_type, $uuid);
}
$field_item = $referenced_entity ? [
'alt' => isset($item['alt']) ? $item['alt'] : ($settings['alt_field_required'] ? $referenced_entity
->label() : ''),
'title' => isset($item['title']) ? $item['title'] : ($settings['title_field_required'] ? $referenced_entity
->label() : ''),
'target_id' => $referenced_entity
->id(),
] : NULL;
}
else {
$uuid = $item;
$referenced_entity = $this->entityRepository
->loadEntityByUuid($entity_type, $uuid);
$field_item = $referenced_entity;
}
if ($field_item) {
$field
->appendItem($field_item);
}
}
}
else {
if ($field instanceof FieldItemListInterface && is_array($value)) {
foreach ($value as $item) {
if (is_string($item) && isset($item[0]) && $item[0] === '{') {
$decoded = json_decode($item, TRUE);
if (json_last_error() === JSON_ERROR_NONE) {
$item = $decoded;
if ($link_field = ContentHubEntityLinkFieldHandler::load($field)
->validate()) {
$item = $link_field
->denormalizeItem($item);
}
}
}
$field
->appendItem($item);
}
}
else {
$field
->setValue($value);
}
}
}
}
return $entity;
}
public function appendToAttribute(Attribute $attribute, array $values) {
$old_values = $attribute
->getValues();
$values = array_merge($old_values, $values);
$attribute
->setValues($values);
}
public function getFieldTypeMapping(ContentEntityInterface $entity) {
$bundle_key = $this->entityTypeManager
->getDefinition($entity
->getEntityTypeId())
->getKey('bundle');
$langcode_key = $this->entityTypeManager
->getDefinition($entity
->getEntityTypeId())
->getKey('langcode');
$mapping = [];
$default_mapping = [
'string' => [
'title',
$bundle_key,
$langcode_key,
'vid',
],
'array<string>' => [
'fallback',
'text_with_summary',
'image',
'file',
'video',
],
'array<reference>' => [
'entity_reference',
'entity_reference_revisions',
],
'array<integer>' => [
'integer',
'timespan',
'timestamp',
],
'array<number>' => [
'decimal',
'float',
],
NULL => [
'password',
],
'array<boolean>' => [
'boolean',
],
];
foreach ($default_mapping as $contenthub_type => $data_types) {
foreach ($data_types as $data_type) {
$mapping[$data_type] = $contenthub_type;
}
}
$this->moduleHandler
->alter('acquia_contenthub_field_type_mapping', $mapping);
return $mapping;
}
protected function excludedProperties(ContentEntityInterface $entity) {
$excluded_fields = [
'global' => [
'created',
'changed',
'uri',
'uid',
'status',
'revision_uid',
'revision_user',
'revision_translation_affected',
'revision_timestamp',
'content_translation_uid',
'comment',
'comment_count',
'comment_count_new',
'moderation_state',
],
'node' => [
'sticky',
'promote',
],
'file' => [
'url',
],
];
$entity_type_id = $entity
->getEntityTypeId();
$entity_keys = $entity
->getEntityType()
->getKeys();
$ignored_keys = [
'uid',
'id',
'revision',
'uuid',
];
$excluded_keys = array_values(array_intersect_key($entity_keys, array_flip($ignored_keys)));
if (!isset($excluded_fields[$entity_type_id])) {
$excluded_fields[$entity_type_id] = [];
}
$excluded = array_merge($excluded_fields['global'], $excluded_fields[$entity_type_id], $excluded_keys);
$excluded_to_alter = [];
$this->moduleHandler
->alter('acquia_contenthub_exclude_fields', $excluded_to_alter, $entity);
$excluded = array_merge($excluded, $excluded_to_alter);
return array_filter($excluded);
}
public function denormalize($data, $class, $format = NULL, array $context = []) {
$context += [
'account' => NULL,
];
if (!$this
->supportsDenormalization($data, $class, $format)) {
return NULL;
}
$contenthub_entity = new ContentHubEntity($data);
$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(),
];
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);
}
}
}
}
$content_translation_source = $contenthub_entity
->getAttribute('content_translation_source');
$contenthub_entity
->removeAttribute('content_translation_source');
$site_langcodes = array_keys($this->languageManager
->getLanguages());
if (!in_array($default_langcode, $site_langcodes, TRUE)) {
$langcodes = array_intersect($site_langcodes, $langcodes);
$site_default_language = $this->languageManager
->getDefaultLanguage()
->getId();
$default_langcode = in_array($site_default_language, $langcodes, TRUE) ? $site_default_language : reset($langcodes);
}
$contenthub_entity
->removeAttribute('langcode');
$source_entity = $this->entityRepository
->loadEntityByUuid($entity_type, $contenthub_entity
->getUuid());
$this
->processPassAlias($entity_type, $contenthub_entity, $langcodes);
if ($source_entity == NULL) {
$values = [
'uuid' => $contenthub_entity
->getUuid(),
];
if ($bundle) {
$values[$bundle_key] = $bundle;
}
$values['content_translation_source'] = $content_translation_source['value'][$default_langcode][0] ?? NULL;
if (empty($values['content_translation_source'])) {
unset($values['content_translation_source']);
$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 {
$values['default_langcode'] = $default_langcode;
}
}
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;
$status = $contenthub_entity
->getAttribute('status') ? $contenthub_entity
->getAttribute('status')['value'][$default_langcode] : 0;
$values['status'] = $status ? $status : 0;
$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]);
$values[$bundle_key] = $value;
}
}
if (!empty($values[$bundle_key])) {
$contenthub_entity
->removeAttribute($bundle_key);
}
break;
case 'file':
$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 {
$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':
$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':
$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);
}
$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) {
$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);
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->languageManager
->getLanguage($langcode)) {
continue;
}
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];
$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);
}
$this->moduleHandler
->alter('acquia_contenthub_drupal_from_cdf', $entity_type, $entity);
return $entity;
}
protected function removeBracketsUuid($uuid_with_brakets) {
preg_match('#\\[(.*)\\]#', $uuid_with_brakets, $match);
$uuid = isset($match[1]) ? $match[1] : '';
if (Uuid::isValid($uuid)) {
return $uuid;
}
else {
return FALSE;
}
}
private function getVocabularyByName($vocabulary_name) {
$vocabs = Vocabulary::loadMultiple(NULL);
foreach ($vocabs as $vocab_object) {
if ($vocab_object
->getOriginalId() == $vocabulary_name) {
return $vocab_object;
}
}
return NULL;
}
private function getFilePath(ContentHubEntity $contenthub_entity) {
if ($contenthub_entity
->getType() !== 'file') {
return NULL;
}
if (!($attribute_filepath = $contenthub_entity
->getAttribute('_filepath'))) {
return NULL;
}
$uri = isset($attribute_filepath['value'][LanguageInterface::LANGCODE_NOT_SPECIFIED]) ? $attribute_filepath['value'][LanguageInterface::LANGCODE_NOT_SPECIFIED] : NULL;
if (substr($uri, 0, 9) !== 'public://') {
return NULL;
}
$file_uri = $uri;
$path = pathinfo($file_uri);
$filepath = $path['dirname'];
if (!is_dir($filepath) || !is_writable($filepath)) {
if (!\Drupal::service('file_system')
->prepareDirectory($filepath, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS)) {
$this->loggerFactory
->get('acquia_contenthub')
->error('Cannot create files subdirectory "@dir". Please check filesystem permissions.', [
'@dir' => $filepath,
]);
$file_uri = NULL;
}
}
return $file_uri;
}
private function processPassAlias(string $entity_type, ContentHubEntity $contenthub_entity, array $langcodes) {
if ($entity_type !== 'path_alias') {
return;
}
$path_uuid = $contenthub_entity
->getAttribute('path_uuid');
$target_entity_type = $contenthub_entity
->getAttribute('target_entity_type');
$path_attribute = new Attribute(Attribute::TYPE_ARRAY_STRING);
foreach ($langcodes as $langcode) {
if (empty($path_uuid['value'][$langcode])) {
continue;
}
$local_target_entity = $this->entityRepository
->loadEntityByUuid($target_entity_type['value'][$langcode], $path_uuid['value'][$langcode]);
if (empty($local_target_entity)) {
continue;
}
$local_path = '/' . ltrim($local_target_entity
->toUrl()
->getInternalPath(), '/');
$path_attribute
->setValue($local_path, $langcode);
}
$attributes = $contenthub_entity
->getAttributes();
$attributes['path'] = (array) $path_attribute;
$contenthub_entity
->setAttributes($attributes);
$contenthub_entity
->removeAttribute('title');
$contenthub_entity
->removeAttribute('path_uuid');
$contenthub_entity
->removeAttribute('target_entity_type');
}
}