You are here

protected static function ResourceResponseTestTrait::toCollectionResourceResponse in JSON:API 8

Same name and namespace in other branches
  1. 8.2 tests/src/Functional/ResourceResponseTestTrait.php \Drupal\Tests\jsonapi\Functional\ResourceResponseTestTrait::toCollectionResourceResponse()

Merges individual responses into a collection response.

Here, a collection response refers to a response with multiple resource objects. Not necessarily to a response to a collection route. In both cases, the document should indistinguishable.

Parameters

array $responses: An array or ResourceResponses to be merged.

string|null $self_link: The self link for the merged document if one should be set.

bool $is_multiple: Whether the responses are for a multiple cardinality field. This cannot be deduced from the number of responses, because a multiple cardinality field may have only one value.

Return value

\Drupal\jsonapi\ResourceResponse The merged ResourceResponse.

3 calls to ResourceResponseTestTrait::toCollectionResourceResponse()
ResourceResponseTestTrait::getExpectedIncludedResourceResponse in tests/src/Functional/ResourceResponseTestTrait.php
Gets an array of expected ResourceResponses for the given include paths.
ResourceTestBase::getExpectedCollectionResponse in tests/src/Functional/ResourceTestBase.php
Returns a JSON API collection document for the expected entities.
ResourceTestBase::getExpectedRelatedResponses in tests/src/Functional/ResourceTestBase.php
Builds an array of expected related ResourceResponses, keyed by field name.

File

tests/src/Functional/ResourceResponseTestTrait.php, line 42

Class

ResourceResponseTestTrait
Utility methods for handling resource responses.

Namespace

Drupal\Tests\jsonapi\Functional

Code

protected static function toCollectionResourceResponse(array $responses, $self_link, $is_multiple) {
  assert(count($responses) > 0);
  $merged_document = [];
  $merged_cacheability = new CacheableMetadata();
  foreach ($responses as $response) {
    $response_document = $response
      ->getResponseData();
    $merge_errors = function ($errors) use (&$merged_document, $is_multiple) {
      foreach ($errors as $error) {
        if ($is_multiple) {
          $merged_document['meta']['errors'][] = $error;
        }
        else {
          $merged_document['errors'][] = $error;
        }
      }
    };

    // If any of the response documents had top-level or meta errors, we
    // should later expect the merged document to have all these errors
    // under the 'meta' member.
    if (!empty($response_document['errors'])) {
      $merge_errors($response_document['errors']);
    }
    if (!empty($response_document['meta']['errors'])) {
      $merge_errors($response_document['meta']['errors']);
    }
    elseif (isset($response_document['data'])) {
      $response_data = $response_document['data'];
      if (!isset($merged_document['data'])) {
        $merged_document['data'] = static::isResourceIdentifier($response_data) && $is_multiple ? [
          $response_data,
        ] : $response_data;
      }
      else {
        $response_resources = static::isResourceIdentifier($response_data) ? [
          $response_data,
        ] : $response_data;
        foreach ($response_resources as $response_resource) {
          $merged_document['data'][] = $response_resource;
        }
      }
    }
    $merged_cacheability
      ->addCacheableDependency($response
      ->getCacheableMetadata());
  }

  // Until we can reasonably know what caused an error, we shouldn't include
  // 'self' links in error documents. For example, a 404 shouldn't have a
  // 'self' link because HATEOAS links shouldn't point to resources which do
  // not exist.
  if (isset($merged_document['errors'])) {
    unset($merged_document['links']);
  }
  else {
    $merged_document['links'] = [
      'self' => $self_link,
    ];

    // @todo Assign this to every document, even with errors in https://www.drupal.org/project/jsonapi/issues/2949807
    $merged_document['jsonapi'] = [
      'meta' => [
        'links' => [
          'self' => 'http://jsonapi.org/format/1.0/',
        ],
      ],
      'version' => '1.0',
    ];
  }

  // If any successful code exists, use that one. Partial success isn't
  // defined by HTTP semantics. When different response codes exist, fall
  // back to a more general code. Any one success will make the merged request
  // a success.
  $merged_response_code = array_reduce($responses, function ($merged_response_code, $response) {
    $response_code = $response
      ->getStatusCode();
    assert($response_code >= 200 && $response_code < 500, 'Responses must be valid and complete to be merged.');
    assert(!($response_code >= 300 && $response_code < 400), 'Redirect responses cannot be merged.');

    // In the initial case, use the first response code.
    if (is_null($merged_response_code)) {
      return $response_code;
    }
    elseif ($merged_response_code === $response_code) {
      return $merged_response_code;
    }
    elseif ($response_code >= 200 && $response_code < 300 || $merged_response_code >= 200 && $merged_response_code < 300) {
      return 200;
    }
    else {
      return 400;
    }
  }, NULL);
  return (new ResourceResponse($merged_document, $merged_response_code))
    ->addCacheableDependency($merged_cacheability);
}