class Relationship

Same name and namespace in other branches
  1. 9 core/modules/jsonapi/src/JsonApiResource/Relationship.php \Drupal\jsonapi\JsonApiResource\Relationship
  2. 8.9.x core/modules/jsonapi/src/JsonApiResource/Relationship.php \Drupal\jsonapi\JsonApiResource\Relationship
  3. 10 core/modules/jsonapi/src/JsonApiResource/Relationship.php \Drupal\jsonapi\JsonApiResource\Relationship

Represents references from one resource object to other resource object(s).

@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

  • class \Drupal\jsonapi\JsonApiResource\Relationship extends \Drupal\jsonapi\JsonApiResource\TopLevelDataInterface

Expanded class hierarchy of Relationship

See also

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

jsonapi.api.php

4 files declare their use of Relationship
EntityResource.php in core/modules/jsonapi/src/Controller/EntityResource.php
RelationshipNormalizer.php in core/modules/jsonapi/src/Normalizer/RelationshipNormalizer.php
RelationshipNormalizerTest.php in core/modules/jsonapi/tests/src/Kernel/Normalizer/RelationshipNormalizerTest.php
ResourceObjectNormalizer.php in core/modules/jsonapi/src/Normalizer/ResourceObjectNormalizer.php
28 string references to 'Relationship'
ConfigHandler::buildForm in core/modules/views_ui/src/Form/Ajax/ConfigHandler.php
Form constructor.
ConfigHandler::buildForm in core/modules/views_ui/src/Form/Ajax/ConfigHandler.php
Form constructor.
DisplayPluginBase::getFieldLabels in core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
Retrieves a list of fields for the current display.
DisplayPluginBase::validate in core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
Validate that the plugin is correct and can be saved.
DisplayTest::testMissingRelationship in core/modules/views/tests/src/Functional/Plugin/DisplayTest.php
Tests display validation when a required relationship is missing.

... See full list

File

core/modules/jsonapi/src/JsonApiResource/Relationship.php, line 22

Namespace

Drupal\jsonapi\JsonApiResource
View source
class Relationship implements TopLevelDataInterface {
  
  /**
   * The context resource object of the relationship.
   *
   * A relationship object represents references from a resource object in
   * which it’s defined to other resource objects. Respectively, the "context"
   * of the relationship and the "target(s)" of the relationship.
   *
   * A relationship object's context either comes from the resource object that
   * contains it or, in the case that the relationship object is accessed
   * directly via a relationship URL, from its `self` URL, which should identify
   * the resource to which it belongs.
   *
   * @var \Drupal\jsonapi\JsonApiResource\ResourceObject
   *
   * @see https://jsonapi.org/format/#document-resource-object-relationships
   * @see https://jsonapi.org/recommendations/#urls-relationships
   */
  protected $context;
  
  /**
   * The data of the relationship object.
   *
   * @var \Drupal\jsonapi\JsonApiResource\RelationshipData
   */
  protected $data;
  
  /**
   * The relationship's public field name.
   *
   * @var string
   */
  protected $fieldName;
  
  /**
   * The relationship object's links.
   *
   * @var \Drupal\jsonapi\JsonApiResource\LinkCollection
   */
  protected $links;
  
  /**
   * The relationship object's meta member.
   *
   * @var array
   */
  protected $meta;
  
  /**
   * Relationship constructor.
   *
   * This constructor is protected by design. To create a new relationship, use
   * static::createFromEntityReferenceField().
   *
   * @param string $public_field_name
   *   The public field name of the relationship field.
   * @param \Drupal\jsonapi\JsonApiResource\RelationshipData $data
   *   The relationship data.
   * @param \Drupal\jsonapi\JsonApiResource\LinkCollection $links
   *   Any links for the resource object, if a `self` link is not
   *   provided, one will be automatically added if the resource is locatable
   *   and is not internal.
   * @param array $meta
   *   Any relationship metadata.
   * @param \Drupal\jsonapi\JsonApiResource\ResourceObject $context
   *   The relationship's context resource object. Use the
   *   self::withContext() method to establish a context.
   *
   * @see \Drupal\jsonapi\JsonApiResource\Relationship::createFromEntityReferenceField()
   */
  protected function __construct($public_field_name, RelationshipData $data, LinkCollection $links, array $meta, ResourceObject $context) {
    $this->fieldName = $public_field_name;
    $this->data = $data;
    $this->links = $links->withContext($this);
    $this->meta = $meta;
    $this->context = $context;
  }
  
