View source
<?php
namespace Drupal\openapi\Plugin\openapi;
use Drupal\Component\Plugin\PluginBase;
use Drupal\Core\Authentication\AuthenticationCollectorInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Config\Entity\ConfigEntityTypeInterface;
use Drupal\Core\Entity\ContentEntityTypeInterface;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Routing\RouteProviderInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\schemata\SchemaFactory;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
abstract class OpenApiGeneratorBase extends PluginBase implements OpenApiGeneratorInterface, ContainerFactoryPluginInterface {
use StringTranslationTrait;
static $DEFINITION_SEPARATOR = ':';
public $label;
protected $entityTypeManager;
protected $routingProvider;
protected $fieldManager;
protected $schemaFactory;
protected $serializer;
protected $request;
protected $configFactory;
protected $options;
protected $authenticationCollector;
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, RouteProviderInterface $routing_provider, EntityFieldManagerInterface $field_manager, SchemaFactory $schema_factory, SerializerInterface $serializer, RequestStack $request_stack, ConfigFactoryInterface $config_factory, AuthenticationCollectorInterface $authentication_collector) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->label = $this
->getPluginDefinition()["label"];
$this->entityTypeManager = $entity_type_manager;
$this->routingProvider = $routing_provider;
$this->fieldManager = $field_manager;
$this->schemaFactory = $schema_factory;
$this->serializer = $serializer;
$this->request = $request_stack
->getCurrentRequest();
$this->configFactory = $config_factory;
$this->authenticationCollector = $authentication_collector;
$this->options = [];
}
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static($configuration, $plugin_id, $plugin_definition, $container
->get('entity_type.manager'), $container
->get('router.route_provider'), $container
->get('entity_field.manager'), $container
->get('schemata.schema_factory'), $container
->get('serializer'), $container
->get('request_stack'), $container
->get('config.factory'), $container
->get('authentication_collector'));
}
public function setOptions($options) {
$this->options = $options;
}
public function getOptions() {
return $this->options;
}
public function getId() {
return $this
->getPluginId();
}
public function getLabel() {
if ($this->label === NULL) {
$this->label = $this
->get()["label"];
}
return $this->label;
}
public function getSpecification() {
$basePath = $this
->getBasePath();
$spec = [
'swagger' => "2.0",
'schemes' => [
$this->request
->getScheme(),
],
'info' => $this
->getInfo(),
'host' => $this->request
->getHttpHost(),
'basePath' => empty($basePath) ? '/' : $basePath,
'securityDefinitions' => $this
->getSecurityDefinitions(),
'security' => $this
->getSecurity(),
'tags' => $this
->getTags(),
'definitions' => $this
->getDefinitions(),
'consumes' => $this
->getConsumes(),
'produces' => $this
->getProduces(),
'paths' => $this
->getPaths(),
];
$required = [
'swagger',
'info',
'paths',
];
foreach ($spec as $key => $item) {
if (!in_array($key, $required) && is_array($item) && !count($item)) {
unset($spec[$key]);
}
}
return $spec;
}
protected function getInfo() {
$site_name = $this->configFactory
->get('system.site')
->get('name');
return [
'description' => $this
->getApiDescription(),
'title' => $site_name . ' - ' . $this
->getApiName(),
'version' => 'Versioning not supported',
];
}
public abstract function getApiName();
public function getBasePath() {
return $this->request
->getBasePath();
}
public function getSecurityDefinitions() {
$base_url = $this->request
->getSchemeAndHttpHost() . '/' . $this->request
->getBasePath();
$auth_providers = $this->authenticationCollector
->getSortedProviders();
$security_definitions = [];
foreach ($auth_providers as $provider => $info) {
$def = NULL;
switch ($provider) {
case 'basic_auth':
$def = [
'type' => 'basic',
];
break;
case 'oauth2':
$def = [
'type' => 'oauth2',
'description' => 'For more information see https://developers.getbase.com/docs/rest/articles/oauth2/requests',
'flows' => [
'password' => [
'tokenUrl' => $base_url . 'oauth/token',
'refreshUrl' => $base_url . 'oauth/token',
],
'authorizationCode' => [
'authorizationUrl' => $base_url . 'oauth/authorize',
'tokenUrl' => $base_url . 'oauth/token',
'refreshUrl' => $base_url . 'oauth/token',
],
'implicit' => [
'authorizationUrl' => $base_url . 'oauth/authorize',
'refreshUrl' => $base_url . 'oauth/token',
],
'clientCredentials' => [
'tokenUrl' => $base_url . 'oauth/token',
'refreshUrl' => $base_url . 'oauth/token',
],
],
];
break;
default:
continue 2;
}
if ($def !== NULL) {
$security_definitions[$provider] = $def;
}
}
$security_definitions['csrf_token'] = [
'type' => 'apiKey',
'name' => 'X-CSRF-Token',
'in' => 'header',
'x-tokenUrl' => $base_url . 'user/token',
];
return $security_definitions;
}
public function getSecurity() {
$security = [];
foreach (array_keys($this
->getSecurityDefinitions()) as $method) {
$security[$method] = [];
}
return $security;
}
public function getTags() {
return [];
}
public function getDefinitions() {
return [];
}
public function getPaths() {
return [];
}
public function getConsumes() {
return [];
}
public function getProduces() {
return [];
}
protected function getJsonSchema($described_format, $entity_type_id, $bundle_name = NULL) {
if ($entity_type_id !== $bundle_name) {
$schema = $this->schemaFactory
->create($entity_type_id, $bundle_name);
}
else {
$schema = $this->schemaFactory
->create($entity_type_id);
}
if ($schema) {
$json_schema = $this->serializer
->normalize($schema, "schema_json:{$described_format}");
unset($json_schema['$schema'], $json_schema['id']);
$json_schema = $this
->cleanSchema($json_schema);
if (!$bundle_name) {
$entity_type = $this->entityTypeManager
->getDefinition($entity_type_id);
if ($bundle_field = $entity_type
->getKey('bundle')) {
$json_schema['discriminator'] = $bundle_field;
}
}
}
else {
$json_schema = [
'type' => 'object',
'title' => $this
->t('@entity_type Schema', [
'@entity_type' => $entity_type_id,
]),
'description' => $this
->t('Describes the payload for @entity_type entities.', [
'@entity_type' => $entity_type_id,
]),
];
}
return $json_schema;
}
protected function cleanSchema(array $json_schema) {
foreach ($json_schema as &$value) {
if ($value === NULL) {
$value = '';
}
else {
if (is_array($value)) {
$this
->fixDefaultFalse($value);
$value = $this
->cleanSchema($value);
}
}
}
return $json_schema;
}
protected function fixDefaultFalse(array &$value) {
$type_is_array = isset($value['type']) && $value['type'] === 'array';
$has_properties = isset($value['items']['properties']) && is_array($value['items']['properties']);
$has_default = isset($value['default']) && is_array($value['default']);
if ($type_is_array && $has_properties && $has_default) {
foreach ($value['items']['properties'] as $property_key => $property) {
if ($property['type'] === 'boolean') {
foreach ($value['default'] as &$default_values) {
if (isset($default_values[$property_key]) && empty($default_values[$property_key])) {
$default_values[$property_key] = FALSE;
}
}
}
}
}
}
protected function getEntityResponses($entity_type_id, $method, $bundle_name = NULL) {
$method = strtolower($method);
$responses = [];
$schema_response = [];
if ($definition_ref = $this
->getDefinitionReference($entity_type_id, $bundle_name)) {
$schema_response = [
'schema' => [
'$ref' => $definition_ref,
],
];
}
switch ($method) {
case 'get':
$responses['200'] = [
'description' => 'successful operation',
] + $schema_response;
break;
case 'post':
unset($responses['200']);
$responses['201'] = [
'description' => 'Entity created',
] + $schema_response;
break;
case 'delete':
unset($responses['200']);
$responses['201'] = [
'description' => 'Entity deleted',
];
break;
}
return $responses;
}
protected function getDefinitionReference($entity_type_id, $bundle_name = NULL) {
$definition_key = $this
->getEntityDefinitionKey($entity_type_id, $bundle_name);
if ($this
->definitionExists($definition_key)) {
$definition_ref = '#/definitions/' . $definition_key;
return $definition_ref;
}
return '';
}
protected function getEntityDefinitionKey($entity_type_id, $bundle_name = NULL) {
$definition_key = $entity_type_id;
if ($bundle_name) {
$definition_key .= static::$DEFINITION_SEPARATOR . $bundle_name;
}
return $definition_key;
}
protected function definitionExists($definition_key) {
$definitions = $this
->getDefinitions();
return isset($definitions[$definition_key]);
}
protected function includeEntityTypeBundle($entity_type_id, $bundle_name = NULL) {
if (isset($this->options['exclude'])) {
if (array_intersect([
$entity_type_id,
$this
->getEntityDefinitionKey($entity_type_id, $bundle_name),
], $this->options['exclude'])) {
return FALSE;
}
}
if (isset($this->options['entity_mode'])) {
$entity_type = $this->entityTypeManager
->getDefinition($entity_type_id);
if ($this->options['entity_mode'] == 'content_entities') {
return $entity_type instanceof ContentEntityTypeInterface;
}
if ($this->options['entity_mode'] == 'config_entities') {
return $entity_type instanceof ConfigEntityTypeInterface;
}
}
if (isset($this->options['entity_type_id']) && $this->options['entity_type_id'] !== $entity_type_id) {
return FALSE;
}
if (isset($bundle_name) && isset($this->options['bundle_name']) && $this->options['bundle_name'] !== $bundle_name) {
return FALSE;
}
return TRUE;
}
protected abstract function getApiDescription();
}