public function JsonApiDocumentTopLevelNormalizer::denormalize in Drupal 9
Same name and namespace in other branches
- 8 core/modules/jsonapi/src/Normalizer/JsonApiDocumentTopLevelNormalizer.php \Drupal\jsonapi\Normalizer\JsonApiDocumentTopLevelNormalizer::denormalize()
File
- core/
modules/ jsonapi/ src/ Normalizer/ JsonApiDocumentTopLevelNormalizer.php, line 73
Class
- JsonApiDocumentTopLevelNormalizer
- Normalizes the top-level document according to the JSON:API specification.
Namespace
Drupal\jsonapi\NormalizerCode
public function denormalize($data, $class, $format = NULL, array $context = []) {
$resource_type = $context['resource_type'];
// Validate a few common errors in document formatting.
static::validateRequestBody($data, $resource_type);
$normalized = [];
if (!empty($data['data']['attributes'])) {
$normalized = $data['data']['attributes'];
}
if (!empty($data['data']['id'])) {
$uuid_key = $this->entityTypeManager
->getDefinition($resource_type
->getEntityTypeId())
->getKey('uuid');
$normalized[$uuid_key] = $data['data']['id'];
}
if (!empty($data['data']['relationships'])) {
// Turn all single object relationship data fields into an array of
// objects.
$relationships = array_map(function ($relationship) {
if (isset($relationship['data']['type']) && isset($relationship['data']['id'])) {
return [
'data' => [
$relationship['data'],
],
];
}
else {
return $relationship;
}
}, $data['data']['relationships']);
// Get an array of ids for every relationship.
$relationships = array_map(function ($relationship) {
if (empty($relationship['data'])) {
return [];
}
if (empty($relationship['data'][0]['id'])) {
throw new BadRequestHttpException("No ID specified for related resource");
}
$id_list = array_column($relationship['data'], 'id');
if (empty($relationship['data'][0]['type'])) {
throw new BadRequestHttpException("No type specified for related resource");
}
if (!($resource_type = $this->resourceTypeRepository
->getByTypeName($relationship['data'][0]['type']))) {
throw new BadRequestHttpException("Invalid type specified for related resource: '" . $relationship['data'][0]['type'] . "'");
}
$entity_type_id = $resource_type
->getEntityTypeId();
try {
$entity_storage = $this->entityTypeManager
->getStorage($entity_type_id);
} catch (PluginNotFoundException $e) {
throw new BadRequestHttpException("Invalid type specified for related resource: '" . $relationship['data'][0]['type'] . "'");
}
// In order to maintain the order ($delta) of the relationships, we need
// to load the entities and create a mapping between id and uuid.
$uuid_key = $this->entityTypeManager
->getDefinition($entity_type_id)
->getKey('uuid');
$related_entities = array_values($entity_storage
->loadByProperties([
$uuid_key => $id_list,
]));
$map = [];
foreach ($related_entities as $related_entity) {
$map[$related_entity
->uuid()] = $related_entity
->id();
}
// $id_list has the correct order of uuids. We stitch this together with
// $map which contains loaded entities, and then bring in the correct
// meta values from the relationship, whose deltas match with $id_list.
$canonical_ids = [];
foreach ($id_list as $delta => $uuid) {
if (!isset($map[$uuid])) {
// @see \Drupal\jsonapi\Normalizer\EntityReferenceFieldNormalizer::normalize()
if ($uuid === 'virtual') {
continue;
}
throw new NotFoundHttpException(sprintf('The resource identified by `%s:%s` (given as a relationship item) could not be found.', $relationship['data'][$delta]['type'], $uuid));
}
$reference_item = [
'target_id' => $map[$uuid],
];
if (isset($relationship['data'][$delta]['meta'])) {
$reference_item += $relationship['data'][$delta]['meta'];
}
$canonical_ids[] = array_filter($reference_item, function ($key) {
return substr($key, 0, strlen('drupal_internal__')) !== 'drupal_internal__';
}, ARRAY_FILTER_USE_KEY);
}
return array_filter($canonical_ids);
}, $relationships);
// Add the relationship ids.
$normalized = array_merge($normalized, $relationships);
}
// Override deserialization target class with the one in the ResourceType.
$class = $context['resource_type']
->getDeserializationTargetClass();
return $this->serializer
->denormalize($normalized, $class, $format, $context);
}