  /**
   * Creates a new Relationship from an entity reference field.
   *
   * @param \Drupal\jsonapi\JsonApiResource\ResourceObject $context
   *   The context resource object of the relationship to be created.
   * @param \Drupal\Core\Field\EntityReferenceFieldItemListInterface $field
   *   The entity reference field from which to create the relationship.
   * @param \Drupal\jsonapi\JsonApiResource\LinkCollection $links
   *   (optional) Any extra links for the Relationship, if a `self` link is not
   *   provided, one will be automatically added if the context resource is
   *   locatable and is not internal.
   * @param array $meta
   *   (optional) Any relationship metadata.
   *
   * @return static
   *   An instantiated relationship object.
   */
  public static function createFromEntityReferenceField(ResourceObject $context, EntityReferenceFieldItemListInterface $field, ?LinkCollection $links = NULL, array $meta = []) {
    $context_resource_type = $context->getResourceType();
    $resource_field = $context_resource_type->getFieldByInternalName($field->getName());
    return new static($resource_field->getPublicName(), new RelationshipData(ResourceIdentifier::toResourceIdentifiers($field), $resource_field->hasOne() ? 1 : -1), static::buildLinkCollectionFromEntityReferenceField($context, $field, $links ?: new LinkCollection([])), $meta, $context);
  }
  
  /**
   * Gets context resource object of the relationship.
   *
   * @return \Drupal\jsonapi\JsonApiResource\ResourceObject
   *   The context ResourceObject.
   *
   * @see \Drupal\jsonapi\JsonApiResource\Relationship::$context
   */
  public function getContext() {
    return $this->context;
  }
  
  /**
   * Gets the relationship object's public field name.
   *
   * @return string
   *   The relationship's field name.
   */
  public function getFieldName() {
    return $this->fieldName;
  }
  
  /**
   * Gets the relationship object's data.
   *
   * @return \Drupal\jsonapi\JsonApiResource\RelationshipData
   *   The relationship's data.
   */
  public function getData() {
    return $this->data;
  }
  
  /**
   * Gets the relationship object's links.
   *
   * @return \Drupal\jsonapi\JsonApiResource\LinkCollection
   *   The relationship object's links.
   */
  public function getLinks() {
    return $this->links;
  }
  
  /**
   * Gets the relationship object's metadata.
   *
   * @return array
   *   The relationship object's metadata.
   */
  public function getMeta() {
    return $this->meta;
  }
  
  /**
   * {@inheritdoc}
   */
  public function getOmissions() {
    return new OmittedData([]);
  }
  
  /**
   * {@inheritdoc}
   */
  public function getMergedLinks(LinkCollection $top_level_links) {
    // When directly fetching a relationship object, the relationship object's
    // links become the top-level object's links unless they've been
    // overridden. Overrides are especially important for the `self` link, which
    // must match the link that generated the response. For example, the
    // top-level `self` link might have an `include` query parameter that would
    // be lost otherwise.
    // See https://jsonapi.org/format/#fetching-relationships-responses-200 and
    // https://jsonapi.org/format/#document-top-level.
    return LinkCollection::merge($top_level_links, $this->getLinks()
      ->filter(function ($key) use ($top_level_links) {
      return !$top_level_links->hasLinkWithKey($key);
    })
      ->withContext($top_level_links->getContext()));
  }
  
  /**
   * {@inheritdoc}
   */
  public function getMergedMeta(array $top_level_meta) {
    return NestedArray::mergeDeep($top_level_meta, $this->getMeta());
  }
  
