function ResourceVersionRouteEnhancer::enhance

Same name in other branches
  1. 9 core/modules/jsonapi/src/Revisions/ResourceVersionRouteEnhancer.php \Drupal\jsonapi\Revisions\ResourceVersionRouteEnhancer::enhance()
  2. 8.9.x core/modules/jsonapi/src/Revisions/ResourceVersionRouteEnhancer.php \Drupal\jsonapi\Revisions\ResourceVersionRouteEnhancer::enhance()
  3. 10 core/modules/jsonapi/src/Revisions/ResourceVersionRouteEnhancer.php \Drupal\jsonapi\Revisions\ResourceVersionRouteEnhancer::enhance()

Overrides EnhancerInterface::enhance

File

core/modules/jsonapi/src/Revisions/ResourceVersionRouteEnhancer.php, line 85

Class

ResourceVersionRouteEnhancer
Loads an appropriate revision for the requested resource version.

Namespace

Drupal\jsonapi\Revisions

Code

public function enhance(array $defaults, Request $request) {
    if (!Routes::isJsonApiRequest($defaults) || !($resource_type = Routes::getResourceTypeNameFromParameters($defaults))) {
        return $defaults;
    }
    $has_version_param = $request->query
        ->has(static::RESOURCE_VERSION_QUERY_PARAMETER);
    // If the resource type is not versionable, then nothing needs to be
    // enhanced.
    if (!$resource_type->isVersionable()) {
        // If the query parameter was provided but the resource type is not
        // versionable, provide a helpful error.
        if ($has_version_param) {
            $cacheability = (new CacheableMetadata())->addCacheContexts([
                'url.path',
                static::CACHE_CONTEXT,
            ]);
            throw new CacheableHttpException($cacheability, 501, 'Resource versioning is not yet supported for this resource type.');
        }
        return $defaults;
    }
    // Since the resource type is versionable, responses must always vary by the
    // requested version, without regard for whether a version query parameter
    // was provided or not.
    if (isset($defaults['entity'])) {
        assert($defaults['entity'] instanceof EntityInterface);
        $defaults['entity']->addCacheContexts([
            static::CACHE_CONTEXT,
        ]);
    }
    // If no version was specified, nothing is left to enhance.
    if (!$has_version_param) {
        return $defaults;
    }
    // Provide a helpful error when a version is specified with an unsafe
    // method.
    if (!$request->isMethodCacheable()) {
        throw new BadRequestHttpException(sprintf('%s requests with a `%s` query parameter are not supported.', $request->getMethod(), static::RESOURCE_VERSION_QUERY_PARAMETER));
    }
    $resource_version_identifier = $request->query
        ->get(static::RESOURCE_VERSION_QUERY_PARAMETER);
    if (!static::isValidVersionIdentifier($resource_version_identifier)) {
        $cacheability = (new CacheableMetadata())->addCacheContexts([
            static::CACHE_CONTEXT,
        ]);
        $message = sprintf('A resource version identifier was provided in an invalid format: `%s`', $resource_version_identifier);
        throw new CacheableBadRequestHttpException($cacheability, $message);
    }
    // Determine if the request is for a collection resource.
    if ($defaults[RouteObjectInterface::CONTROLLER_NAME] === Routes::CONTROLLER_SERVICE_NAME . ':getCollection') {
        $latest_version_identifier = 'rel' . VersionNegotiator::SEPARATOR . 'latest-version';
        $working_copy_identifier = 'rel' . VersionNegotiator::SEPARATOR . 'working-copy';
        // Until Drupal core has a revision access API that works on entity
        // queries, filtering is not permitted on non-default revisions.
        if ($request->query
            ->has('filter') && $resource_version_identifier !== $latest_version_identifier) {
            $cache_contexts = [
                'url.path',
                static::CACHE_CONTEXT,
                'url.query_args:filter',
            ];
            $cacheability = (new CacheableMetadata())->addCacheContexts($cache_contexts);
            $message = 'JSON:API does not support filtering on revisions other than the latest version because a secure Drupal core API does not yet exist to do so.';
            throw new CacheableHttpException($cacheability, 501, $message);
        }
        // 'latest-version' and 'working-copy' are the only acceptable version
        // identifiers for a collection resource.
        if (!in_array($resource_version_identifier, [
            $latest_version_identifier,
            $working_copy_identifier,
        ])) {
            $cacheability = (new CacheableMetadata())->addCacheContexts([
                'url.path',
                static::CACHE_CONTEXT,
            ]);
            $message = sprintf('Collection resources only support the following resource version identifiers: %s', implode(', ', [
                $latest_version_identifier,
                $working_copy_identifier,
            ]));
            throw new CacheableBadRequestHttpException($cacheability, $message);
        }
        // Whether the collection to be loaded should include only working copies.
        $defaults[static::WORKING_COPIES_REQUESTED] = $resource_version_identifier === $working_copy_identifier;
        return $defaults;
    }
    
    /** @var \Drupal\Core\Entity\EntityInterface $entity */
    $entity = $defaults['entity'];
    
    /** @var \Drupal\jsonapi\Revisions\VersionNegotiatorInterface $negotiator */
    $resolved_revision = $this->versionNegotiator
        ->getRevision($entity, $resource_version_identifier);
    // Ensure none of the original entity cacheability is lost, especially the
    // query argument's cache context.
    $resolved_revision->addCacheableDependency($entity);
    return [
        'entity' => $resolved_revision,
    ] + $defaults;
}

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