View source
<?php
namespace Drupal\content_sync\Importer;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\serialization\Normalizer\SerializedColumnNormalizerTrait;
use Symfony\Component\Serializer\Serializer;
class ContentImporter implements ContentImporterInterface {
use SerializedColumnNormalizerTrait;
protected $format = 'yaml';
protected $updateEntities = TRUE;
protected $context = [];
protected $serializer;
protected $entityTypeManager;
public function __construct(Serializer $serializer, EntityTypeManagerInterface $entity_type_manager) {
$this->serializer = $serializer;
$this->entityTypeManager = $entity_type_manager;
}
public function importEntity($decoded_entity, $context = []) {
$context = $this->context + $context;
if (!empty($context['entity_type'])) {
$entity_type_id = $context['entity_type'];
}
elseif (!empty($decoded_entity['_content_sync']['entity_type'])) {
$entity_type_id = $decoded_entity['_content_sync']['entity_type'];
}
else {
return NULL;
}
if ($entity_type_id == 'menu_link_content' && !empty($decoded_entity["_content_sync"]["menu_entity_link"])) {
$decoded_entity = $this
->alterMenuLink($decoded_entity);
}
$entity_type = $this->entityTypeManager
->getDefinition($entity_type_id);
if ($entity_type_id == 'taxonomy_term') {
if (empty($decoded_entity['parent'])) {
$decoded_entity['parent']['target_id'] = 0;
}
}
if (!empty($decoded_entity['_translations'])) {
$entity_translations = $decoded_entity['_translations'];
}
$entity = $this->serializer
->denormalize($decoded_entity, $entity_type
->getClass(), $this->format, $context);
if (!empty($entity)) {
if ($entity_type_id == 'user' && !$entity
->isNew() && (int) $entity
->id() === 0) {
return $entity;
}
$entity = $this
->syncEntity($entity);
}
if ($entity) {
if (isset($entity_translations) && is_array($entity_translations)) {
$this
->updateTranslation($entity, $entity_type, $entity_translations, $context);
}
}
return $entity;
}
protected function updateTranslation(&$entity, $entity_type, $entity_translations, $context) {
foreach ($entity_translations as $langcode => $translation) {
$translation = $this->serializer
->denormalize($translation, $entity_type
->getClass(), $this->format, $context);
$entity_translation = $entity
->hasTranslation($langcode) ? $entity
->getTranslation($langcode) : $entity
->addTranslation($langcode);
$fields = $translation
->getFieldDefinitions();
foreach ($translation as $itemID => $item) {
if ($entity_translation
->hasField($itemID)) {
if ($fields[$itemID]
->isTranslatable() == TRUE) {
$entity_translation->{$itemID}
->setValue($item
->getValue());
}
}
}
if ($entity_translation
->getEntityType()
->hasKey('revision')) {
$entity_translation
->updateLoadedRevisionId();
$entity_translation
->setNewRevision(FALSE);
}
$entity_translation
->save();
}
}
protected function alterMenuLink(array $decoded_entity) {
$referenced_entity_uuid = reset($decoded_entity["_content_sync"]["menu_entity_link"]);
$referenced_entity_type = key($decoded_entity["_content_sync"]["menu_entity_link"]);
if (!preg_match('/^internal:/', $decoded_entity["link"][0]["uri"]) && ($referenced_entity = \Drupal::service('entity.repository')
->loadEntityByUuid($referenced_entity_type, $referenced_entity_uuid))) {
$url = $referenced_entity
->toUrl();
if ($url
->isRouted()) {
$route_name = $url
->getRouteName();
foreach (array_keys($this->entityTypeManager
->getDefinitions()) as $entity_type_id) {
if ($route_name == "entity.{$entity_type_id}.canonical" && isset($url
->getRouteParameters()[$entity_type_id])) {
$uri = "entity:{$entity_type_id}/" . $url
->getRouteParameters()[$entity_type_id];
}
}
}
else {
$uri = $url
->getUri();
}
$decoded_entity["link"][0]["uri"] = $uri;
}
return $decoded_entity;
}
public function getFormat() {
return $this->format;
}
protected function syncEntity(ContentEntityInterface $entity) {
$preparedEntity = $this
->prepareEntity($entity);
if ($this
->validateEntity($preparedEntity)) {
$preparedEntity
->save();
return $preparedEntity;
}
elseif (!$preparedEntity
->isNew()) {
return $preparedEntity;
}
return NULL;
}
protected function processSerializedFields($entity) {
foreach ($entity
->getTypedData() as $name => $field_items) {
foreach ($field_items as $field_item) {
if (!empty($this
->getCustomSerializedPropertyNames($field_item))) {
$unserialized_value = $field_item
->get('value')
->getValue();
$entity
->set($name, is_array($unserialized_value) ? serialize($unserialized_value) : $unserialized_value);
}
}
}
return $entity;
}
public function prepareEntity(ContentEntityInterface $entity) {
$uuid = $entity
->uuid();
$original_entity = $this->entityTypeManager
->getStorage($entity
->getEntityTypeId())
->loadByProperties([
'uuid' => $uuid,
]);
if (!empty($original_entity)) {
$original_entity = reset($original_entity);
if (!$this->updateEntities) {
return $original_entity;
}
if (!empty($entity->_restSubmittedFields)) {
foreach ($entity->_restSubmittedFields as $field_name) {
if ($this
->isValidEntityField($original_entity, $entity, $field_name)) {
$original_entity
->set($field_name, $entity
->get($field_name)
->getValue());
}
}
}
return $this
->processSerializedFields($original_entity);
}
$duplicate = $entity
->createDuplicate();
$entity_type = $entity
->getEntityType();
$duplicate->{$entity_type
->getKey('uuid')}->value = $uuid;
return $this
->processSerializedFields($duplicate);
}
protected function isValidEntityField(ContentEntityInterface $original_entity, ContentEntityInterface $entity, $field_name) {
$valid = TRUE;
$entity_keys = $entity
->getEntityType()
->getKeys();
if (!$entity
->hasField($field_name)) {
$valid = FALSE;
}
elseif (in_array($field_name, $entity_keys, TRUE)) {
if ($original_entity
->get($field_name)
->getValue() === $entity
->get($field_name)
->getValue() || isset($entity_keys['langcode']) && $field_name === $entity_keys['langcode'] && $entity
->get($field_name)
->isEmpty() || $field_name === $entity
->getEntityType()
->getKey('id') || $entity
->getEntityType()
->isRevisionable() && $field_name === $entity
->getEntityType()
->getKey('revision')) {
$valid = FALSE;
}
}
return $valid;
}
public function validateEntity(ContentEntityInterface $entity) {
$reflection = new \ReflectionClass($entity);
$valid = TRUE;
if ($reflection
->implementsInterface('\\Drupal\\user\\UserInterface')) {
$validations = $entity
->validate();
if (count($validations)) {
foreach ($validations as $validation) {
if (!empty($this
->getContext()['skipped_constraints']) && in_array(get_class($validation
->getConstraint()), $this
->getContext()['skipped_constraints'])) {
continue;
}
$valid = FALSE;
\Drupal::logger('content_sync')
->error($validation
->getMessage());
}
}
}
return $valid;
}
public function getContext() {
return $this->context;
}
public function setContext($context) {
$this->context = $context;
}
}