rdf_sync-1.x-dev/src/Normalizer/RdfSyncNormalizer.php

src/Normalizer/RdfSyncNormalizer.php
<?php

declare(strict_types=1);

namespace Drupal\rdf_sync\Normalizer;

use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\EntityTypeRepositoryInterface;
use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\rdf_sync\Encoder\RdfSyncEncoder;
use Drupal\rdf_sync\Event\RdfSyncNormalizeEvent;
use Drupal\rdf_sync\RdfSyncMapperInterface;
use Drupal\serialization\Normalizer\EntityNormalizer;
use EasyRdf\Literal;
use EasyRdf\RdfNamespace;
use EasyRdf\Resource;
use Psr\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Serializer\Exception\NotEncodableValueException;

/**
 * Normalizes data to an EasyRDF graph PHP representation.
 */
class RdfSyncNormalizer extends EntityNormalizer {

  public function __construct(
    EntityTypeManagerInterface $entity_type_manager,
    EntityTypeRepositoryInterface $entity_type_repository,
    EntityFieldManagerInterface $entity_field_manager,
    protected RdfSyncMapperInterface $mapper,
    protected LanguageManagerInterface $languageManager,
    protected EventDispatcherInterface $eventDispatcher,
  ) {
    parent::__construct($entity_type_manager, $entity_type_repository, $entity_field_manager);
  }

  /**
   * {@inheritdoc}
   */
  public function normalize($object, $format = NULL, array $context = []): array {
    \assert($object instanceof ContentEntityInterface);
    if (!$this->mapper->isMappedEntity(entity: $object)) {
      throw new NotEncodableValueException("Not acceptable format: $format");
    }

    $normalized = parent::normalize($object, $format, $context);

    $uriFieldName = $this->mapper->getRdfUriFieldName(entity: $object);
    $id = new Resource($object->get($uriFieldName)->value);
    $entityType = $object->getEntityType();
    unset($normalized[$entityType->getKey('id')]);
    $mappings = $this->mapper->getMappings(entity: $object);
    $rdfType = $this->mapper->getBundleRdfType(entity: $object);

    foreach ($this->mapper->getNamespaces(entity: $object) as $prefix => $namespace) {
      RdfNamespace::set($prefix, $namespace);
    }

    $rdf = [];
    if (!$hasBundleMapping = $this->mapper->hasBundleMapping($object)) {
      $rdf[$id->getUri()]['http://www.w3.org/1999/02/22-rdf-syntax-ns#type'][] = (new Resource($rdfType))->toRdfPhp();
    }

    foreach ($normalized as $fieldName => $items) {
      foreach ($items as $delta => $item) {
        foreach ($item as $columnName => $value) {
          if (!$mapping = ($mappings[$fieldName][$columnName] ?? NULL)) {
            // This column is not mapped.
            continue;
          }

          $fieldDefinition = $object->getFieldDefinition($fieldName);
          $itemDefinition = $fieldDefinition->getItemDefinition();

          if ($fieldName === $entityType->getKey('bundle')) {
            if ($hasBundleMapping) {
              // This entity has bundle mapping. Taxonomy terms, for instance,
              // need the bundle mapping to refer to the vocabulary resource.
              $value = $rdfType;
            }
          }
          // Resolve references to other entities. Cover also field types that
          // are extending entity reference.
          elseif ($columnName === 'target_id' && is_a($itemDefinition->getClass(), EntityReferenceItem::class, TRUE)) {
            /** @var \Drupal\Core\Entity\ContentEntityInterface $targetEntity */
            $targetEntity = $object->get($fieldName)->get($delta)->entity;
            if (!$targetEntity) {
              $value = NULL;
            }
            elseif ($this->mapper->isMappedEntity($targetEntity)) {
              // If the destination is also mapped, replace the scalar ID (int,
              // string) with the URI.
              $targetUriFieldName = $this->mapper->getRdfUriFieldName(entity: $targetEntity);
              $value = $targetEntity->get($targetUriFieldName)->value;
            }
          }

          if ($value === NULL) {
            // Don't store NULLs.
            continue;
          }

          // phpcs:disable
          // @todo implement transformations against values. A list of callables
          //   might be stored in $mapping. If present iterate over all and do
          //   cascade transformations against the value. Other option could be
          //   the current Inbound/OutboundValue events and subscribers.
          // phpcs:enable

          // Set the langcode of value.
          $langCode = NULL;
          if ($fieldDefinition->isTranslatable() && !$this->languageManager->isLanguageLocked($object->get($fieldName)->getLangcode())) {
            $langCode = $object->get($fieldName)->getLangcode();
          }

          $value = $mapping->type === 'resource' ? new Resource($value) : Literal::create($value, $langCode, $mapping->type);
          $predicate = new Resource($mapping->predicate);
          $rdf[$id->getUri()][$predicate->getUri()][] = $value->toRdfPhp();
        }
      }
    }

    // Allow 3rd-party to alter the normalized array.
    $event = new RdfSyncNormalizeEvent($rdf, $object, $context);
    $this->eventDispatcher->dispatch($event);

    return $event->getNormalizedArray();
  }

  /**
   * {@inheritdoc}
   */
  public function getSupportedTypes(?string $format): array {
    return [ContentEntityInterface::class => TRUE];
  }

  /**
   * {@inheritdoc}
   */
  public function supportsNormalization($data, ?string $format = NULL, array $context = []): bool {
    return $this->checkFormat($format);
  }

  /**
   * {@inheritdoc}
   */
  public function supportsDenormalization($data, string $type, ?string $format = NULL, array $context = []): bool {
    return FALSE;
  }

  /**
   * {@inheritdoc}
   */
  protected function checkFormat($format = NULL): bool {
    return isset(RdfSyncEncoder::getSupportedFormats()[$format]);
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc