contentserialize-8.x-1.x-dev/modules/vcsnormalizer/src/Normalizer/LinkNormalizer.php

modules/vcsnormalizer/src/Normalizer/LinkNormalizer.php
<?php

namespace Drupal\vcsnormalizer\Normalizer;

use Drupal\Component\Uuid\Uuid;
use Drupal\contentserialize\Event\ImportEvents;
use Drupal\contentserialize\Event\MissingReferenceEvent;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\link\Plugin\Field\FieldType\LinkItem;
use Drupal\menu_link_content\MenuLinkContentInterface;
use Drupal\serialization\Normalizer\NormalizerBase;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;

/**
 * Normalizes link field items preserving node links.
 */
class LinkNormalizer extends NormalizerBase implements DenormalizerInterface {

  /**
   * {@inheritdoc}
   */
  protected $supportedInterfaceOrClass = LinkItem::class;

  /**
   * The field item normalizer service.
   *
   * It's contained rather than extended to avoid backwards-compatibility
   * problems.
   *
   * @var \Symfony\Component\Serializer\Normalizer\NormalizerInterface|\Symfony\Component\Serializer\Normalizer\DenormalizerInterface
   */
  protected $fieldItemNormalizer;

  /**
   * The node storage provider if available.
   *
   * @var \Drupal\node\NodeStorageInterface|null
   */
  protected $nodeStorage;

  /**
   * The event dispatcher service.
   *
   * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
   */
  protected $eventDispatcher;

  /**
   * Create the link normalizer.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager service.
   * @param \Symfony\Component\Serializer\Normalizer\NormalizerInterface $field_item_normalizer
   *   The field item normalizer service.
   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
   *   The event dispatcher service.
   */
  public function __construct(EntityTypeManagerInterface $entity_type_manager, NormalizerInterface $field_item_normalizer, EventDispatcherInterface $event_dispatcher) {
    // The object just acts as a transparent proxy if nodes aren't available.
    if ($entity_type_manager->getDefinition('node', FALSE)) {
      $this->nodeStorage = $entity_type_manager->getStorage('node');
    }
    $this->fieldItemNormalizer = $field_item_normalizer;
    $this->eventDispatcher = $event_dispatcher;
  }

  /**
   * {@inheritdoc}
   */
  public function normalize($object, $format = NULL, array $context = []) {
    $data = $this->fieldItemNormalizer->normalize($object, $format, $context);
    // Don't do anything special if the node module isn't installed.
    if ($this->nodeStorage) {
      $data = $this->replaceLinkId($data, '\d+', function ($nid) {
        $node = $this->nodeStorage->load($nid);
        if (!$node) {
          throw new UnexpectedValueException("Menu link content has link to non-existant node $nid");
        }
        return $node->uuid();
      });
    }
    return $data;
  }

  /**
   * {@inheritdoc}
   */
  public function denormalize($data, $class, $format = NULL, array $context = []) {
    if (!isset($context['target_instance'])) {
      throw new InvalidArgumentException('$context[\'target_instance\'] must be set to denormalize with the FieldItemNormalizer');
    }

    if ($context['target_instance']->getParent() == NULL) {
      throw new InvalidArgumentException('The field item passed in via $context[\'target_instance\'] must have a parent set.');
    }

    // Don't do anything special if the node module isn't installed.
    if ($this->nodeStorage) {
      /** @var \Drupal\link\LinkItemInterface $field_item */
      $field_item = $context['target_instance'];
      $parent = $field_item->getParent()->getParent()->getValue();

      $data = $this->replaceLinkId($data, Uuid::VALID_PATTERN, function ($uuid) use ($parent, $context) {
        $results = $this->nodeStorage->getQuery()
          ->condition('uuid', $uuid)
          ->execute();
        if (!$results) {
          // If it's not found dispatch an event and return an empty value.
          if (($parent instanceof ContentEntityInterface)) {
            $event = new MissingReferenceEvent(
              $parent->getEntityTypeId(),
              $parent->uuid(),
              'node',
              $uuid,
              function (MenuLinkContentInterface $entity, $target_id, $target_vid) {
                $entity->link = 'entity:node/' . $target_id;
              },
              $context
            );
            $this->eventDispatcher->dispatch(ImportEvents::MISSING_REFERENCE, $event);
          }

          return '';
        }

        return current($results);
      });
    }

    return $this->fieldItemNormalizer->denormalize($data, $class, $format, $context);
  }

  /**
   * Replace the ID in a link to a node.
   *
   * @param array $data
   *   The normalized array for the menu_link_content entity.
   * @param $pattern_fragment
   *   A regular expression fragment that will match the ID.
   * @param callable $callback
   *   A callable that accepts the ID currently in the link and returns the new
   *   ID to be used.
   *
   * @return array
   *   The updated normalized array for the menu_link_content_entity.
   */
  protected function replaceLinkId(array $data, $pattern_fragment, callable $callback) {
    $uri = preg_replace_callback('~^(entity:node/)(' . $pattern_fragment . ')$~', function ($matches) use ($callback) {
      return $matches[1] . $callback($matches[2]);
    }, $data['uri']);
    if ($uri == 'entity:node/') {
      // @todo Log this?
      $uri = 'route:<nolink>';
    }
    $data['uri'] = $uri;
    return $data;
  }

}

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

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