| Current Path : /home/rtorresani/www/vendor/magento/module-webapi/Model/Rest/Swagger/ |
| Current File : //home/rtorresani/www/vendor/magento/module-webapi/Model/Rest/Swagger/Generator.php |
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Webapi\Model\Rest\Swagger;
use Magento\Framework\Api\SimpleDataObjectConverter;
use Magento\Framework\App\ProductMetadataInterface;
use Magento\Framework\Reflection\TypeProcessor;
use Magento\Framework\Webapi\Authorization;
use Magento\Framework\Webapi\Exception as WebapiException;
use Magento\Webapi\Controller\Rest;
use Magento\Webapi\Model\AbstractSchemaGenerator;
use Magento\Webapi\Model\Config\Converter;
use Magento\Webapi\Model\Rest\Swagger;
use Magento\Webapi\Model\Rest\SwaggerFactory;
use Magento\Webapi\Model\ServiceMetadata;
/**
* REST Swagger schema generator.
*
* Generate REST API description in a format of JSON document,
* compliant with {@link https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md Swagger specification}
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
* @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
*/
class Generator extends AbstractSchemaGenerator
{
/**
* Error response schema
*/
private const ERROR_SCHEMA = '#/definitions/error-response';
private const UNAUTHORIZED_DESCRIPTION = '401 Unauthorized';
protected const ARRAY_SIGNIFIER = '[0]';
/**
* Wrapper node for XML requests
*/
private const XML_SCHEMA_PARAMWRAPPER = 'request';
/**
* Swagger factory instance.
*
* @var SwaggerFactory
*/
protected SwaggerFactory $swaggerFactory;
/**
* Magento product metadata
*
* @var ProductMetadataInterface
*/
protected ProductMetadataInterface $productMetadata;
/**
* A map of Tags
*
* example:
* [
* class1Name => tag information,
* class2Name => tag information,
* ...
* ]
*
* @var array
*/
protected array $tags = [];
/**
* A map of definition
*
* example:
* [
* definitionName1 => definition,
* definitionName2 => definition,
* ...
* ]
* Note: definitionName is converted from class name
* @var array
*/
protected array $definitions = [];
/**
* List of simple parameter types not to be processed by the definitions generator
* Contains mapping to the internal swagger simple types
*
* @var string[]
*/
protected array $simpleTypeList = [
'bool' => 'boolean',
'boolean' => 'boolean',
'int' => 'integer',
'integer' => 'integer',
'double' => 'number',
'float' => 'number',
'number' => 'number',
'string' => 'string',
TypeProcessor::ANY_TYPE => 'string',
TypeProcessor::NORMALIZED_ANY_TYPE => 'string',
];
/**
* Initialize dependencies.
*
* @param \Magento\Webapi\Model\Cache\Type\Webapi $cache
* @param \Magento\Framework\Reflection\TypeProcessor $typeProcessor
* @param \Magento\Framework\Webapi\CustomAttribute\ServiceTypeListInterface $serviceTypeList
* @param \Magento\Webapi\Model\ServiceMetadata $serviceMetadata
* @param Authorization $authorization
* @param SwaggerFactory $swaggerFactory
* @param \Magento\Framework\App\ProductMetadataInterface $productMetadata
*/
public function __construct(
\Magento\Webapi\Model\Cache\Type\Webapi $cache,
\Magento\Framework\Reflection\TypeProcessor $typeProcessor,
\Magento\Framework\Webapi\CustomAttribute\ServiceTypeListInterface $serviceTypeList,
\Magento\Webapi\Model\ServiceMetadata $serviceMetadata,
Authorization $authorization,
SwaggerFactory $swaggerFactory,
ProductMetadataInterface $productMetadata
) {
$this->swaggerFactory = $swaggerFactory;
$this->productMetadata = $productMetadata;
parent::__construct(
$cache,
$typeProcessor,
$serviceTypeList,
$serviceMetadata,
$authorization
);
}
/**
* @inheritdoc
*/
protected function generateSchema($requestedServiceMetadata, $requestScheme, $requestHost, $endpointUrl)
{
/** @var Swagger $swagger */
$swagger = $this->swaggerFactory->create();
$swagger->setInfo($this->getGeneralInfo());
$this->addCustomAttributeTypes();
$swagger->setHost($requestHost);
$swagger->setBasePath(strstr($endpointUrl, Rest::SCHEMA_PATH, true));
$swagger->setSchemes([$requestScheme]);
foreach ($requestedServiceMetadata as $serviceName => $serviceData) {
if (!isset($this->tags[$serviceName])) {
$this->tags[$serviceName] = $this->generateTagInfo($serviceName, $serviceData);
$swagger->addTag($this->tags[$serviceName]);
}
foreach ($serviceData[Converter::KEY_ROUTES] as $uri => $httpMethods) {
$uri = $this->convertPathParams($uri);
foreach ($httpMethods as $httpOperation => $httpMethodData) {
$httpOperation = strtolower($httpOperation);
$phpMethodData = $serviceData[Converter::KEY_METHODS][$httpMethodData[Converter::KEY_METHOD]];
$httpMethodData[Converter::KEY_METHOD] = $phpMethodData;
$httpMethodData['uri'] = $uri;
$httpMethodData['httpOperation'] = $httpOperation;
$swagger->addPath(
$this->convertPathParams($uri),
$httpOperation,
$this->generatePathInfo($httpOperation, $httpMethodData, $serviceName, $uri)
);
}
}
}
$swagger->setDefinitions($this->getDefinitions());
return $swagger->toSchema();
}
/**
* Get the 'Info' section data
*
* @return string[]
*/
protected function getGeneralInfo()
{
$versionParts = explode('.', $this->productMetadata->getVersion());
if (!isset($versionParts[0]) || !isset($versionParts[1])) {
return []; // Major and minor version are not set - return empty response
}
$majorMinorVersion = $versionParts[0] . '.' . $versionParts[1];
return [
'version' => $majorMinorVersion,
'title' => $this->productMetadata->getName() . ' ' . $this->productMetadata->getEdition(),
];
}
/**
* List out consumes data type
*
* @return array
*/
private function getConsumableDatatypes()
{
return [
'application/json',
'application/xml',
];
}
/**
* List out produces data type
*
* @return array
*/
private function getProducibleDatatypes()
{
return [
'application/json',
'application/xml',
];
}
/**
* Generate path info based on method data
*
* @param string $methodName
* @param array $httpMethodData
* @param string $tagName
* @param string $uri
* @return array
*/
protected function generatePathInfo(string $methodName, array $httpMethodData, string $tagName, string $uri): array
{
$methodData = $httpMethodData[Converter::KEY_METHOD];
$uri = ucwords(str_replace(['/{', '}/', '{', '}'], '/', $uri), "/");
$operationId = ucfirst($methodName) . str_replace(['/', '-'], '', $uri);
$pathInfo = [
'tags' => [$tagName],
'description' => $methodData['documentation'],
'operationId' => $operationId,
'consumes' => $this->getConsumableDatatypes(),
'produces' => $this->getProducibleDatatypes(),
];
$parameters = $this->generateMethodParameters($httpMethodData, $operationId);
if ($parameters) {
$pathInfo['parameters'] = $parameters;
}
$pathInfo['responses'] = $this->generateMethodResponses($methodData);
return $pathInfo;
}
/**
* Generate response based on method data
*
* @param array $methodData
* @return array
*/
protected function generateMethodResponses($methodData)
{
$responses = [];
if (isset($methodData['interface']['out']['parameters'])
&& is_array($methodData['interface']['out']['parameters'])
) {
$parameters = $methodData['interface']['out']['parameters'];
$responses = $this->generateMethodSuccessResponse($parameters, $responses);
}
/** Handle authorization exceptions that may not be documented */
if (isset($methodData['resources'])) {
foreach ($methodData['resources'] as $resourceName) {
if ($resourceName !== 'anonymous') {
$responses[WebapiException::HTTP_UNAUTHORIZED]['description'] = self::UNAUTHORIZED_DESCRIPTION;
$responses[WebapiException::HTTP_UNAUTHORIZED]['schema']['$ref'] = self::ERROR_SCHEMA;
break;
}
}
}
if (isset($methodData['interface']['out']['throws'])
&& is_array($methodData['interface']['out']['throws'])
) {
foreach ($methodData['interface']['out']['throws'] as $exceptionClass) {
$responses = $this->generateMethodExceptionErrorResponses($exceptionClass, $responses);
}
}
$responses['default']['description'] = 'Unexpected error';
$responses['default']['schema']['$ref'] = self::ERROR_SCHEMA;
return $responses;
}
/**
* Generate parameters based on method data
*
* @param array $httpMethodData
* @param string $operationId
* @return array
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
*/
private function generateMethodParameters($httpMethodData, $operationId)
{
$bodySchema = [];
$parameters = [];
$phpMethodData = $httpMethodData[Converter::KEY_METHOD];
/** Return nothing if necessary fields are not set */
if (!isset($phpMethodData['interface']['in']['parameters'])
|| !isset($httpMethodData['uri'])
|| !isset($httpMethodData['httpOperation'])
) {
return [];
}
foreach ($phpMethodData['interface']['in']['parameters'] as $parameterName => $parameterInfo) {
/** Omit forced parameters */
if (isset($httpMethodData['parameters'][$parameterName]['force'])
&& $httpMethodData['parameters'][$parameterName]['force']
) {
continue;
}
if (!isset($parameterInfo['type'])) {
return [];
}
$description = $parameterInfo['documentation'] ?? null;
/** Get location of parameter */
if (strpos($httpMethodData['uri'], (string) ('{' . $parameterName . '}')) !== false) {
$parameters[] = $this->generateMethodPathParameter($parameterName, $parameterInfo, $description);
} elseif (strtoupper($httpMethodData['httpOperation']) === 'GET') {
$parameters = $this->generateMethodQueryParameters(
$parameterName,
$parameterInfo,
$description,
$parameters
);
} else {
$bodySchema = $this->generateBodySchema(
$parameterName,
$parameterInfo,
$description,
$bodySchema
);
}
}
/**
* Add all the path params that don't correspond directly the PHP parameters
*/
preg_match_all('#\\{([^\\{\\}]*)\\}#', $httpMethodData['uri'], $allPathParams);
$remainingPathParams = array_diff(
$allPathParams[1],
array_keys($phpMethodData['interface']['in']['parameters'])
);
foreach ($remainingPathParams as $pathParam) {
$parameters[] = [
'name' => $pathParam,
'in' => 'path',
'type' => 'string',
'required' => true
];
}
if ($bodySchema) {
$bodyParam = [];
$bodyParam['name'] = $operationId . 'Body';
$bodyParam['in'] = 'body';
$bodyParam['schema'] = $bodySchema;
$parameters[] = $bodyParam;
}
return $parameters;
}
/**
* Creates an array for the given query parameter
*
* @param string $name
* @param string $type
* @param string $description
* @param bool|null $required
* @return array
*/
private function createQueryParam($name, $type, $description, $required = null)
{
$param = [
'name' => $name,
'in' => 'query',
];
$param = array_merge($param, $this->getObjectSchema($type, $description));
if (isset($required)) {
$param['required'] = $required;
}
return $param;
}
/**
* Generate Tag Info for given service
*
* @param string $serviceName
* @param array $serviceData
* @return string[]
*/
protected function generateTagInfo($serviceName, $serviceData)
{
$tagInfo = [];
$tagInfo['name'] = $serviceName;
if (!empty($serviceData) && is_array($serviceData)) {
$tagInfo['description'] = $serviceData[Converter::KEY_DESCRIPTION];
}
return $tagInfo;
}
/**
* Generate definition for given type
*
* @param string $typeName
* @param string $description
* @return array
*/
protected function getObjectSchema($typeName, $description = '')
{
$simpleType = $this->getSimpleType($typeName);
if ($simpleType == false) {
$result = ['type' => 'array'];
if (!empty($description)) {
$result['description'] = $description;
}
$trimedTypeName = $typeName !== null ? rtrim($typeName, '[]') : '';
if ($simpleType = $this->getSimpleType($trimedTypeName)) {
$result['items'] = ['type' => $simpleType];
} else {
if ($typeName && strpos($typeName, '[]') !== false) {
$result['items'] = ['$ref' => $this->getDefinitionReference($trimedTypeName)];
} else {
$result = ['$ref' => $this->getDefinitionReference($trimedTypeName)];
}
if (!$this->isDefinitionExists($trimedTypeName)) {
$definitionKey = $this->toLowerCaseDashSeparated($trimedTypeName);
$this->definitions[$definitionKey] = [];
$this->definitions[$definitionKey] = $this->generateDefinition($trimedTypeName);
}
}
} else {
$result = ['type' => $simpleType];
if (!empty($description)) {
$result['description'] = $description;
}
}
return $result;
}
/**
* Generate definition for given type
*
* @param string $typeName
* @return array
*/
protected function generateDefinition($typeName)
{
$properties = [];
$requiredProperties = [];
$typeData = $this->typeProcessor->getTypeData($typeName);
if (isset($typeData['parameters'])) {
foreach ($typeData['parameters'] as $parameterName => $parameterData) {
$properties[$parameterName] = $this->getObjectSchema(
$parameterData['type'],
$parameterData['documentation']
);
if ($parameterData['required']) {
$requiredProperties[] = $parameterName;
}
}
}
$definition = ['type' => 'object'];
if (isset($typeData['documentation'])) {
$definition['description'] = $typeData['documentation'];
}
if (!empty($properties)) {
$definition['properties'] = $properties;
}
if (!empty($requiredProperties)) {
$definition['required'] = $requiredProperties;
}
return $definition;
}
/**
* Get definitions
*
* @return array
* Todo: create interface for error response
*/
protected function getDefinitions()
{
return array_merge(
[
'error-response' => [
'type' => 'object',
'properties' => [
'message' => [
'type' => 'string',
'description' => 'Error message',
],
'errors' => [
'$ref' => '#/definitions/error-errors',
],
'code' => [
'type' => 'integer',
'description' => 'Error code',
],
'parameters' => [
'$ref' => '#/definitions/error-parameters',
],
'trace' => [
'type' => 'string',
'description' => 'Stack trace',
],
],
'required' => ['message'],
],
'error-errors' => [
'type' => 'array',
'description' => 'Errors list',
'items' => [
'$ref' => '#/definitions/error-errors-item',
],
],
'error-errors-item' => [
'type' => 'object',
'description' => 'Error details',
'properties' => [
'message' => [
'type' => 'string',
'description' => 'Error message',
],
'parameters' => [
'$ref' => '#/definitions/error-parameters',
],
],
],
'error-parameters' => [
'type' => 'array',
'description' => 'Error parameters list',
'items' => [
'$ref' => '#/definitions/error-parameters-item',
],
],
'error-parameters-item' => [
'type' => 'object',
'description' => 'Error parameters item',
'properties' => [
'resources' => [
'type' => 'string',
'description' => 'ACL resource',
],
'fieldName' => [
'type' => 'string',
'description' => 'Missing or invalid field name'
],
'fieldValue' => [
'type' => 'string',
'description' => 'Incorrect field value'
],
],
],
],
$this->snakeCaseDefinitions($this->definitions)
);
}
/**
* Converts definitions' properties array to snake_case.
*
* @param array $definitions
* @return array
*/
private function snakeCaseDefinitions($definitions)
{
foreach ($definitions as $name => $vals) {
if (!empty($vals['properties'])) {
$definitions[$name]['properties'] = $this->convertArrayToSnakeCase($vals['properties']);
}
if (!empty($vals['required'])) {
$snakeCaseRequired = [];
foreach ($vals['required'] as $requiredProperty) {
$snakeCaseRequired[] = SimpleDataObjectConverter::camelCaseToSnakeCase($requiredProperty);
}
$definitions[$name]['required'] = $snakeCaseRequired;
}
}
return $definitions;
}
/**
* Converts associative array's key names from camelCase to snake_case, recursively.
*
* @param array $properties
* @return array
*/
private function convertArrayToSnakeCase($properties)
{
foreach ($properties as $name => $value) {
$snakeCaseName = SimpleDataObjectConverter::camelCaseToSnakeCase($name);
if (is_array($value)) {
$value = $this->convertArrayToSnakeCase($value);
}
unset($properties[$name]);
$properties[$snakeCaseName] = $value;
}
return $properties;
}
/**
* Get definition reference
*
* @param string $typeName
* @return string
*/
protected function getDefinitionReference($typeName)
{
return '#/definitions/' . $this->toLowerCaseDashSeparated($typeName);
}
/**
* Get the CamelCased type name in 'hyphen-separated-lowercase-words' format
*
* E.g. test-module5-v1-entity-all-soap-and-rest
*
* @param string $typeName
* @return string
*/
protected function toLowerCaseDashSeparated($typeName)
{
return strtolower(preg_replace('/(.)([A-Z])/', "$1-$2", $typeName));
}
/**
* Check if definition exists
*
* @param string $typeName
* @return bool
*/
protected function isDefinitionExists($typeName)
{
return isset($this->definitions[$this->toLowerCaseDashSeparated($typeName)]);
}
/**
* Create and add custom attribute types
*
* @return void
*/
protected function addCustomAttributeTypes()
{
foreach ($this->serviceTypeList->getDataTypes() as $customAttributeClass) {
$this->typeProcessor->register($customAttributeClass);
}
}
/**
* Get service metadata
*
* @param string $serviceName
* @return array
*/
protected function getServiceMetadata($serviceName)
{
return $this->serviceMetadata->getRouteMetadata($serviceName);
}
/**
* Get the simple type supported by Swagger, or false if type is not simple
*
* @param string $type
* @return bool|string
*/
protected function getSimpleType($type)
{
if (array_key_exists($type, $this->simpleTypeList)) {
return $this->simpleTypeList[$type];
} else {
return false;
}
}
/**
* Return the parameter names to describe a given parameter, mapped to the respective type
*
* Query parameters may be complex types, and multiple parameters will be listed in the schema to outline
* the structure of the type.
*
* @param string $name
* @param string $type
* @param string $description
* @param string $prefix
* @return string[]
*/
protected function getQueryParamNames($name, $type, $description, $prefix = '')
{
if ($this->typeProcessor->isTypeSimple($type)) {
// Primitive type or array of primitive types
return [
$this->handlePrimitive($name, $prefix) => [
'type' => ($type && substr($type, -2) === '[]') ? $type : $this->getSimpleType($type),
'description' => $description
]
];
}
if ($this->typeProcessor->isArrayType($type)) {
// Array of complex type
$arrayType = $type !== null ? substr($type, 0, -2) : '';
return $this->handleComplex($name, $arrayType, $prefix, true);
} else {
// Complex type
return $this->handleComplex($name, $type, $prefix, false);
}
}
/**
* Recursively generate the query param names for a complex type
*
* @param string $name
* @param string $type
* @param string $prefix
* @param bool $isArray
* @return string[]
*/
private function handleComplex($name, $type, $prefix, $isArray)
{
$typeData = $this->typeProcessor->getTypeData($type);
$parameters = $typeData['parameters'] ?? [];
$queryNames = [];
foreach ($parameters as $subParameterName => $subParameterInfo) {
$subParameterType = $subParameterInfo['type'];
$subParameterDescription = $subParameterInfo['documentation'] ?? null;
$subPrefix = $prefix
? $prefix . '[' . $name . ']'
: $name;
if ($isArray) {
$subPrefix .= self::ARRAY_SIGNIFIER;
}
$queryNames[] = $this->getQueryParamNames(
$subParameterName,
$subParameterType,
$subParameterDescription,
$subPrefix
);
}
return array_merge([], ...$queryNames);
}
/**
* Generate the query param name for a primitive type
*
* @param string $name
* @param string $prefix
* @return string
*/
private function handlePrimitive($name, $prefix)
{
return $prefix
? $prefix . '[' . $name . ']'
: $name;
}
/**
* Convert path parameters from :param to {param}
*
* @param string $uri
* @return string
*/
private function convertPathParams($uri)
{
$parts = explode('/', $uri);
$count = count($parts);
for ($i=0; $i < $count; $i++) {
if (strpos($parts[$i] ?? '', ':') === 0) {
$parts[$i] = '{' . substr($parts[$i] ?? '', 1) . '}';
}
}
return implode('/', $parts);
}
/**
* Generate method path parameter
*
* @param string $parameterName
* @param array $parameterInfo
* @param string $description
* @return string[]
*/
private function generateMethodPathParameter($parameterName, $parameterInfo, $description)
{
$param = [
'name' => $parameterName,
'in' => 'path',
'type' => $this->getSimpleType($parameterInfo['type']),
'required' => true
];
if ($description) {
$param['description'] = $description;
return $param;
}
return $param;
}
/**
* Generate method query parameters
*
* @param string $parameterName
* @param array $parameterInfo
* @param string $description
* @param array $parameters
* @return array
*/
private function generateMethodQueryParameters($parameterName, $parameterInfo, $description, $parameters)
{
$queryParams = $this->getQueryParamNames($parameterName, $parameterInfo['type'], $description);
if (count($queryParams) === 1) {
// handle simple query parameter (includes the 'required' field)
$parameters[] = $this->createQueryParam(
$parameterName,
$parameterInfo['type'],
$description,
$parameterInfo['required']
);
} else {
/**
* Complex query parameters are represented by a set of names which describes the object's fields.
*
* Omits the 'required' field.
*/
foreach ($queryParams as $name => $queryParamInfo) {
$parameters[] = $this->createQueryParam(
$name,
$queryParamInfo['type'],
$queryParamInfo['description']
);
}
}
return $parameters;
}
/**
* Generate body schema
*
* @param string $parameterName
* @param array $parameterInfo
* @param string $description
* @param array $bodySchema
* @return array
*/
private function generateBodySchema($parameterName, $parameterInfo, $description, $bodySchema)
{
$required = isset($parameterInfo['required']) ? $parameterInfo['required'] : null;
/*
* There can only be one body parameter, multiple PHP parameters are represented as different
* properties of the body.
*/
if ($required) {
$bodySchema['required'][] = $parameterName;
}
$bodySchema['properties'][$parameterName] = $this->getObjectSchema(
$parameterInfo['type'],
$description
);
$bodySchema['type'] = 'object';
/*
* Make sure we have a proper XML wrapper for request parameters for the XML format.
*/
if (!isset($bodySchema['xml']) || !is_array($bodySchema['xml'])) {
$bodySchema['xml'] = [];
}
if (!isset($bodySchema['xml']['name']) || empty($bodySchema['xml']['name'])) {
$bodySchema['xml']['name'] = self::XML_SCHEMA_PARAMWRAPPER;
}
return $bodySchema;
}
/**
* Generate method 200 response
*
* @param array $parameters
* @param array $responses
* @return array
*/
private function generateMethodSuccessResponse($parameters, $responses)
{
if (isset($parameters['result']) && is_array($parameters['result'])) {
$description = '';
if (isset($parameters['result']['documentation'])) {
$description = $parameters['result']['documentation'];
}
$schema = [];
if (isset($parameters['result']['type'])) {
$schema = $this->getObjectSchema($parameters['result']['type'], $description);
}
// Some methods may have a non-standard HTTP success code.
$specificResponseData = $parameters['result']['response_codes']['success'] ?? [];
// Default HTTP success code to 200 if nothing has been supplied.
$responseCode = $specificResponseData['code'] ?? '200';
// Default HTTP response status to 200 Success if nothing has been supplied.
$responseDescription = $specificResponseData['description'] ?? '200 Success.';
$responses[$responseCode]['description'] = $responseDescription;
if (!empty($schema)) {
$responses[$responseCode]['schema'] = $schema;
}
}
return $responses;
}
/**
* Generate method exception error responses
*
* @param array $exceptionClass
* @param array $responses
* @return array
*/
private function generateMethodExceptionErrorResponses($exceptionClass, $responses)
{
$httpCode = '500';
$description = 'Internal Server error';
if (is_subclass_of($exceptionClass, \Magento\Framework\Exception\LocalizedException::class)) {
// Map HTTP codes for LocalizedExceptions according to exception type
if (is_subclass_of($exceptionClass, \Magento\Framework\Exception\NoSuchEntityException::class)) {
$httpCode = WebapiException::HTTP_NOT_FOUND;
$description = '404 Not Found';
} elseif (is_subclass_of($exceptionClass, \Magento\Framework\Exception\AuthorizationException::class)
|| is_subclass_of($exceptionClass, \Magento\Framework\Exception\AuthenticationException::class)
) {
$httpCode = WebapiException::HTTP_UNAUTHORIZED;
$description = self::UNAUTHORIZED_DESCRIPTION;
} else {
// Input, Expired, InvalidState exceptions will fall to here
$httpCode = WebapiException::HTTP_BAD_REQUEST;
$description = '400 Bad Request';
}
}
$responses[$httpCode]['description'] = $description;
$responses[$httpCode]['schema']['$ref'] = self::ERROR_SCHEMA;
return $responses;
}
/**
* Retrieve a list of services visible to current user.
*
* @return string[]
*/
public function getListOfServices()
{
$listOfAllowedServices = [];
foreach ($this->serviceMetadata->getServicesConfig() as $serviceName => $service) {
foreach ($service[ServiceMetadata::KEY_SERVICE_METHODS] as $method) {
if ($this->authorization->isAllowed($method[ServiceMetadata::KEY_ACL_RESOURCES])) {
$listOfAllowedServices[] = $serviceName;
break;
}
}
}
return $listOfAllowedServices;
}
}