class Relationship

Same name 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. 11.x 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 implements \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
ConfigHandler::buildForm in core/modules/views_ui/src/Form/Ajax/ConfigHandler.php
DisplayPluginBase::getFieldLabels in core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
DisplayPluginBase::validate in core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
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.