class JsonApiSchemaController in JSON:API Schema 8
Hierarchy
- class \Drupal\Core\Controller\ControllerBase implements ContainerInjectionInterface uses LoggerChannelTrait, MessengerTrait, LinkGeneratorTrait, RedirectDestinationTrait, UrlGeneratorTrait, StringTranslationTrait
- class \Drupal\jsonapi_schema\Controller\JsonApiSchemaController
Expanded class hierarchy of JsonApiSchemaController
1 file declares its use of JsonApiSchemaController
- Routes.php in src/
Routing/ Routes.php
File
- src/
Controller/ JsonApiSchemaController.php, line 23
Namespace
Drupal\jsonapi_schema\ControllerView source
class JsonApiSchemaController extends ControllerBase {
const JSON_SCHEMA_DRAFT = 'https://json-schema.org/draft/2019-09/hyper-schema';
const JSONAPI_BASE_SCHEMA_URI = 'https://jsonapi.org/schema';
/**
* The JSON:API resource type repository.
*
* @var \Drupal\jsonapi\ResourceType\ResourceTypeRepositoryInterface
*/
protected $resourceTypeRepository;
/**
* The serialization service.
*
* @var \Symfony\Component\Serializer\Normalizer\NormalizerInterface
*/
protected $normalizer;
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* The static data definition extractor.
*
* @var \Drupal\jsonapi_schema\StaticDataDefinitionExtractor
*/
protected $staticDataDefinitionExtractor;
/**
* JsonApiSchemaController constructor.
*
* @param \Drupal\jsonapi\ResourceType\ResourceTypeRepositoryInterface $resource_type_repository
* The JSON:API resource type repository.
* @param \Symfony\Component\Serializer\Normalizer\NormalizerInterface $normalizer
* The serializer.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
*/
public function __construct(ResourceTypeRepositoryInterface $resource_type_repository, NormalizerInterface $normalizer, EntityTypeManagerInterface $entity_type_manager, StaticDataDefinitionExtractor $static_data_definition_extractor) {
$this->resourceTypeRepository = $resource_type_repository;
$this->normalizer = $normalizer;
$this->entityTypeManager = $entity_type_manager;
$this->staticDataDefinitionExtractor = $static_data_definition_extractor;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static($container
->get('jsonapi.resource_type.repository'), $container
->get('serializer'), $container
->get('entity_type.manager'), $container
->get('jsonapi_schema.static_data_definition_extractor'));
}
public function getEntrypointSchema(Request $request) {
$cacheability = new CacheableMetadata();
$cacheability
->addCacheTags([
'jsonapi_resource_types',
]);
$collection_links = array_values(array_map(function (ResourceType $resource_type) use ($cacheability) {
$schema_url = Url::fromRoute("jsonapi_schema.{$resource_type->getTypeName()}.collection")
->setAbsolute()
->toString(TRUE);
$cacheability
->addCacheableDependency($schema_url);
return [
'href' => '{instanceHref}',
'rel' => 'related',
'title' => $this
->getSchemaTitle($resource_type, 'collection'),
'targetMediaType' => 'application/vnd.api+json',
'targetSchema' => $schema_url
->getGeneratedUrl(),
'templatePointers' => [
'instanceHref' => "/links/{$resource_type->getTypeName()}/href",
],
'templateRequired' => [
'instanceHref',
],
];
}, array_filter($this->resourceTypeRepository
->all(), function (ResourceType $resource_type) {
return !$resource_type
->isInternal() && $resource_type
->isLocatable();
})));
$schema = [
'$schema' => static::JSON_SCHEMA_DRAFT,
'$id' => $request
->getUri(),
'allOf' => [
[
'$ref' => static::JSONAPI_BASE_SCHEMA_URI . '#/definitions/success',
],
[
'type' => 'object',
'links' => $collection_links,
],
],
];
return CacheableJsonResponse::create($schema)
->addCacheableDependency($cacheability);
}
public function getDocumentSchema(Request $request, $resource_type, $route_type) {
if (is_array($resource_type)) {
$titles = array_map(function (ResourceType $type) use ($route_type) {
return $this
->getSchemaTitle($this->resourceTypeRepository
->getByTypeName($type), $route_type);
}, $resource_type);
$title = count($titles) === 2 ? implode(' and ', $titles) : implode(', ', array_slice($titles, -1)) . ', and ' . end($titles);
}
else {
$title = $this
->getSchemaTitle($this->resourceTypeRepository
->getByTypeName($resource_type), $route_type);
}
$schema = [
'$schema' => static::JSON_SCHEMA_DRAFT,
'$id' => $request
->getUri(),
'title' => $title,
'allOf' => [
[
'$ref' => static::JSONAPI_BASE_SCHEMA_URI,
],
[
'if' => [
'$ref' => static::JSONAPI_BASE_SCHEMA_URI . '#/definitions/success',
],
'then' => [
'type' => 'object',
'properties' => [
'data' => [
'$ref' => '#/definitions/data',
],
],
'required' => [
'data',
],
],
],
],
];
$cacheability = new CacheableMetadata();
$get_schema_ref = function ($resource_type) use ($cacheability) {
$schema_url = Url::fromRoute("jsonapi_schema.{$resource_type}.type")
->setAbsolute()
->toString(TRUE);
$cacheability
->addCacheableDependency($schema_url);
return [
'$ref' => $schema_url
->getGeneratedUrl(),
];
};
$type_schema = is_array($resource_type) ? [
'anyOf' => array_map($get_schema_ref, $resource_type),
] : $get_schema_ref($resource_type);
switch ($route_type) {
case 'item':
$schema['definitions']['data'] = $type_schema;
break;
case 'collection':
$schema['definitions']['data'] = [
'type' => 'array',
'items' => $type_schema,
];
break;
case 'relationship':
assert('not implemented');
break;
}
return CacheableJsonResponse::create($schema)
->addCacheableDependency($cacheability);
}
public function getResourceObjectSchema(Request $request, $resource_type) {
$resource_type = $this->resourceTypeRepository
->getByTypeName($resource_type);
$schema = [
'$schema' => static::JSON_SCHEMA_DRAFT,
'$id' => $request
->getUri(),
'title' => $this
->getSchemaTitle($resource_type, 'item'),
'allOf' => [
[
'type' => 'object',
'properties' => [
'type' => [
'$ref' => '#definitions/type',
],
],
],
[
'$ref' => static::JSONAPI_BASE_SCHEMA_URI . '#/definitions/resource',
],
],
'definitions' => [
'type' => [
'const' => $resource_type
->getTypeName(),
],
],
];
$cacheability = new CacheableMetadata();
$schema = $this
->addFieldsSchema($schema, $resource_type);
$schema = $this
->addRelationshipsSchemaLinks($schema, $resource_type, $cacheability);
return CacheableJsonResponse::create($schema)
->addCacheableDependency($cacheability);
}
protected function addFieldsSchema(array $schema, ResourceType $resource_type) {
// Filter out disabled fields.
$resource_fields = array_filter($resource_type
->getFields(), function (ResourceTypeField $field) {
return $field
->isFieldEnabled();
});
if (empty($resource_fields)) {
return $schema;
}
$schema['allOf'][0]['properties']['attributes'] = [
'$ref' => '#/definitions/attributes',
];
$normalizer = $this->normalizer;
$entity_type = $this->entityTypeManager
->getDefinition($resource_type
->getEntityTypeId());
$bundle = $resource_type
->getBundle();
$fields = array_reduce($resource_fields, function ($carry, ResourceTypeField $field) use ($normalizer, $entity_type, $bundle) {
$field_schema = $normalizer
->normalize($this->staticDataDefinitionExtractor
->extractField($entity_type, $bundle, $field
->getInternalName()), 'schema_json', [
'name' => $field
->getPublicName(),
]);
$fields_member = $field instanceof ResourceTypeAttribute ? 'attributes' : 'relationships';
return NestedArray::mergeDeep($carry, [
'type' => 'object',
'properties' => [
$fields_member => $field_schema,
],
]);
}, []);
$field_definitions = NestedArray::getValue($fields, [
'properties',
]) ?: [];
if (!empty($field_definitions['attributes'])) {
$field_definitions['attributes']['additionalProperties'] = FALSE;
}
if (!empty($field_definitions['relationships'])) {
$field_definitions['relationships']['additionalProperties'] = FALSE;
}
$schema['definitions'] = NestedArray::mergeDeep($schema['definitions'], $field_definitions);
return $schema;
}
protected static function addRelationshipsSchemaLinks(array $schema, ResourceType $resource_type, CacheableMetadata $cacheability) {
$resource_relationships = array_filter($resource_type
->getFields(), function (ResourceTypeField $field) {
return $field
->isFieldEnabled() && $field instanceof ResourceTypeRelationship;
});
if (empty($resource_relationships)) {
return $schema;
}
$schema['allOf'][0]['properties']['relationships'] = [
'$ref' => '#/definitions/relationships',
];
$relationships = array_reduce($resource_relationships, function ($relationships, ResourceTypeRelationship $relationship) use ($resource_type, $cacheability) {
if ($resource_type
->isInternal() || !Routes::hasNonInternalTargetResourceTypes($relationship
->getRelatableResourceTypes())) {
return $relationships;
}
$field_name = $relationship
->getPublicName();
$resource_type_name = $resource_type
->getTypeName();
$related_route_name = "jsonapi_schema.{$resource_type_name}.{$field_name}.related";
$related_schema_uri = Url::fromRoute($related_route_name)
->setAbsolute()
->toString(TRUE);
$cacheability
->addCacheableDependency($related_schema_uri);
return NestedArray::mergeDeep($relationships, [
$field_name => [
'links' => [
[
'href' => '{instanceHref}',
'rel' => 'related',
'targetMediaType' => 'application/vnd.api+json',
'targetSchema' => $related_schema_uri
->getGeneratedUrl(),
'templatePointers' => [
'instanceHref' => '/links/related/href',
],
'templateRequired' => [
'instanceHref',
],
],
],
],
]);
}, []);
$schema['definitions']['relationships'] = NestedArray::mergeDeep(empty($schema['definitions']['relationships']) ? [] : $schema['definitions']['relationships'], [
'properties' => $relationships,
]);
return $schema;
}
/**
* Gets a schema title.
*
* @param \Drupal\jsonapi\ResourceType\ResourceType $resource_type
* A JSON:API resource type for which to generate a title.
* @param $schema_type
* The type of schema. Either 'collection' or 'item'.
*
* @return \Drupal\Core\StringTranslation\TranslatableMarkup
* The schema title.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/
protected function getSchemaTitle(ResourceType $resource_type, $schema_type) {
$entity_type = $this->entityTypeManager
->getDefinition($resource_type
->getEntityTypeId());
$entity_type_label = $schema_type === 'collection' ? $entity_type
->getPluralLabel() : $entity_type
->getSingularLabel();
if ($bundle_type = $entity_type
->getBundleEntityType()) {
$bundle = $this->entityTypeManager
->getStorage($bundle_type)
->load($resource_type
->getBundle());
return $this
->t(rtrim('@bundle_label @entity_type_label'), [
'@bundle_label' => Unicode::ucfirst($bundle
->label()),
'@entity_type_label' => $entity_type_label,
]);
}
else {
return $this
->t(rtrim('@entity_type_label'), [
'@entity_type_label' => Unicode::ucfirst($entity_type_label),
]);
}
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
ControllerBase:: |
protected | property | The configuration factory. | |
ControllerBase:: |
protected | property | The current user service. | 1 |
ControllerBase:: |
protected | property | The entity form builder. | |
ControllerBase:: |
protected | property | The entity manager. | |
ControllerBase:: |
protected | property | The form builder. | 2 |
ControllerBase:: |
protected | property | The key-value storage. | 1 |
ControllerBase:: |
protected | property | The language manager. | 1 |
ControllerBase:: |
protected | property | The module handler. | 2 |
ControllerBase:: |
protected | property | The state service. | |
ControllerBase:: |
protected | function | Returns the requested cache bin. | |
ControllerBase:: |
protected | function | Retrieves a configuration object. | |
ControllerBase:: |
private | function | Returns the service container. | |
ControllerBase:: |
protected | function | Returns the current user. | 1 |
ControllerBase:: |
protected | function | Retrieves the entity form builder. | |
ControllerBase:: |
protected | function | Retrieves the entity manager service. | |
ControllerBase:: |
protected | function | Retrieves the entity type manager. | |
ControllerBase:: |
protected | function | Returns the form builder service. | 2 |
ControllerBase:: |
protected | function | Returns a key/value storage collection. | 1 |
ControllerBase:: |
protected | function | Returns the language manager service. | 1 |
ControllerBase:: |
protected | function | Returns the module handler. | 2 |
ControllerBase:: |
protected | function |
Returns a redirect response object for the specified route. Overrides UrlGeneratorTrait:: |
|
ControllerBase:: |
protected | function | Returns the state storage service. | |
JsonApiSchemaController:: |
protected | property |
The entity type manager. Overrides ControllerBase:: |
|
JsonApiSchemaController:: |
protected | property | The serialization service. | |
JsonApiSchemaController:: |
protected | property | The JSON:API resource type repository. | |
JsonApiSchemaController:: |
protected | property | The static data definition extractor. | |
JsonApiSchemaController:: |
protected | function | ||
JsonApiSchemaController:: |
protected static | function | ||
JsonApiSchemaController:: |
public static | function |
Instantiates a new instance of this class. Overrides ControllerBase:: |
|
JsonApiSchemaController:: |
public | function | ||
JsonApiSchemaController:: |
public | function | ||
JsonApiSchemaController:: |
public | function | ||
JsonApiSchemaController:: |
protected | function | Gets a schema title. | |
JsonApiSchemaController:: |
constant | |||
JsonApiSchemaController:: |
constant | |||
JsonApiSchemaController:: |
public | function | JsonApiSchemaController constructor. | |
LinkGeneratorTrait:: |
protected | property | The link generator. | 1 |
LinkGeneratorTrait:: |
protected | function | Returns the link generator. | |
LinkGeneratorTrait:: |
protected | function | Renders a link to a route given a route name and its parameters. | |
LinkGeneratorTrait:: |
public | function | Sets the link generator service. | |
LoggerChannelTrait:: |
protected | property | The logger channel factory service. | |
LoggerChannelTrait:: |
protected | function | Gets the logger for a specific channel. | |
LoggerChannelTrait:: |
public | function | Injects the logger channel factory. | |
MessengerTrait:: |
protected | property | The messenger. | 29 |
MessengerTrait:: |
public | function | Gets the messenger. | 29 |
MessengerTrait:: |
public | function | Sets the messenger. | |
RedirectDestinationTrait:: |
protected | property | The redirect destination service. | 1 |
RedirectDestinationTrait:: |
protected | function | Prepares a 'destination' URL query parameter for use with \Drupal\Core\Url. | |
RedirectDestinationTrait:: |
protected | function | Returns the redirect destination service. | |
RedirectDestinationTrait:: |
public | function | Sets the redirect destination service. | |
StringTranslationTrait:: |
protected | property | The string translation service. | 1 |
StringTranslationTrait:: |
protected | function | Formats a string containing a count of items. | |
StringTranslationTrait:: |
protected | function | Returns the number of plurals supported by a given language. | |
StringTranslationTrait:: |
protected | function | Gets the string translation service. | |
StringTranslationTrait:: |
public | function | Sets the string translation service to use. | 2 |
StringTranslationTrait:: |
protected | function | Translates a string to the current language or to a given language. | |
UrlGeneratorTrait:: |
protected | property | The url generator. | |
UrlGeneratorTrait:: |
protected | function | Returns the URL generator service. | |
UrlGeneratorTrait:: |
public | function | Sets the URL generator service. | |
UrlGeneratorTrait:: |
protected | function | Generates a URL or path for a specific route based on the given parameters. |