src/Controller/EntityResource.php | 11 +++++++--- src/JsonApiResource/JsonApiDocumentTopLevel.php | 24 ++++++++++++++++++++-- .../JsonApiDocumentTopLevelNormalizer.php | 6 ++---- .../JsonApiDocumentTopLevelNormalizerValue.php | 22 ++++++++++---------- 4 files changed, 43 insertions(+), 20 deletions(-) diff --git a/src/Controller/EntityResource.php b/src/Controller/EntityResource.php index 87a0c84..189e9a6 100644 --- a/src/Controller/EntityResource.php +++ b/src/Controller/EntityResource.php @@ -794,13 +794,15 @@ class EntityResource { * An array of response headers. * @param \Drupal\Core\Url[]|string[] $links * The URLs to which to link. A 'self' link is added automatically. + * @param array $meta + * (optional) The top-level metadata. * * @return \Drupal\jsonapi\ResourceResponse * The response. */ - protected function buildWrappedResponse($data, $response_code = 200, array $headers = [], array $links = []) { + protected function buildWrappedResponse($data, $response_code = 200, array $headers = [], array $links = [], array $meta = []) { $links['self'] = $this->linkManager->getRequestLink(\Drupal::request()); - return new ResourceResponse(new JsonApiDocumentTopLevel($data, $links), $response_code, $headers); + return new ResourceResponse(new JsonApiDocumentTopLevel($data, $links, $meta), $response_code, $headers); } /** @@ -821,8 +823,11 @@ class EntityResource { ? $entity_collection->getTotalCount() : FALSE, ]; + $meta = $link_context['total_count'] === FALSE + ? [] + : ['count' => $link_context['total_count']]; $collection_links = $this->linkManager->getPagerLinks(\Drupal::request(), $link_context); - $response = $this->buildWrappedResponse($entity_collection, 200, [], $collection_links); + $response = $this->buildWrappedResponse($entity_collection, 200, [], $collection_links, $meta); // When a new change to any entity in the resource happens, we cannot ensure // the validity of this cached list. Add the list tag to deal with that. diff --git a/src/JsonApiResource/JsonApiDocumentTopLevel.php b/src/JsonApiResource/JsonApiDocumentTopLevel.php index 049e755..72560d2 100644 --- a/src/JsonApiResource/JsonApiDocumentTopLevel.php +++ b/src/JsonApiResource/JsonApiDocumentTopLevel.php @@ -12,7 +12,7 @@ use Drupal\Core\Url; * * @internal * - * @todo Add the missing required members: 'error' and 'meta' or document why not. + * @todo Add the missing required members: 'error' or document why not. * @todo Add support for the missing optional members: 'jsonapi' and 'included' or document why not. */ class JsonApiDocumentTopLevel { @@ -25,6 +25,13 @@ class JsonApiDocumentTopLevel { protected $data; /** + * The metadata to normalize. + * + * @var array + */ + protected $meta; + + /** * The links. Keys are link relation types. * * @var array|\Drupal\Core\Url[]|string[] @@ -40,8 +47,10 @@ class JsonApiDocumentTopLevel { * @param \Drupal\Core\Url[]|string[] $links * The URLs to which the top-level document should link. Keys are link * relation types. Values are URLs. + * @param array $meta + * (optional) The metadata to normalize. */ - public function __construct($data, array $links) { + public function __construct($data, array $links, array $meta = []) { assert(empty(array_diff(array_keys($links), [ 'self', 'first', @@ -56,6 +65,7 @@ class JsonApiDocumentTopLevel { $this->data = $data; $this->links = $links; + $this->meta = $meta; } /** @@ -78,4 +88,14 @@ class JsonApiDocumentTopLevel { return $this->links; } + /** + * Gets the metadata. + * + * @return array + * The metadata. + */ + public function getMeta() { + return $this->meta; + } + } diff --git a/src/Normalizer/JsonApiDocumentTopLevelNormalizer.php b/src/Normalizer/JsonApiDocumentTopLevelNormalizer.php index 9d5cf89..ad0976b 100644 --- a/src/Normalizer/JsonApiDocumentTopLevelNormalizer.php +++ b/src/Normalizer/JsonApiDocumentTopLevelNormalizer.php @@ -174,7 +174,7 @@ class JsonApiDocumentTopLevelNormalizer extends NormalizerBase implements Denorm $normalizer_values = [ $this->serializer->normalize($data, $format, $context), ]; - return new JsonApiDocumentTopLevelNormalizerValue($normalizer_values, [], FALSE); + return new JsonApiDocumentTopLevelNormalizerValue($normalizer_values, [], FALSE, $object->getMeta()); } $is_collection = $data instanceof EntityCollection; // To improve the logical workflow deal with an array at all times. @@ -184,9 +184,7 @@ class JsonApiDocumentTopLevelNormalizer extends NormalizerBase implements Denorm return $serializer->normalize($entity, $format, $context); }, $entities); - $total_count = $is_collection && $context['resource_type']->includeCount() ? $data->getTotalCount() : FALSE; - - return new JsonApiDocumentTopLevelNormalizerValue($normalizer_values, $object->getLinks(), $is_collection, $total_count); + return new JsonApiDocumentTopLevelNormalizerValue($normalizer_values, $object->getLinks(), $is_collection, $object->getMeta()); } /** diff --git a/src/Normalizer/Value/JsonApiDocumentTopLevelNormalizerValue.php b/src/Normalizer/Value/JsonApiDocumentTopLevelNormalizerValue.php index 3bfdc4b..f148ad6 100644 --- a/src/Normalizer/Value/JsonApiDocumentTopLevelNormalizerValue.php +++ b/src/Normalizer/Value/JsonApiDocumentTopLevelNormalizerValue.php @@ -47,9 +47,11 @@ class JsonApiDocumentTopLevelNormalizerValue implements ValueExtractorInterface, protected $isCollection; /** - * @var int + * The metadata. + * + * @var array */ - protected $totalCount; + protected $meta; /** * Instantiates a JsonApiDocumentTopLevelNormalizerValue object. @@ -61,12 +63,10 @@ class JsonApiDocumentTopLevelNormalizerValue implements ValueExtractorInterface, * The URLs to which to link. * @param bool $is_collection * TRUE if this is a serialization for a list. - * @param int $total_count - * (optional) A total count of resources available in a collection without - * respect for access control. + * @param array $meta + * (optional) The metadata to normalize. */ - public function __construct(array $values, array $links, $is_collection = FALSE, $total_count = FALSE) { - assert($total_count === FALSE || $is_collection, 'Only collection documents can contain result counts.'); + public function __construct(array $values, array $links, $is_collection = FALSE, array $meta = []) { $this->values = $values; array_walk($values, [$this, 'addCacheableDependency']); // Make sure that different sparse fieldsets are cached differently. @@ -91,6 +91,8 @@ class JsonApiDocumentTopLevelNormalizerValue implements ValueExtractorInterface, }, $links)); $this->links = $links; + $this->meta = $meta; + // Get an array of arrays of includes. $this->includes = array_map(function ($value) { return $value->getIncludes(); @@ -102,7 +104,6 @@ class JsonApiDocumentTopLevelNormalizerValue implements ValueExtractorInterface, }, []); // Filter the empty values. $this->includes = array_filter($this->includes); - $this->totalCount = $total_count; } /** @@ -120,9 +121,8 @@ class JsonApiDocumentTopLevelNormalizerValue implements ValueExtractorInterface, ], 'links' => $this->links, ]; - - if ($this->totalCount !== FALSE) { - $rasterized['meta']['count'] = $this->totalCount; + if (!empty($this->meta)) { + $rasterized['meta'] = $this->meta; } foreach ($this->values as $normalizer_value) {