You are here

class EntityReferenceFieldNormalizer in JSON:API 8.2

Same name and namespace in other branches
  1. 8 src/Normalizer/EntityReferenceFieldNormalizer.php \Drupal\jsonapi\Normalizer\EntityReferenceFieldNormalizer

Normalizer class specific for entity reference field objects.

@internal JSON:API maintains no PHP API since its API is the HTTP API. This class may change at any time and this will break any dependencies on it.

Hierarchy

Expanded class hierarchy of EntityReferenceFieldNormalizer

See also

https://www.drupal.org/project/jsonapi/issues/3032787

jsonapi.api.php

2 files declare their use of EntityReferenceFieldNormalizer
EntityReferenceFieldNormalizerTest.php in tests/src/Kernel/Normalizer/EntityReferenceFieldNormalizerTest.php
EntityResource.php in src/Controller/EntityResource.php
1 string reference to 'EntityReferenceFieldNormalizer'
jsonapi.services.yml in ./jsonapi.services.yml
jsonapi.services.yml
1 service uses EntityReferenceFieldNormalizer
serializer.normalizer.entity_reference_field.jsonapi in ./jsonapi.services.yml
Drupal\jsonapi\Normalizer\EntityReferenceFieldNormalizer

File

src/Normalizer/EntityReferenceFieldNormalizer.php, line 24

Namespace

Drupal\jsonapi\Normalizer
View source
class EntityReferenceFieldNormalizer extends FieldNormalizer {

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

  /**
   * {@inheritdoc}
   */
  public function normalize($field, $format = NULL, array $context = []) {
    assert($field instanceof EntityReferenceFieldItemListInterface);

    // Build the relationship object based on the Entity Reference and normalize
    // that object instead.
    $definition = $field
      ->getFieldDefinition();
    $cardinality = $definition
      ->getFieldStorageDefinition()
      ->getCardinality();
    $resource_identifiers = array_filter(ResourceIdentifier::toResourceIdentifiers($field
      ->filterEmptyItems()), function (ResourceIdentifierInterface $resource_identifier) {
      return !$resource_identifier
        ->getResourceType()
        ->isInternal();
    });
    $context['field_name'] = $field
      ->getName();
    $normalized_items = CacheableNormalization::aggregate($this->serializer
      ->normalize($resource_identifiers, $format, $context));
    assert($context['resource_object'] instanceof ResourceObject);
    $link_cacheability = new CacheableMetadata();
    $links = array_map(function (Url $link) use ($link_cacheability) {
      $href = $link
        ->setAbsolute()
        ->toString(TRUE);
      $link_cacheability
        ->addCacheableDependency($href);
      return [
        'href' => $href
          ->getGeneratedUrl(),
      ];
    }, static::getRelationshipLinks($context['resource_object'], $field
      ->getName()));
    $data_normalization = $normalized_items
      ->getNormalization();
    $normalization = [
      // Empty 'to-one' relationships must be NULL.
      // Empty 'to-many' relationships must be an empty array.
      // @link http://jsonapi.org/format/#document-resource-object-linkage
      'data' => $cardinality === 1 ? array_shift($data_normalization) : $data_normalization,
    ];
    if (!empty($links)) {
      $normalization['links'] = $links;
    }
    return (new CacheableNormalization($normalized_items, $normalization))
      ->withCacheableDependency($link_cacheability);
  }

  /**
   * Gets the links for the relationship.
   *
   * @param \Drupal\jsonapi\JsonApiResource\ResourceObject $relationship_context
   *   The JSON:API resource object context of the relationship.
   * @param string $relationship_field_name
   *   The internal relationship field name.
   *
   * @return array
   *   The relationship's links.
   */
  public static function getRelationshipLinks(ResourceObject $relationship_context, $relationship_field_name) {
    $resource_type = $relationship_context
      ->getResourceType();
    if ($resource_type
      ->isInternal() || !$resource_type
      ->isLocatable()) {
      return [];
    }
    $public_field_name = $resource_type
      ->getPublicName($relationship_field_name);
    $relationship_route_name = Routes::getRouteName($resource_type, "{$public_field_name}.relationship.get");
    $links = [
      'self' => Url::fromRoute($relationship_route_name, [
        'entity' => $relationship_context
          ->getId(),
      ]),
    ];
    if (static::hasNonInternalResourceType($resource_type
      ->getRelatableResourceTypesByField($public_field_name))) {
      $related_route_name = Routes::getRouteName($resource_type, "{$public_field_name}.related");
      $links['related'] = Url::fromRoute($related_route_name, [
        'entity' => $relationship_context
          ->getId(),
      ]);
    }
    if ($resource_type
      ->isVersionable()) {
      $version_query_parameter = [
        JsonApiSpec::VERSION_QUERY_PARAMETER => $relationship_context
          ->getVersionIdentifier(),
      ];
      $links['self']
        ->setOption('query', $version_query_parameter);
      if (isset($links['related'])) {
        $links['related']
          ->setOption('query', $version_query_parameter);
      }
    }
    return $links;
  }

  /**
   * Determines if a given list of resource types contains a non-internal type.
   *
   * @param \Drupal\jsonapi\ResourceType\ResourceType[] $resource_types
   *   The JSON:API resource types to evaluate.
   *
   * @return bool
   *   FALSE if every resource type is internal, TRUE otherwise.
   */
  protected static function hasNonInternalResourceType(array $resource_types) {
    foreach ($resource_types as $resource_type) {
      if (!$resource_type
        ->isInternal()) {
        return TRUE;
      }
    }
    return FALSE;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
CacheableNormalizerInterface::SERIALIZATION_CONTEXT_CACHEABILITY constant Name of key for bubbling cacheability metadata via serialization context.
EntityReferenceFieldNormalizer::$supportedInterfaceOrClass protected property The interface or class that this Normalizer supports. Overrides FieldNormalizer::$supportedInterfaceOrClass
EntityReferenceFieldNormalizer::getRelationshipLinks public static function Gets the links for the relationship.
EntityReferenceFieldNormalizer::hasNonInternalResourceType protected static function Determines if a given list of resource types contains a non-internal type.
EntityReferenceFieldNormalizer::normalize public function Normalizes an object into a set of arrays/scalars. Overrides FieldNormalizer::normalize
FieldNormalizer::denormalize public function Denormalizes data back into an object of the given class.
FieldNormalizer::normalizeFieldItems protected function Helper function to normalize field items.
NormalizerBase::$format protected property List of formats which supports (de-)normalization. Overrides NormalizerBase::$format
NormalizerBase::addCacheableDependency protected function Adds cacheability if applicable.
NormalizerBase::checkFormat protected function Checks if the provided format is supported by this normalizer. Overrides NormalizerBase::checkFormat
NormalizerBase::rasterizeValueRecursive protected static function Rasterizes a value recursively.
NormalizerBase::supportsDenormalization public function Implements \Symfony\Component\Serializer\Normalizer\DenormalizerInterface::supportsDenormalization() 1
NormalizerBase::supportsNormalization public function Checks whether the given class is supported for normalization by this normalizer. 1