View source
<?php
namespace Drupal\jsonapi\Normalizer\Value;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Cache\RefinableCacheableDependencyInterface;
use Drupal\Core\Cache\RefinableCacheableDependencyTrait;
use Drupal\jsonapi\JsonApiSpec;
class JsonApiDocumentTopLevelNormalizerValue implements ValueExtractorInterface, RefinableCacheableDependencyInterface {
use RefinableCacheableDependencyTrait;
protected $values;
protected $includes;
protected $context;
protected $isCollection;
protected $linkManager;
protected $linkContext;
public function __construct(array $values, array $context, array $link_context, $is_collection = FALSE) {
$this->values = $values;
array_walk($values, [
$this,
'addCacheableDependency',
]);
$this
->addCacheContexts(array_map(function ($query_parameter_name) {
return sprintf('url.query_args:%s', $query_parameter_name);
}, JsonApiSpec::getReservedQueryParameters()));
$this
->addCacheContexts([
'url.site',
]);
$this->context = $context;
$this->isCollection = $is_collection;
$this->linkManager = $link_context['link_manager'];
unset($link_context['link_manager']);
$this->linkContext = $link_context;
$this->includes = array_map(function ($value) {
return $value
->getIncludes();
}, $values);
$this->includes = array_reduce($this->includes, function ($carry, $includes) {
array_walk($includes, [
$this,
'addCacheableDependency',
]);
return array_merge($carry, $includes);
}, []);
$this->includes = array_filter($this->includes);
}
public function rasterizeValue() {
$rasterized = [
'data' => [],
'jsonapi' => [
'version' => JsonApiSpec::SUPPORTED_SPECIFICATION_VERSION,
'meta' => [
'links' => [
'self' => JsonApiSpec::SUPPORTED_SPECIFICATION_PERMALINK,
],
],
],
'links' => [],
];
foreach ($this->values as $normalizer_value) {
if ($normalizer_value instanceof HttpExceptionNormalizerValue) {
$previous_errors = NestedArray::getValue($rasterized, [
'meta',
'errors',
]) ?: [];
$rasterized['meta']['errors'] = array_merge($previous_errors, $normalizer_value
->rasterizeValue());
}
else {
$rasterized_value = $normalizer_value
->rasterizeValue();
if (array_key_exists('data', $rasterized_value) && array_key_exists('links', $rasterized_value)) {
$rasterized['data'][] = $rasterized_value['data'];
$rasterized['links'] = NestedArray::mergeDeep($rasterized['links'], $rasterized_value['links']);
}
else {
$rasterized['data'][] = $rasterized_value;
}
}
}
$rasterized['data'] = $this->isCollection ? array_filter($rasterized['data']) : reset($rasterized['data']);
if ($this->context['request']) {
$request = $this->context['request'];
$rasterized['links'] += [
'self' => $this->linkManager
->getRequestLink($request),
];
if ($this->isCollection) {
$rasterized['links'] += $this->linkManager
->getPagerLinks($request, $this->linkContext);
if (isset($this->context['total_count'])) {
$rasterized = NestedArray::mergeDeepArray([
$rasterized,
[
'meta' => [
'count' => $this->context['total_count'],
],
],
]);
}
}
}
$included = array_filter($this
->rasterizeIncludes());
if (!empty($included)) {
foreach ($included as $included_item) {
if ($included_item['data'] === FALSE) {
unset($included_item['data']);
$rasterized = NestedArray::mergeDeep($rasterized, $included_item);
}
else {
$rasterized['included'][] = $included_item['data'];
}
}
}
if (empty($rasterized['links'])) {
unset($rasterized['links']);
}
return $rasterized;
}
public function getIncludes() {
$nested_includes = array_map(function ($include) {
return $include
->getIncludes();
}, $this->includes);
$includes = array_reduce(array_filter($nested_includes), function ($carry, $item) {
return array_merge($carry, $item);
}, $this->includes);
return array_values(array_reduce($includes, function ($unique_includes, $include) {
$rasterized_include = $include
->rasterizeValue();
if ($rasterized_include['data'] === FALSE) {
$unique_includes[] = $include;
}
else {
$unique_key = $rasterized_include['data']['type'] . ':' . $rasterized_include['data']['id'];
$unique_includes[$unique_key] = $include;
}
return $unique_includes;
}, []));
}
public function rasterizeIncludes() {
return array_map(function ($include) {
return $include
->rasterizeValue();
}, $this
->getIncludes());
}
}