protected function DocumentExtractor::handleRelationships in JSON:API Resources 8
Builds the relationships for the resource object.
Parameters
array $data: Multi-dimensional array containing the decoded data.
Return value
array The relationships array.
1 call to DocumentExtractor::handleRelationships()
- DocumentExtractor::extractResourceObjectFromRequest in src/
Unstable/ DocumentExtractor.php - Decodes and builds a resource object from a request body.
File
- src/
Unstable/ DocumentExtractor.php, line 216
Class
- DocumentExtractor
- Document extractor for requests.
Namespace
Drupal\jsonapi_resources\UnstableCode
protected function handleRelationships(array $data) : array {
// 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['relationships']);
$result = [];
// Get an array of ids for every relationship.
foreach ($relationships as $relationship_field => $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(sprintf('Invalid type specified for related resource: "%s"', $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(sprintf('Invalid type specified for related resource: "%s"', $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[] = $reference_item;
}
$result[$relationship_field] = $canonical_ids;
}
return $result;
}