View source
<?php
namespace Drupal\jsonapi_schema\Normalizer;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Field\FieldTypePluginManagerInterface;
use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
use Drupal\jsonapi\ResourceType\ResourceType;
use Drupal\jsonapi\ResourceType\ResourceTypeRepositoryInterface;
class RelationshipFieldDefinitionNormalizer extends ListDataDefinitionNormalizer {
protected $supportedInterfaceOrClass = FieldDefinitionInterface::class;
protected $fieldTypeManager;
public function __construct(FieldTypePluginManagerInterface $field_type_manager) {
$this->fieldTypeManager = $field_type_manager;
}
public function supportsNormalization($data, $format = NULL) {
if (!parent::supportsNormalization($data, $format)) {
return FALSE;
}
$type = $data
->getItemDefinition()
->getFieldDefinition()
->getType();
$class = $this->fieldTypeManager
->getPluginClass($type);
return $class == EntityReferenceItem::class || is_subclass_of($class, EntityReferenceItem::class);
}
public function normalize($entity, $format = NULL, array $context = []) {
$cardinality = $entity
->getFieldStorageDefinition()
->getCardinality();
$context['cardinality'] = $cardinality;
assert($entity instanceof FieldDefinitionInterface);
$normalized = [
'description' => t('Entity relationships'),
'properties' => [
$context['name'] => $this
->normalizeRelationship($entity, $format, $context),
],
'type' => 'object',
];
$default_value = $entity
->getDefaultValueLiteral();
if (!empty($default_value)) {
$normalized['properties'][$context['name']]['default'] = $default_value;
}
if ($cardinality != FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED && $cardinality != 1) {
$normalized['properties'][$context['name']]['maxItems'] = $cardinality;
}
return $normalized;
}
protected function normalizeRelationship(FieldDefinitionInterface $field_definition, $format = NULL, $context = []) {
$resource_type_repository = \Drupal::service('jsonapi.resource_type.repository');
assert($resource_type_repository instanceof ResourceTypeRepositoryInterface);
$resource_identifier_object = [
'type' => 'object',
'required' => [
'type',
'id',
],
'properties' => [
'type' => [
'type' => 'string',
'title' => t('Referenced resource'),
],
'id' => [
'type' => 'string',
'title' => t('Resource ID'),
'format' => 'uuid',
'maxLength' => 128,
],
],
];
$cardinality = $field_definition
->getFieldStorageDefinition()
->getCardinality();
if ($target_entity_type = $field_definition
->getSetting('target_type')) {
$handler_settings = $field_definition
->getSetting('handler_settings');
$target_bundles = empty($handler_settings['target_bundles']) ? [
$target_entity_type,
] : array_values($handler_settings['target_bundles']);
$target_resource_types = array_map(function ($bundle) use ($target_entity_type, $resource_type_repository) {
return $resource_type_repository
->get($target_entity_type, $bundle ?: $target_entity_type);
return $resource_type
->getTypeName();
}, $target_bundles);
$enum = array_map(function (ResourceType $resource_type) {
return $resource_type
->getTypeName();
}, array_filter($target_resource_types));
}
$meta = $this->serializer
->normalize($field_definition
->getItemDefinition(), $format, $context);
if ($cardinality == 1) {
$data = $resource_identifier_object;
if (!empty($enum)) {
$data['properties']['type']['enum'] = $enum;
$data['properties']['meta'] = $meta;
}
}
else {
$data = [
'type' => 'array',
'items' => $resource_identifier_object,
];
if (!empty($enum)) {
$data['items']['properties']['type']['enum'] = $enum;
$data['items']['properties']['meta'] = $meta;
}
}
$normalized = [
'type' => 'object',
'properties' => [
'data' => $data,
],
'title' => $field_definition
->getLabel(),
];
return $normalized;
}
}