  /**
   * Builds a LinkCollection for the given entity reference field.
   *
   * @param \Drupal\jsonapi\JsonApiResource\ResourceObject $context
   *   The context resource object of the relationship object.
   * @param \Drupal\Core\Field\EntityReferenceFieldItemListInterface $field
   *   The entity reference field from which to create the links.
   * @param \Drupal\jsonapi\JsonApiResource\LinkCollection $links
   *   Any extra links for the Relationship, if a `self` link is not provided,
   *   one will be automatically added if the context resource is locatable and
   *   is not internal.
   *
   * @return \Drupal\jsonapi\JsonApiResource\LinkCollection
   *   The built links.
   */
  protected static function buildLinkCollectionFromEntityReferenceField(ResourceObject $context, EntityReferenceFieldItemListInterface $field, LinkCollection $links) {
    $context_resource_type = $context->getResourceType();
    $public_field_name = $context_resource_type->getPublicName($field->getName());
    if ($context_resource_type->isLocatable() && !$context_resource_type->isInternal()) {
      $context_is_versionable = $context_resource_type->isVersionable();
      if (!$links->hasLinkWithKey('self')) {
        $route_name = Routes::getRouteName($context_resource_type, "{$public_field_name}.relationship.get");
        $self_link = Url::fromRoute($route_name, [
          'entity' => $context->getId(),
        ]);
        if ($context_is_versionable) {
          $self_link->setOption('query', [
            JsonApiSpec::VERSION_QUERY_PARAMETER => $context->getVersionIdentifier(),
          ]);
        }
        $links = $links->withLink('self', new Link(new CacheableMetadata(), $self_link, 'self'));
      }
      $has_non_internal_resource_type = array_reduce($context_resource_type->getRelatableResourceTypesByField($public_field_name), function ($carry, ResourceType $target) {
        return $carry ?: !$target->isInternal();
      }, FALSE);
      // If a `related` link was not provided, automatically generate one from
      // the relationship object to the collection resource with all of the
      // resources targeted by this relationship. However, that link should
      // *not* be generated if all of the relatable resources are internal.
      // That's because, in that case, a route will not exist for it.
      if (!$links->hasLinkWithKey('related') && $has_non_internal_resource_type) {
        $route_name = Routes::getRouteName($context_resource_type, "{$public_field_name}.related");
        $related_link = Url::fromRoute($route_name, [
          'entity' => $context->getId(),
        ]);
        if ($context_is_versionable) {
          $related_link->setOption('query', [
            JsonApiSpec::VERSION_QUERY_PARAMETER => $context->getVersionIdentifier(),
          ]);
        }
        $links = $links->withLink('related', new Link(new CacheableMetadata(), $related_link, 'related'));
      }
    }
    return $links;
  }

}

Members

Title Sort descending Modifiers Object type Summary Overriden Title
Relationship::$context protected property The context resource object of the relationship.
Relationship::$data protected property The data of the relationship object.
Relationship::$fieldName protected property The relationship's public field name.
Relationship::$links protected property The relationship object's links.
Relationship::$meta protected property The relationship object's meta member.
Relationship::buildLinkCollectionFromEntityReferenceField protected static function Builds a LinkCollection for the given entity reference field.
Relationship::createFromEntityReferenceField public static function Creates a new Relationship from an entity reference field.
Relationship::getContext public function Gets context resource object of the relationship.
Relationship::getData public function Gets the relationship object's data. Overrides TopLevelDataInterface::getData
Relationship::getFieldName public function Gets the relationship object's public field name.
Relationship::getLinks public function Gets the relationship object's links.
Relationship::getMergedLinks public function Overrides TopLevelDataInterface::getMergedLinks
Relationship::getMergedMeta public function Overrides TopLevelDataInterface::getMergedMeta
Relationship::getMeta public function Gets the relationship object's metadata.
Relationship::getOmissions public function Overrides TopLevelDataInterface::getOmissions
Relationship::__construct protected function Relationship constructor.

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.