View source
<?php
declare (strict_types=1);
namespace Drupal\entity_share_diff\Service;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\entity_share\EntityShareUtility;
use Drupal\entity_share_client\Entity\RemoteInterface;
use Drupal\entity_share_client\Service\EntityReferenceHelper;
use Drupal\entity_share_client\Service\JsonapiHelperInterface;
use Drupal\entity_share_client\Service\RemoteManagerInterface;
use Drupal\entity_share_diff\DiffGenerator\DiffGeneratorPluginManager;
use Drupal\jsonapi\ResourceType\ResourceType;
use Drupal\jsonapi\ResourceType\ResourceTypeRepositoryInterface;
class EntityParser implements EntityParserInterface {
protected $diffGeneratorManager;
protected $languageManager;
protected $remoteManager;
protected $jsonapiHelper;
protected $resourceTypeRepository;
protected $entityReferenceHelper;
protected $remote;
private $processedEntities;
public function __construct(DiffGeneratorPluginManager $diff_generator_manager, LanguageManagerInterface $language_manager, RemoteManagerInterface $remote_manager, JsonapiHelperInterface $jsonapi_helper, ResourceTypeRepositoryInterface $resource_type_repository, EntityReferenceHelper $entity_reference_helper) {
$this->diffGeneratorManager = $diff_generator_manager;
$this->languageManager = $language_manager;
$this->remoteManager = $remote_manager;
$this->jsonapiHelper = $jsonapi_helper;
$this->resourceTypeRepository = $resource_type_repository;
$this->entityReferenceHelper = $entity_reference_helper;
$this->processedEntities = [
'local' => [],
'remote' => [],
];
}
public function getRemote() {
return $this->remote;
}
public function setRemote($remote) {
$this->remote = $remote;
}
public function prepareLocalEntity(ContentEntityInterface $entity) {
$this
->setRemote(FALSE);
return $this
->parseEntity($entity);
}
public function prepareRemoteEntity(array $remote_data, RemoteInterface $remote) {
$this
->setRemote($remote);
$remote_entity = $this->jsonapiHelper
->extractEntity($remote_data);
return $this
->parseEntity($remote_entity, $remote_data);
}
public function validateNeedToProcess(string $uuid, bool $remote) {
$main_key = $remote ? 'remote' : 'local';
if (!in_array($uuid, $this->processedEntities[$main_key])) {
$this->processedEntities[$main_key][] = $uuid;
return TRUE;
}
return FALSE;
}
public function getPublicFieldName(string $field_name, array $entity_json_data) {
if (empty($entity_json_data['type'])) {
return '';
}
$parsed_type = explode('--', $entity_json_data['type']);
$entity_type_id = $parsed_type[0];
$bundle = $parsed_type[1];
$resource_type = $this->resourceTypeRepository
->get($entity_type_id, $bundle);
if (!$resource_type instanceof ResourceType) {
return '';
}
if (!$resource_type
->hasField($field_name)) {
return '';
}
return $resource_type
->getPublicName($field_name);
}
public function getRemoteChangedTime(array $remote_data) {
$changed_public_name = $this
->getPublicFieldName('changed', $remote_data);
$entity_changed_time = 0;
if ($changed_public_name && !empty($remote_data['attributes'][$changed_public_name])) {
$entity_changed_time = EntityShareUtility::convertChangedTime($remote_data['attributes'][$changed_public_name]);
}
return $entity_changed_time;
}
protected function parseEntity(ContentEntityInterface $entity, array $remote_data = NULL) {
$result = [];
$langcode = $this->languageManager
->getCurrentLanguage(LanguageInterface::TYPE_CONTENT)
->getId();
if ($entity
->hasTranslation($langcode)) {
$entity = $entity
->getTranslation($langcode);
}
$irrelevant_fields = $this
->getFieldsIrrelevantForDiff($entity);
foreach ($entity as $item_key => $field_items) {
if ($this
->getRemote()) {
$public_key = $this
->getPublicFieldName($item_key, $remote_data);
}
else {
$public_key = $item_key;
}
$remote_field_data = [];
switch ($this->entityReferenceHelper
->relationshipHandleable($field_items)) {
case EntityReferenceHelper::RELATIONSHIP_HANDLEABLE:
$should_parse = TRUE;
if (isset($remote_data['relationships'][$public_key])) {
$remote_field_data = $remote_data['relationships'][$public_key];
if (isset($remote_field_data['data'])) {
$remote_field_data['data'] = EntityShareUtility::prepareData($remote_field_data['data']);
}
}
break;
case EntityReferenceHelper::RELATIONSHIP_NOT_HANDLEABLE:
$should_parse = FALSE;
break;
case EntityReferenceHelper::RELATIONSHIP_NOT_ENTITY_REFERENCE:
$should_parse = !in_array($item_key, $irrelevant_fields);
break;
}
if (!$should_parse) {
continue;
}
$parsed_field = $this
->parseField($item_key, $field_items, $remote_field_data);
if ($parsed_field != NULL) {
$field_label = (string) $field_items
->getFieldDefinition()
->getLabel();
$result[$field_label] = $parsed_field;
}
}
return $result;
}
protected function parseField(string $item_key, FieldItemListInterface $field_items, array $remote_field_data = []) {
$build = [];
$field_type = $field_items
->getFieldDefinition()
->getType();
$plugin = $this->diffGeneratorManager
->createInstanceForFieldDefinition($field_type);
if ($plugin) {
$remote = $this
->getRemote();
if ($remote) {
$plugin
->setRemote($remote);
}
$build = $plugin
->build($field_items, $remote_field_data);
if (!empty($build)) {
$cardinality = $field_items
->getFieldDefinition()
->getFieldStorageDefinition()
->getCardinality();
if ($cardinality == 1 && is_array($build)) {
$build = current($build);
}
}
}
return $build;
}
public function referenceEmbeddable(string $entity_type_id) {
$embeddable_types = [
'paragraph',
'media',
];
return in_array($entity_type_id, $embeddable_types);
}
protected function getFieldsIrrelevantForDiff(ContentEntityInterface $entity) {
$entity_keys = $entity
->getEntityType()
->getKeys();
unset($entity_keys['label']);
unset($entity_keys['langcode']);
$field_names = array_values($entity_keys);
$revision_keys = array_keys($entity
->getEntityType()
->getRevisionMetadataKeys());
$field_names = array_merge($field_names, $revision_keys);
$other_keys = [
'changed',
'created',
'content_translation_source',
'content_translation_affected',
'content_translation_outdated',
'revision_translation_affected',
'parent_id',
'parent_type',
'parent_field_name',
'revision_timestamp',
'revision_log',
];
$field_names = array_merge($field_names, $other_keys);
return $field_names;
}
}