Skip to main content
Drupal API
User account menu
  • Log in

Breadcrumb

  1. Drupal Core 11.1.x
  2. IncludeResolver.php

function IncludeResolver::resolveIncludeTree

Receives a tree of include field names and resolves resources for it.

This method takes a tree of relationship field names and JSON:API Data object. For the top-level of the tree and for each entity in the collection, it gets the target entity type and IDs for each relationship field. The method then loads all of those targets and calls itself recursively with the next level of the tree and those loaded resources.

Parameters

array $include_tree: The include paths, represented as a tree.

\Drupal\jsonapi\JsonApiResource\Data $data: The entity collection from which includes should be resolved.

\Drupal\jsonapi\JsonApiResource\Data|null $includes: (Internal use only) Any prior resolved includes.

Return value

\Drupal\jsonapi\JsonApiResource\Data A JSON:API Data of included items.

Throws

\Drupal\Component\Plugin\Exception\PluginNotFoundException Thrown if an included entity type doesn't exist.

\Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException Thrown if a storage handler couldn't be loaded.

1 call to IncludeResolver::resolveIncludeTree()
IncludeResolver::resolve in core/modules/jsonapi/src/IncludeResolver.php
Resolves included resources.

File

core/modules/jsonapi/src/IncludeResolver.php, line 101

Class

IncludeResolver
Resolves included resources for an entity or collection of entities.

Namespace

Drupal\jsonapi

Code

protected function resolveIncludeTree(array $include_tree, Data $data, ?Data $includes = NULL) {
    $includes = is_null($includes) ? new IncludedData([]) : $includes;
    foreach ($include_tree as $field_name => $children) {
        $references = [];
        foreach ($data as $resource_object) {
            // Some objects in the collection may be LabelOnlyResourceObjects or
            // EntityAccessDeniedHttpException objects.
            assert($resource_object instanceof ResourceIdentifierInterface);
            $public_field_name = $resource_object->getResourceType()
                ->getPublicName($field_name);
            if ($resource_object instanceof LabelOnlyResourceObject) {
                $message = "The current user is not allowed to view this relationship.";
                $exception = new EntityAccessDeniedHttpException($resource_object->getEntity(), AccessResult::forbidden("The user only has authorization for the 'view label' operation."), '', $message, $public_field_name);
                $includes = IncludedData::merge($includes, new IncludedData([
                    $exception,
                ]));
                continue;
            }
            elseif (!$resource_object instanceof ResourceObject) {
                continue;
            }
            // Not all entities in $entity_collection will be of the same bundle and
            // may not have all of the same fields. Therefore, calling
            // $resource_object->get($a_missing_field_name) will result in an
            // exception.
            if (!$resource_object->hasField($public_field_name)) {
                continue;
            }
            $field_list = $resource_object->getField($public_field_name);
            // Config entities don't have real fields and can't have relationships.
            if (!$field_list instanceof FieldItemListInterface) {
                continue;
            }
            $field_access = $field_list->access('view', NULL, TRUE);
            if (!$field_access->isAllowed()) {
                $message = 'The current user is not allowed to view this relationship.';
                $exception = new EntityAccessDeniedHttpException($field_list->getEntity(), $field_access, '', $message, $public_field_name);
                $includes = IncludedData::merge($includes, new IncludedData([
                    $exception,
                ]));
                continue;
            }
            foreach ($field_list as $field_item) {
                if (!$field_item->getDataDefinition()
                    ->getPropertyDefinition('entity') instanceof DataReferenceDefinitionInterface) {
                    continue;
                }
                if (!$field_item->entity instanceof EntityInterface) {
                    continue;
                }
                // Support entity reference fields that don't have the referenced
                // target type stored in settings.
                $references[$field_item->entity
                    ->getEntityTypeId()][] = $field_item->get($field_item::mainPropertyName())
                    ->getValue();
            }
        }
        foreach ($references as $target_type => $ids) {
            $entity_storage = $this->entityTypeManager
                ->getStorage($target_type);
            $targeted_entities = $entity_storage->loadMultiple(array_unique($ids));
            $access_checked_entities = array_map(function (EntityInterface $entity) {
                return $this->entityAccessChecker
                    ->getAccessCheckedResourceObject($entity);
            }, $targeted_entities);
            $targeted_collection = new IncludedData(array_filter($access_checked_entities, function (ResourceIdentifierInterface $resource_object) {
                return !$resource_object->getResourceType()
                    ->isInternal();
            }));
            $includes = static::resolveIncludeTree($children, $targeted_collection, IncludedData::merge($includes, $targeted_collection));
        }
    }
    return $includes;
}

API Navigation

  • Drupal Core 11.1.x
  • Topics
  • Classes
  • Functions
  • Constants
  • Globals
  • Files
  • Namespaces
  • Deprecated
  • Services
RSS feed
Powered by Drupal