class ResourceObjectNormalizer in Drupal 9
Same name and namespace in other branches
- 8 core/modules/jsonapi/src/Normalizer/ResourceObjectNormalizer.php \Drupal\jsonapi\Normalizer\ResourceObjectNormalizer
Converts the JSON:API module ResourceObject into a JSON:API array structure.
@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\ResourceObjectNormalizer
- class \Drupal\jsonapi\Normalizer\NormalizerBase
Expanded class hierarchy of ResourceObjectNormalizer
See also
https://www.drupal.org/project/drupal/issues/3032787
1 string reference to 'ResourceObjectNormalizer'
- jsonapi.services.yml in core/
modules/ jsonapi/ jsonapi.services.yml - core/modules/jsonapi/jsonapi.services.yml
1 service uses ResourceObjectNormalizer
File
- core/
modules/ jsonapi/ src/ Normalizer/ ResourceObjectNormalizer.php, line 23
Namespace
Drupal\jsonapi\NormalizerView source
class ResourceObjectNormalizer extends NormalizerBase {
/**
* {@inheritdoc}
*/
protected $supportedInterfaceOrClass = ResourceObject::class;
/**
* The entity normalization cacher.
*
* @var \Drupal\jsonapi\EventSubscriber\ResourceObjectNormalizationCacher
*/
protected $cacher;
/**
* Constructs a ResourceObjectNormalizer object.
*
* @param \Drupal\jsonapi\EventSubscriber\ResourceObjectNormalizationCacher $cacher
* The entity normalization cacher.
*/
public function __construct(ResourceObjectNormalizationCacher $cacher) {
$this->cacher = $cacher;
}
/**
* {@inheritdoc}
*/
public function supportsDenormalization($data, $type, $format = NULL) {
return FALSE;
}
/**
* {@inheritdoc}
*/
public function normalize($object, $format = NULL, array $context = []) {
assert($object instanceof ResourceObject);
// If the fields to use were specified, only output those field values.
$context['resource_object'] = $object;
$resource_type = $object
->getResourceType();
$resource_type_name = $resource_type
->getTypeName();
$fields = $object
->getFields();
// Get the bundle ID of the requested resource. This is used to determine if
// this is a bundle level resource or an entity level resource.
if (!empty($context['sparse_fieldset'][$resource_type_name])) {
$field_names = $context['sparse_fieldset'][$resource_type_name];
}
else {
$field_names = array_keys($fields);
}
$normalization_parts = $this
->getNormalization($field_names, $object, $format, $context);
// Keep only the requested fields (the cached normalization gradually grows
// to the complete set of fields).
$fields = $normalization_parts[ResourceObjectNormalizationCacher::RESOURCE_CACHE_SUBSET_FIELDS];
$field_normalizations = array_intersect_key($fields, array_flip($field_names));
$relationship_field_names = array_keys($resource_type
->getRelatableResourceTypes());
$attributes = array_diff_key($field_normalizations, array_flip($relationship_field_names));
$relationships = array_intersect_key($field_normalizations, array_flip($relationship_field_names));
$entity_normalization = array_filter($normalization_parts[ResourceObjectNormalizationCacher::RESOURCE_CACHE_SUBSET_BASE] + [
'attributes' => CacheableNormalization::aggregate($attributes)
->omitIfEmpty(),
'relationships' => CacheableNormalization::aggregate($relationships)
->omitIfEmpty(),
]);
return CacheableNormalization::aggregate($entity_normalization)
->withCacheableDependency($object);
}
/**
* Normalizes an entity using the given fieldset.
*
* @param string[] $field_names
* The field names to normalize (the sparse fieldset, if any).
* @param \Drupal\jsonapi\JsonApiResource\ResourceObject $object
* The resource object to partially normalize.
* @param string $format
* The format in which the normalization will be encoded.
* @param array $context
* Context options for the normalizer.
*
* @return array
* An array with two key-value pairs:
* - 'base': array, the base normalization of the entity, that does not
* depend on which sparse fieldset was requested.
* - 'fields': CacheableNormalization for all requested fields.
*
* @see ::normalize()
*/
protected function getNormalization(array $field_names, ResourceObject $object, $format = NULL, array $context = []) {
$cached_normalization_parts = $this->cacher
->get($object);
$normalizer_values = $cached_normalization_parts !== FALSE ? $cached_normalization_parts : static::buildEmptyNormalization($object);
$fields =& $normalizer_values[ResourceObjectNormalizationCacher::RESOURCE_CACHE_SUBSET_FIELDS];
$non_cached_fields = array_diff_key($object
->getFields(), $fields);
$non_cached_requested_fields = array_intersect_key($non_cached_fields, array_flip($field_names));
foreach ($non_cached_requested_fields as $field_name => $field) {
$fields[$field_name] = $this
->serializeField($field, $context, $format);
}
// Add links if missing.
$base =& $normalizer_values[ResourceObjectNormalizationCacher::RESOURCE_CACHE_SUBSET_BASE];
$base['links'] = isset($base['links']) ? $base['links'] : $this->serializer
->normalize($object
->getLinks(), $format, $context)
->omitIfEmpty();
if (!empty($non_cached_requested_fields)) {
$this->cacher
->saveOnTerminate($object, $normalizer_values);
}
return $normalizer_values;
}
/**
* Builds the empty normalization structure for cache misses.
*
* @param \Drupal\jsonapi\JsonApiResource\ResourceObject $object
* The resource object being normalized.
*
* @return array
* The normalization structure as defined in ::getNormalization().
*
* @see ::getNormalization()
*/
protected static function buildEmptyNormalization(ResourceObject $object) {
return [
ResourceObjectNormalizationCacher::RESOURCE_CACHE_SUBSET_BASE => [
'type' => CacheableNormalization::permanent($object
->getResourceType()
->getTypeName()),
'id' => CacheableNormalization::permanent($object
->getId()),
],
ResourceObjectNormalizationCacher::RESOURCE_CACHE_SUBSET_FIELDS => [],
];
}
/**
* Serializes a given field.
*
* @param mixed $field
* The field to serialize.
* @param array $context
* The normalization context.
* @param string $format
* The serialization format.
*
* @return \Drupal\jsonapi\Normalizer\Value\CacheableNormalization
* The normalized value.
*/
protected function serializeField($field, array $context, $format) {
// Only content entities contain FieldItemListInterface fields. Since config
// entities do not have "real" fields and therefore do not have field access
// restrictions.
if ($field instanceof FieldItemListInterface) {
$field_access_result = $field
->access('view', $context['account'], TRUE);
if (!$field_access_result
->isAllowed()) {
return new CacheableOmission(CacheableMetadata::createFromObject($field_access_result));
}
if ($field instanceof EntityReferenceFieldItemListInterface) {
// Build the relationship object based on the entity reference and
// normalize that object instead.
assert(!empty($context['resource_object']) && $context['resource_object'] instanceof ResourceObject);
$resource_object = $context['resource_object'];
$relationship = Relationship::createFromEntityReferenceField($resource_object, $field);
$normalized_field = $this->serializer
->normalize($relationship, $format, $context);
}
else {
$normalized_field = $this->serializer
->normalize($field, $format, $context);
}
assert($normalized_field instanceof CacheableNormalization);
return $normalized_field
->withCacheableDependency(CacheableMetadata::createFromObject($field_access_result));
}
else {
// @todo Replace this workaround after https://www.drupal.org/node/3043245
// or remove the need for this in https://www.drupal.org/node/2942975.
// See \Drupal\layout_builder\Normalizer\LayoutEntityDisplayNormalizer.
if ($context['resource_object']
->getResourceType()
->getDeserializationTargetClass() === 'Drupal\\layout_builder\\Entity\\LayoutBuilderEntityViewDisplay' && $context['resource_object']
->getField('third_party_settings') === $field) {
unset($field['layout_builder']['sections']);
}
// Config "fields" in this case are arrays or primitives and do not need
// to be normalized.
return CacheableNormalization::permanent($field);
}
}
}
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 | 1 | |
ResourceObjectNormalizer:: |
protected | property | The entity normalization cacher. | |
ResourceObjectNormalizer:: |
protected | property |
The interface or class that this Normalizer supports. Overrides NormalizerBase:: |
|
ResourceObjectNormalizer:: |
protected static | function | Builds the empty normalization structure for cache misses. | |
ResourceObjectNormalizer:: |
protected | function | Normalizes an entity using the given fieldset. | |
ResourceObjectNormalizer:: |
public | function | ||
ResourceObjectNormalizer:: |
protected | function | Serializes a given field. | |
ResourceObjectNormalizer:: |
public | function |
Implements \Symfony\Component\Serializer\Normalizer\DenormalizerInterface::supportsDenormalization() Overrides NormalizerBase:: |
|
ResourceObjectNormalizer:: |
public | function | Constructs a ResourceObjectNormalizer object. |