You are here

class RelationshipItemNormalizer in JSON:API 8

Converts the Drupal entity reference item object to a JSON API structure.

@internal

Hierarchy

Expanded class hierarchy of RelationshipItemNormalizer

1 string reference to 'RelationshipItemNormalizer'
jsonapi.services.yml in ./jsonapi.services.yml
jsonapi.services.yml
1 service uses RelationshipItemNormalizer
serializer.normalizer.entity_reference_item.jsonapi in ./jsonapi.services.yml
Drupal\jsonapi\Normalizer\RelationshipItemNormalizer

File

src/Normalizer/RelationshipItemNormalizer.php, line 17

Namespace

Drupal\jsonapi\Normalizer
View source
class RelationshipItemNormalizer extends FieldItemNormalizer {

  /**
   * The interface or class that this Normalizer supports.
   *
   * @var string
   */
  protected $supportedInterfaceOrClass = RelationshipItem::class;

  /**
   * The JSON API resource type repository.
   *
   * @var \Drupal\jsonapi\ResourceType\ResourceTypeRepositoryInterface
   */
  protected $resourceTypeRepository;

  /**
   * Instantiates a RelationshipItemNormalizer object.
   *
   * @param \Drupal\jsonapi\ResourceType\ResourceTypeRepositoryInterface $resource_type_repository
   *   The JSON API resource type repository.
   */
  public function __construct(ResourceTypeRepositoryInterface $resource_type_repository) {
    $this->resourceTypeRepository = $resource_type_repository;
  }

  /**
   * {@inheritdoc}
   */
  public function normalize($relationship_item, $format = NULL, array $context = []) {

    /* @var $relationship_item \Drupal\jsonapi\Normalizer\RelationshipItem */

    // TODO: We are always loading the referenced entity. Even if it is not
    // going to be included. That may be a performance issue. We do it because
    // we need to know the entity type and bundle to load the JSON API resource
    // type for the relationship item. We need a better way of finding about
    // this.
    $target_entity = $relationship_item
      ->getTargetEntity();
    $values = $relationship_item
      ->getValue();
    if (isset($context['langcode'])) {
      $values['lang'] = $context['langcode'];
    }
    $host_field_name = $relationship_item
      ->getParent()
      ->getPropertyName();
    if (!empty($context['include']) && in_array($host_field_name, $context['include']) && $target_entity !== NULL) {
      $context = $this
        ->buildSubContext($context, $target_entity, $host_field_name);
      $entity_and_access = EntityResource::getEntityAndAccess($target_entity);
      $included_normalizer_value = $this->serializer
        ->normalize(new JsonApiDocumentTopLevel($entity_and_access['entity']), $format, $context);
    }
    else {
      $included_normalizer_value = NULL;
    }
    return new RelationshipItemNormalizerValue($values, new CacheableMetadata(), $relationship_item
      ->getTargetResourceType(), $included_normalizer_value);
  }

  /**
   * Builds the sub-context for the relationship include.
   *
   * @param array $context
   *   The serialization context.
   * @param \Drupal\Core\Entity\EntityInterface $entity
   *   The related entity.
   * @param string $host_field_name
   *   The name of the field reference.
   *
   * @return array
   *   The modified new context.
   */
  protected function buildSubContext(array $context, EntityInterface $entity, $host_field_name) {

    // Swap out the context for the context of the referenced resource.
    $context['resource_type'] = $this->resourceTypeRepository
      ->get($entity
      ->getEntityTypeId(), $entity
      ->bundle());

    // Since we're going one level down the only includes we need are the ones
    // that apply to this level as well.
    $include_candidates = array_filter($context['include'], function ($include) use ($host_field_name) {
      return strpos($include, $host_field_name . '.') === 0;
    });
    $context['include'] = array_map(function ($include) use ($host_field_name) {
      return str_replace($host_field_name . '.', '', $include);
    }, $include_candidates);
    $context['is_include_normalization'] = TRUE;
    return $context;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
CacheableNormalizerInterface::SERIALIZATION_CONTEXT_CACHEABILITY constant Name of key for bubbling cacheability metadata via serialization context.
FieldItemNormalizer::$formats protected property The formats that the Normalizer can handle. Overrides NormalizerBase::$formats
FieldItemNormalizer::denormalize public function
NormalizerBase::$format protected property List of formats which supports (de-)normalization. 3
NormalizerBase::addCacheableDependency protected function Adds cacheability if applicable.
NormalizerBase::checkFormat protected function Checks if the provided format is supported by this normalizer. 2
NormalizerBase::supportsDenormalization public function Implements \Symfony\Component\Serializer\Normalizer\DenormalizerInterface::supportsDenormalization() Overrides NormalizerBase::supportsDenormalization
NormalizerBase::supportsNormalization public function Checks whether the given class is supported for normalization by this normalizer. Overrides NormalizerBase::supportsNormalization
RelationshipItemNormalizer::$resourceTypeRepository protected property The JSON API resource type repository.
RelationshipItemNormalizer::$supportedInterfaceOrClass protected property The interface or class that this Normalizer supports. Overrides FieldItemNormalizer::$supportedInterfaceOrClass
RelationshipItemNormalizer::buildSubContext protected function Builds the sub-context for the relationship include.
RelationshipItemNormalizer::normalize public function This normalizer leaves JSON API normalizer land and enters the land of Drupal core's serialization system. That system was never designed with cacheability in mind, and hence bubbles cacheability out of band. This must catch it, and pass it to… Overrides FieldItemNormalizer::normalize
RelationshipItemNormalizer::__construct public function Instantiates a RelationshipItemNormalizer object.