class ResourceIdentifierNormalizer in Drupal 8
Same name and namespace in other branches
- 9 core/modules/jsonapi/src/Normalizer/ResourceIdentifierNormalizer.php \Drupal\jsonapi\Normalizer\ResourceIdentifierNormalizer
Normalizes a Relationship according to the JSON:API specification.
Normalizer class for relationship elements. A relationship can be anything that points to an entity in a JSON:API resource.
@internal JSON:API maintains no PHP API since its API is the HTTP API. This class may change at any time and this will break any dependencies on it.
Hierarchy
- class \Drupal\serialization\Normalizer\NormalizerBase implements \Symfony\Component\Serializer\SerializerAwareInterface, CacheableNormalizerInterface uses \Symfony\Component\Serializer\SerializerAwareTrait
- class \Drupal\jsonapi\Normalizer\NormalizerBase
- class \Drupal\jsonapi\Normalizer\ResourceIdentifierNormalizer implements \Symfony\Component\Serializer\Normalizer\DenormalizerInterface
- class \Drupal\jsonapi\Normalizer\NormalizerBase
Expanded class hierarchy of ResourceIdentifierNormalizer
See also
https://www.drupal.org/project/drupal/issues/3032787
1 file declares its use of ResourceIdentifierNormalizer
- ResourceIdentifierNormalizerTest.php in core/
modules/ jsonapi/ tests/ src/ Unit/ Normalizer/ ResourceIdentifierNormalizerTest.php
1 string reference to 'ResourceIdentifierNormalizer'
- jsonapi.services.yml in core/
modules/ jsonapi/ jsonapi.services.yml - core/modules/jsonapi/jsonapi.services.yml
1 service uses ResourceIdentifierNormalizer
File
- core/
modules/ jsonapi/ src/ Normalizer/ ResourceIdentifierNormalizer.php, line 24
Namespace
Drupal\jsonapi\NormalizerView source
class ResourceIdentifierNormalizer extends NormalizerBase implements DenormalizerInterface {
/**
* {@inheritdoc}
*/
protected $supportedInterfaceOrClass = ResourceIdentifier::class;
/**
* The entity field manager.
*
* @var \Drupal\Core\Entity\EntityFieldManagerInterface
*/
protected $fieldManager;
/**
* RelationshipNormalizer constructor.
*
* @param \Drupal\Core\Entity\EntityFieldManagerInterface $field_manager
* The entity field manager.
*/
public function __construct(EntityFieldManagerInterface $field_manager) {
$this->fieldManager = $field_manager;
}
/**
* {@inheritdoc}
*/
public function normalize($object, $format = NULL, array $context = []) {
assert($object instanceof ResourceIdentifier);
$normalization = [
'type' => $object
->getTypeName(),
'id' => $object
->getId(),
];
if ($object
->getMeta()) {
$normalization['meta'] = $this->serializer
->normalize($object
->getMeta(), $format, $context);
}
return CacheableNormalization::permanent($normalization);
}
/**
* {@inheritdoc}
*/
public function denormalize($data, $class, $format = NULL, array $context = []) {
// If we get here, it's via a relationship POST/PATCH.
/** @var \Drupal\jsonapi\ResourceType\ResourceType $resource_type */
$resource_type = $context['resource_type'];
$entity_type_id = $resource_type
->getEntityTypeId();
$field_definitions = $this->fieldManager
->getFieldDefinitions($entity_type_id, $resource_type
->getBundle());
if (empty($context['related']) || empty($field_definitions[$context['related']])) {
throw new BadRequestHttpException('Invalid or missing related field.');
}
/* @var \Drupal\field\Entity\FieldConfig $field_definition */
$field_definition = $field_definitions[$context['related']];
// This is typically 'target_id'.
$item_definition = $field_definition
->getItemDefinition();
$property_key = $item_definition
->getMainPropertyName();
$target_resource_types = $resource_type
->getRelatableResourceTypesByField($resource_type
->getPublicName($context['related']));
$target_resource_type_names = array_map(function (ResourceType $resource_type) {
return $resource_type
->getTypeName();
}, $target_resource_types);
$is_multiple = $field_definition
->getFieldStorageDefinition()
->isMultiple();
$data = $this
->massageRelationshipInput($data, $is_multiple);
$resource_identifiers = array_map(function ($value) use ($property_key, $target_resource_type_names) {
// Make sure that the provided type is compatible with the targeted
// resource.
if (!in_array($value['type'], $target_resource_type_names)) {
throw new BadRequestHttpException(sprintf('The provided type (%s) does not mach the destination resource types (%s).', $value['type'], implode(', ', $target_resource_type_names)));
}
return new ResourceIdentifier($value['type'], $value['id'], isset($value['meta']) ? $value['meta'] : []);
}, $data['data']);
if (!ResourceIdentifier::areResourceIdentifiersUnique($resource_identifiers)) {
throw new BadRequestHttpException('Duplicate relationships are not permitted. Use `meta.arity` to distinguish resource identifiers with matching `type` and `id` values.');
}
return $resource_identifiers;
}
/**
* Validates and massages the relationship input depending on the cardinality.
*
* @param array $data
* The input data from the body.
* @param bool $is_multiple
* Indicates if the relationship is to-many.
*
* @return array
* The massaged data array.
*/
protected function massageRelationshipInput(array $data, $is_multiple) {
if ($is_multiple) {
if (!is_array($data['data'])) {
throw new BadRequestHttpException('Invalid body payload for the relationship.');
}
// Leave the invalid elements.
$invalid_elements = array_filter($data['data'], function ($element) {
return empty($element['type']) || empty($element['id']);
});
if ($invalid_elements) {
throw new BadRequestHttpException('Invalid body payload for the relationship.');
}
}
else {
// For to-one relationships you can have a NULL value.
if (is_null($data['data'])) {
return [
'data' => [],
];
}
if (empty($data['data']['type']) || empty($data['data']['id'])) {
throw new BadRequestHttpException('Invalid body payload for the relationship.');
}
$data['data'] = [
$data['data'],
];
}
return $data;
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
CacheableNormalizerInterface:: |
constant | Name of key for bubbling cacheability metadata via serialization context. | ||
NormalizerBase:: |
protected | property |
List of formats which supports (de-)normalization. Overrides NormalizerBase:: |
|
NormalizerBase:: |
protected | function | Adds cacheability if applicable. | |
NormalizerBase:: |
protected | function |
Checks if the provided format is supported by this normalizer. Overrides NormalizerBase:: |
|
NormalizerBase:: |
protected static | function | Rasterizes a value recursively. | |
NormalizerBase:: |
public | function | Implements \Symfony\Component\Serializer\Normalizer\DenormalizerInterface::supportsDenormalization() | 1 |
NormalizerBase:: |
public | function | Checks whether the given class is supported for normalization by this normalizer. | 1 |
ResourceIdentifierNormalizer:: |
protected | property | The entity field manager. | |
ResourceIdentifierNormalizer:: |
protected | property |
The interface or class that this Normalizer supports. Overrides NormalizerBase:: |
|
ResourceIdentifierNormalizer:: |
public | function | Denormalizes data back into an object of the given class. | |
ResourceIdentifierNormalizer:: |
protected | function | Validates and massages the relationship input depending on the cardinality. | |
ResourceIdentifierNormalizer:: |
public | function | Normalizes an object into a set of arrays/scalars. | |
ResourceIdentifierNormalizer:: |
public | function | RelationshipNormalizer constructor. |