contentserialize-8.x-1.x-dev/modules/vcsnormalizer/src/Normalizer/UuidEntityReferenceFieldItemNormalizer.php
modules/vcsnormalizer/src/Normalizer/UuidEntityReferenceFieldItemNormalizer.php
<?php
namespace Drupal\vcsnormalizer\Normalizer;
use Drupal\contentserialize\Event\ImportEvents;
use Drupal\contentserialize\Event\MissingReferenceEvent;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
use Drupal\serialization\EntityResolver\EntityResolverInterface;
use Drupal\serialization\EntityResolver\UuidReferenceInterface;
use Drupal\serialization\Normalizer\FieldItemNormalizer;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
/**
* (De)-normalizes entity reference fields replacing serial IDs with UUIDs.
*
* It uses a UUID resolver rather than an entity repository.
*
* @see \Drupal\serialization\EntityResolver\UuidResolver
*/
class UuidEntityReferenceFieldItemNormalizer extends FieldItemNormalizer implements UuidReferenceInterface {
/**
* The interface or class that this Normalizer supports.
*
* @var string
*/
protected $supportedInterfaceOrClass = EntityReferenceItem::class;
/**
* The UUID entity resolver.
*
* @var \Drupal\serialization\EntityResolver\EntityResolverInterface
*/
protected $uuidResolver;
/**
* The event dispatcher service.
*
* @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
*/
protected $eventDispatcher;
/**
* Create a UuidEntityReferenceFieldItemDenormalizer.
*
* @param \Drupal\serialization\EntityResolver\EntityResolverInterface $uuid_resolver
* The UUID entity resolver.
* @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
* The event dispatcher service.
*/
public function __construct(
EntityResolverInterface $uuid_resolver,
EventDispatcherInterface $event_dispatcher
) {
$this->uuidResolver = $uuid_resolver;
$this->eventDispatcher = $event_dispatcher;
}
/**
* {@inheritdoc}
*/
public function normalize($field_item, $format = NULL, array $context = []) {
$values = parent::normalize($field_item, $format, $context);
/** @var \Drupal\Core\Entity\EntityInterface $entity */
$entity = $field_item->get('entity')->getValue();
if (!$entity) {
return $values;
}
$values['target_type'] = $entity->getEntityTypeId();
$uuid = $entity->uuid();
if ($uuid) {
unset($values['target_id'], $values['target_revision_id']);
$values['target_uuid'] = $uuid;
}
return $values;
}
/**
* {@inheritdoc}
*/
protected function constructValue($data, $context) {
// @todo Do I need the check on target_id below?
if (!isset($data['target_id'])) {
$id = $this->uuidResolver->resolve($this, $data, $data['target_type']);
if ($id) {
$data['target_id'] = $id;
}
else {
/** @var EntityReferenceItem $field */
$field = $context['target_instance'];
$entity = $field->getEntity();
$field_name = $field->getFieldDefinition()->getName();
$field_type = $field->getFieldDefinition()->getType();
$delta = $field->getName();
// Creating a closure for every delta isn't the quickest or most memory
// efficient method, but it's flexible and understandable.
// @todo Remove the special casing of entity reference revisions once
// #2667748 lands.
if ($field_type == 'entity_reference_revisions') {
$update_reference = function (ContentEntityInterface $entity, $target_id, $target_vid) use ($field_name, $field_type, $delta) {
$entity->{$field_name}[$delta] = [
'target_id' => $target_id,
'target_revision_id' => $target_vid,
];
};
}
else {
$update_reference = function (ContentEntityInterface $entity, $target_id, $target_vid) use ($field_name, $field_type, $delta) {
$entity->{$field_name}[$delta] = $target_id;
};
}
$event = new MissingReferenceEvent(
$entity->getEntityTypeId(),
$entity->uuid(),
$data['target_type'],
$data['target_uuid'],
$update_reference,
$context
);
$this->eventDispatcher->dispatch(ImportEvents::MISSING_REFERENCE, $event);
}
}
return parent::constructValue($data, $context);
}
/**
* {@inheritdoc}
*/
public function getUuid($data) {
return empty($data['target_id']) ? NULL : $data['target_id'];
}
}
